関数名 | 適用する演算 |
---|---|
Sys.Date() | 現在の日付を返す(Date) |
Sys.Time() | 現在の日時を返す(POSIXct) |
Sys.timezone() | 現在のタイムゾーンを返す |
as.POSIXlt(x) | xをPOSIXltに変換する |
weekdays(x) | xの曜日を返す |
months(x) | xの月名を返す |
quarters(x) | xの四半期を返す |
ISOdatetime(y, m, d, h, m, s) | POSIXctオブジェクトを作成 |
seq(x, by, length.out) | xからbyの間隔でlength.outの長さのベクターを作成 |
cut.POSIXt(x, breaks) | xをbreaksで丸めた因子を作成 |
min(x) | xの最小値を返す |
max(x) | xの最大値を返す |
mean(x) | xの平均値を返す |
range(x) | xの範囲を返す |
difftime(x, y) | xとyの時間差を返す |
round(x, unit) | xをunitにまるめて返す |
Sys.sleep(sec) | 演算をsec秒停止する |
tic() | 時間計測を開始(tictocパッケージ) |
toc() | 時間計測を終了(tictocパッケージ) |
17 日時データの取り扱い
時間とともに変化する値を記録したデータである時系列データは、統計で取り扱う代表的なデータの一つです。時系列データの代表的な例として、為替や株価、温度や湿度、ネットワークへのアクセス数などが挙げられます。これらのデータを取り扱うためには、日時データを適切に取り扱う必要があります。
日時データは通常文字列として記録されるため、Rでデータを読み込んだ際には、文字列のデータを日時データとして取り扱えるように変換する必要があります。この変換に関する関数をRは多数取り揃えています。
17.1 日時データのクラス:Date・POSIXct・POSIXlt・POSIXt
Rでは、日時データのクラスとして、Date・POSIXct・POSIXlt・POSIXtの4種類が設定されています。これらのうち、Date型は日付のみを取り扱う型、POSIXct・POSIXlt・POSIXt型は日時(日付+時間)を取り扱う型です。これらの型は、それぞれ取り扱い方が少しずつ異なります。
Rには、表1に示す日時データ取り扱いのための関数が備わっています。以下にそれぞれの関数・データ型の取り扱いについて説明します。
POSIXtクラスはPOSIXctとPOSIXltの親クラスです。Rの日時に関する関数の多くはPOSIXtクラスを引数に取るよう設定されているため、POSIXctもPOSIXltもほぼ同じように取り扱うことができます。
17.2 現在の日時を取得する
Sys.Date
関数とSys.time
関数は、現在の日付・日時をそれぞれ取得するための関数です。Sys.Date
関数は現在の日付をDateクラスで、Sys.time
関数は現在の時刻をPOSIXctクラスで返します。同様の関数としてdate
関数もありますが、この関数の返り値は文字列です。
Sys.timezone
関数は、Rが演算に用いるタイムゾーンを返す関数です。日本で使用しているPCでは、通常Asia/Tokyo(GMT+9)をタイムゾーンとしています。
Sys.DateとSys.time関数
Sys.Date() # 現在の日付(Date)
## [1] "2025-03-29"
Sys.time() # 現在の日時(POSIXct)
## [1] "2025-03-29 08:11:38 +09"
date() # 現在の日時(文字列)
## [1] "Sat Mar 29 08:11:38 2025"
Sys.timezone() # システムのタイムゾーン
## [1] "Etc/GMT-9"
Sys.Date() |> class() # Sys.Dateの返り値はDate
## [1] "Date"
Sys.time() |> class() # Sys.timeの返り値はPOSIXct(POSIXt)
## [1] "POSIXct" "POSIXt"
date() |> class() # dateの返り値は文字列(character)
## [1] "character"
Dateクラスのデータ型は数値で、as.numeric
関数で数値に変換すると1970年1月1日からの日数を返します。
Dateクラス
Sys.Date() |> mode() # Dateクラスは数値型
## [1] "numeric"
Sys.Date() |> as.numeric() # 1970/1/1からの日数
## [1] 20176
同様に、POSIXctもデータ型は数値で、数値変換すると1970年1月1日0時0分0秒からの秒数を返します。
POSIXctクラス
Sys.time() |> mode() # POSIXctクラスは数値型
## [1] "numeric"
Sys.time() |> as.numeric() # 1970/1/1からの時間(秒)
## [1] 1743203499
17.3 POSIXctクラスとPOSIXltクラス
POSIXctクラスのオブジェクトは、as.POSIXlt
関数でPOSIXltクラスに変換することができます。また、as.POSIXct
関数を用いてPOSIXltクラスのオブジェクトをPOSIXctクラスに変換することもできます。
POSIXctクラスとPOSIXltクラスの違いは、POSIXctが数値なのに対し、POSIXltにはクラスだけでなく、名前(names
)とタイムゾーン(tzone
)がアトリビュートとして設定されているリストである点です。POSIXltは名前付きリストですので、設定されている名前(sec
、min
、hour
、mday
など)を用いて、秒、分、時、日などの日時の部分データを呼び出すことができます。
POSIXltクラス
Sys.time() |> as.POSIXct() # POSIXctに変換
## [1] "2025-03-29 08:11:38 +09"
Sys.time() |> as.POSIXlt() # POSIXltに変換
## [1] "2025-03-29 08:11:38 +09"
<- Sys.time() # tはPOSIXct
t $year # POSIXctには名前が無いため、エラー
t## Error in t$year: $ operator is invalid for atomic vectors
attributes(t) # class以外は設定されていない
## $class
## [1] "POSIXct" "POSIXt"
<- as.POSIXlt(t) # t1はPOSIXlt
t1 attributes(t1) # 名前とタイムゾーンが設定されている
## $names
## [1] "sec" "min" "hour" "mday" "mon" "year" "wday" "yday"
## [9] "isdst" "zone" "gmtoff"
##
## $class
## [1] "POSIXlt" "POSIXt"
##
## $tzone
## [1] "" "+09" " "
##
## $balanced
## [1] TRUE
as.numeric(t1) # POSIXltも数値に置き換えできる
## [1] 1743203499
mode(t1) # POSIXltはリスト
## [1] "list"
$mday # POSIXltは$で名前から呼び出し可能
t1## [1] 29
$hour
t1## [1] 8
$wday # 曜日は月曜日が1
t1## [1] 6
$zone # タイムゾーン
t1## [1] "+09"
POSIXltにはタイムゾーンがアトリビュートとして設定されており、POSIXctには設定されていませんが、いずれもas.POSIXlt
、as.POSIXct
関数のtz
引数を設定することで、タイムゾーンを変更することができます。
タイムゾーンの設定
as.POSIXct(Sys.time(), tz = "GMT") # POSIXct型のSys.time()をUTCに変換
## [1] "2025-03-28 23:11:38 GMT"
as.POSIXct(Sys.time(), tz = "EST") # アメリカ東時間に変換
## [1] "2025-03-28 18:11:38 EST"
as.POSIXlt(t1, tz = "GMT") # POSIXlt型をUTCに変換
## [1] "2025-03-29 08:11:38 +09"
as.POSIXlt(t1, tz = "EST") # アメリカ東時間に変換
## [1] "2025-03-29 08:11:38 +09"
POSIXct、POSIXltクラスのオブジェクトは、共にRの日時データに関する関数の引数として設定し、演算を行うことができます。
代表的な日時データに関する関数は、weekdays
関数やmonths
関数、quarters
関数などです。いずれも日時データのベクターを引数に取り、曜日・月・四半期などの値を返します。
日時データに関する関数
weekdays(t)
## [1] "土曜日"
weekdays(t, abbreviate = T) # 省略形
## [1] "土"
weekdays(as.POSIXlt(t, tz="EST")) # US時間に変更しても、日本語で出てくる
## [1] "金曜日"
<- c(as.POSIXct("2023-10-10 11:11:11"), as.POSIXct("2024-1-11 11:11:11"))
t2 weekdays(t2) # ベクターでも処理可能
## [1] "火曜日" "木曜日"
months(t2) # 月を返す関数
## [1] "10月" "1月"
quarters(t2) # 四半期を返す関数
## [1] "Q4" "Q1"
17.4 文字列を日時データに変換する
Excelやテキストファイルなどでは、日時データは文字列や数値で保存されています。Rでは文字列や数値をそのまま日時データとして取り扱うことはできないため、日時データに変換する必要があります。日時データへの変換にも、as.POSIXct
関数やas.POSIXlt
関数を用います。
文字列は、日本人が通常使うような日時の表現("2022/2/22 11:11:11"
や"2022-2-22 11:11:11"
など)であれば、その文字列のみを引数に取り、as.POSIXct
関数やas.POSIXlt
関数で日時クラスに変換できます。
ただし、単に日時の数値を並べた文字列や、年月日等の日本語が混じった文字列では、どのような日時データなのかRが読み解くことができないため、as.POSIXct
関数やas.POSIXlt
関数で直接日時データに変換することはできません。
このように、文字列を日時データに変換する場合には、変換のルールであるフォーマットを指定する必要があります。フォーマットとは、%(パーセント)に特定のアルファベットを付けて、年や月、分などを指定するものです。例えば、年であれば%Y
や%y
、月であれば%m
が対応するフォーマットとなります。フォーマットの一覧を以下の表2に示します。
記号 | 意味 |
---|---|
%a | 省略した曜日名(Mon, Tueなど) |
%A | 省略しない曜日名(Mondayなど) |
%b | 省略した月名(Jan,Febなど) |
%B | 省略しない月名(Januaryなど) |
%c | 日時(通常表示はこれ,%Y-%m-%d %H:%M:%Sと同じ) |
%C | 世紀 |
%d | 日(01-30日) |
%D | 日付(%Y-%m-%dと同じ) |
%e | 日(1-30日,ゼロがないもの) |
%F | %Y-%m-%dと同じ |
%g | week-based-yearの最後2桁(1-99) |
%G | week-based-year(01-99) |
%h | %bと同じ |
%H | 時間(00-23) |
%I | 時間(00-12) |
%j | 年基準の日数(001-366) |
%m | 月(01-12) |
%M | 分(00-59) |
%n | 新しい行(出力),スペース(入力) |
%p | AM・PMの表記 |
%r | %I:%M:%S %pと同じ |
%R | %H:%Mと同じ |
%S | 秒(00-61) |
%t | タブ切り(出力),スペース(入力) |
%T | %H:%M:%Sと同じ |
%u | 週の日数(1-7,1は月曜) |
%U | 日曜日を始めとするweek of the year(00-53) |
%V | ISO8601に従ったweek of the year(01-53) |
%w | 週の日数(0-6,0は日曜) |
%W | 月曜日を始めとするweek of the year(00-53) |
%x | %y/%m/%dと同じ |
%X | %H:%M:%Sと同じ |
%y | 世紀表現なしの年(00-99) |
%Y | 正規表現込みの年(2023など) |
%z | UTCからの時間差表現(-0800など) |
%Z | タイムゾーンの出力 |
フォーマットを利用することで、日本語の混じった文字列や、単に数値だけの文字列であっても、日時データに変換することができます。
フォーマットを用いた日時データへの変換
as.POSIXlt("2022-2-22 11:11:11")
## [1] "2022-02-22 11:11:11 +09"
as.POSIXlt("2022/2/22 11:11:11")
## [1] "2022-02-22 11:11:11 +09"
as.Date("2022/10/22")
## [1] "2022-10-22"
as.POSIXct("20221022 111111") # エラー
## Error in as.POSIXlt.character(x, tz, ...): character string is not in a standard unambiguous format
as.POSIXct("20221022 111111", format = "%Y%m%d %H%M%S") # フォーマットを設定
## [1] "2022-10-22 11:11:11 +09"
as.Date("20221022", format = "%Y%m%d")
## [1] "2022-10-22"
# 漢字が混じっていても、フォーマットを設定すると日時データに変換できる
as.POSIXct("2022年10月22日 11時11分11秒", format = "%Y年%m月%d日 %H時%M分%S秒")
## [1] "2022-10-22 11:11:11 +09"
17.5 数値を日時データに変換する
as.Date
やas.POSIXct
の引数に数値を指定すると、1970年1月1日からの日数・秒数に従い日時データに変換されてしまいます。したがって、数値を日時データに変換する場合には、まず文字列に変換しておく必要があります。
数値から日時データへの変換
as.Date(20221022, format = "%Y%m%d") # 数値はうまく変換できない
## [1] "57333-04-12"
20221022 |> as.character() |> as.Date(format = "%Y%m%d") # 文字列に変換する
## [1] "2022-10-22"
17.5.1 ISOdatetime関数で日時データを作成する
ISOdatetime
関数を用いて日時データを作成することもできます。ISOdatetime
関数は引数に年、月、日、時、分、秒の数値を取り、引数に応じた日時データをPOSIXctクラスで返します。
ISOdatetime関数
ISOdatetime(2022, 2, 22, 2, 22, 22) # POSIXct型の2022/2/22 2:22:22を作成
## [1] "2022-02-22 02:22:22 +09"
17.6 連続した日時データの作成
ココまでは、1つの日時データの作成について見てきました。しかし、統計では日時データとして一定間隔で数時間~数年などの連続した時間を取り扱う場合が多いです。このような一定間隔での日時データの作成には、seq
関数を用います。
数値ベクターでのseq
関数と同じく、第一引数に始めの日時、第二引数に終わりの日時、by
引数に時間間隔を入力すると、始めの日時から終わりの日時まで、by
引数で指定した間隔での連続した日時データを作成することができます。
seq
関数の引数にはDate
クラスもPOSIXt
クラスも利用することができますが、Date
クラスとPOSIXt
クラスを同時に用いることはできません。
seq関数で連続する日時データを作成する
<- as.POSIXlt("2022-2-22")
day1 <- as.POSIXlt("2022-2-26")
day2
# day1からday2まで、1日置きのベクター
seq(day1, day2, by="day")
## [1] "2022-02-22 +09" "2022-02-23 +09" "2022-02-24 +09" "2022-02-25 +09"
## [5] "2022-02-26 +09"
# 1日間隔で、5日間のベクター
seq(day1, by="day", length.out=5)
## [1] "2022-02-22 +09" "2022-02-23 +09" "2022-02-24 +09" "2022-02-25 +09"
## [5] "2022-02-26 +09"
# 1週間間隔で、5週間のベクター
seq(day1, by="week", length.out=5)
## [1] "2022-02-22 +09" "2022-03-01 +09" "2022-03-08 +09" "2022-03-15 +09"
## [5] "2022-03-22 +09"
# 2週間間隔で、10週間のベクター
seq(day1, by="2 week", length.out=5)
## [1] "2022-02-22 +09" "2022-03-08 +09" "2022-03-22 +09" "2022-04-05 +09"
## [5] "2022-04-19 +09"
<- as.Date("2022-2-22") # Dateクラスでも同じ演算が使える
day3 seq(day3, by="1 week", length.out=5)
## [1] "2022-02-22" "2022-03-01" "2022-03-08" "2022-03-15" "2022-03-22"
seq(day1, day3, by="day") # POSIXtとDateを同時に使うとエラー
## Error in seq.POSIXt(day1, day3, by = "day"): 'to' must be a "POSIXt" object
seq
関数はジェネリック関数の一つで、引数が数値の場合にはseq.default
関数、整数の場合にはseq.int
関数、引数がPOSIXtの場合にはseq.POSIXt
関数、引数がDateの場合はseq.Date
関数がそれぞれ実行されます。seq
関数の第一引数と第二引数のクラスは同じである必要があります。引数にDateとPOSIXtを指定すると、第一引数に従い用いる関数が変化するため(第一引数がDateならseq.Date
、POSIXtならseq.POSIXt
が呼び出される)、第一引数と第二引数のデータ型が異なるとエラーとなります。
17.7 cut関数
cut
関数は、第一引数に日時データのベクター、第二引数by
に時間間隔("weeks"
、"months"
など)を取り、時間間隔で指定した範囲の日時データを同一の値に変換する関数です。返り値は因子になるため、週や月、年の集計データを収集したい場合などに利用できます。
cut関数
<- seq(day1, by="day", length.out = 25) # 2022-2-22から25日間のデータ
hdays <- cut(hdays, "weeks") # hdaysを週ごとに分けて、因子にする
cutdays 1:14] # 同一週の日時は同じ因子のレベルが振り当てられる
cutdays[## [1] 2022-02-21 2022-02-21 2022-02-21 2022-02-21 2022-02-21 2022-02-21
## [7] 2022-02-28 2022-02-28 2022-02-28 2022-02-28 2022-02-28 2022-02-28
## [13] 2022-02-28 2022-03-07
## Levels: 2022-02-21 2022-02-28 2022-03-07 2022-03-14
class(cutdays) # cut関数の返り値は因子
## [1] "factor"
levels(cutdays) # 週ごとにレベルが設定される
## [1] "2022-02-21" "2022-02-28" "2022-03-07" "2022-03-14"
17.8 日時データを引数に取る関数
上記のcut
関数以外にも、Rには日時データを引数に取る関数が多数設定されています。例えば最初の日時、最後の日時を返すmin
・max
関数、平均の日時を返すmean
関数、最初と最後の日時を返すrange
関数などが代表例です。日時の差はdifftime
関数で計算することができますが、単に日時データを引き算することでも計算できます。また、特定の単位(年、月、日など)で丸める場合には、round
関数を用いることができます。
日時データの関数演算
min(hdays)
## [1] "2022-02-22 +09"
max(hdays)
## [1] "2022-03-18 +09"
mean(hdays)
## [1] "2022-03-06 +09"
range(hdays)
## [1] "2022-02-22 +09" "2022-03-18 +09"
difftime(max(hdays), min(hdays))
## Time difference of 24 days
max(hdays) - min(hdays)
## Time difference of 24 days
round(t, unit="year")
## [1] "2025-01-01 +09"
17.9 演算を一時停止する:Sys.sleep関数
Sys.sleep
関数はRの演算の途中で、演算を指定した時間だけ一時停止するための関数です。一時停止する時間(秒)を数値で引数に取ります。
Sys.sleep関数
Sys.sleep(5) # 5秒待つ
17.10 演算時間の計測
Sys.time
関数を用いると、演算にかかる時間を計測することができます。繰り返し計算などで、とても時間がかかる演算を含む場合には、あらかじめ演算時間を計測しておくと、繰り返し計算全体でどの程度時間がかかるのか把握しやすくなります。
まず、Sys.time
関数の返り値である、現在の時刻を変数t
に代入します。その後何らかの演算を行い(下の例ではSys.sleep
関数で3秒停止)、その後、演算後の現在時刻からt
を引くと、Sys.sleep
関数による演算の時間を計測することができます。Sys.sleep
関数による3秒の停止以外にも、代入等でわずかに時間がかかるため、3秒よりほんの少し時間がかかっていることが計測できます。
同様の時間計測は、system.time
関数を用いても行うことができます。system.time
関数は演算全体を引数に取り、その演算にかかる時間を計測します。
プログラムの演算時間を計測する
<- Sys.time() # 現在時刻を記録
t Sys.sleep(3) # 3秒スリープ
Sys.time() - t # 現在時刻と記録した時刻の差を計算
## Time difference of 3.073357 secs
# system.time関数でも演算時間を計測できる
system.time(for(i in 1:1000000){i^2})
## user system elapsed
## 0.00 0.00 0.01
17.10.1 tictocパッケージ
もう少しスマートに演算時間を計測する方法をtictoc
パッケージ (Izrailev 2023)が提供しています。tictoc
パッケージにはtic
関数とtoc
関数が設定されており、tic
関数で計測を開始し、toc
関数で計測を終了、演算時間を返します。
tic
関数は引数に文字列を取ることができ、toc
関数で計測時間が返ってくる時に、このtic
関数の引数を同時に返してくれます。tic
関数、toc
関数による時間計測は、後入れ先出し(Last In, First Out, LIFO)のルールに従い時間を計測します。ですので、後からtic
関数で計測をスタートした演算時間は、先のtoc
関数で返ってくる仕組みになっています。
tictocパッケージで演算時間を計測
::p_load(tictoc)
pacmantic()
Sys.sleep(3)
toc()
## 3.08 sec elapsed
tic("first")
tic("second")
tic("third")
toc() # 後のtic(third)からの時間がまず返ってくる
## third: 0 sec elapsed
toc()
## second: 0 sec elapsed
toc() # 先のtic(first)が最後に返ってくる
## first: 0 sec elapsed
17.11 時系列データ:tsクラス
時系列データ(time series data)は、日時データとセットになった測定値です。例えば、14章で説明したNile
のデータセットは時系列データの代表的な例です。Nile
は1871年から1970年のナイル川の流量を年ごとに測定したデータです。
Nileデータセット
# 時系列データの代表例:ナイル川の流量
Nile ## Time Series:
## Start = 1871
## End = 1970
## Frequency = 1
## [1] 1120 1160 963 1210 1160 1160 813 1230 1370 1140 995 935 1110 994 1020
## [16] 960 1180 799 958 1140 1100 1210 1150 1250 1260 1220 1030 1100 774 840
## [31] 874 694 940 833 701 916 692 1020 1050 969 831 726 456 824 702
## [46] 1120 1100 832 764 821 768 845 864 862 698 845 744 796 1040 759
## [61] 781 865 845 944 984 897 822 1010 771 676 649 846 812 742 801
## [76] 1040 860 874 848 890 744 749 838 1050 918 986 797 923 975 815
## [91] 1020 906 901 1170 912 746 919 718 714 740
このような時系列データをRで取り扱うために準備されているクラスが、tsクラスです。tsクラスには計測されたデータと共に、日時に関する情報が付属しています。
tsクラスのattribute
attributes(Nile) # 日時に関するattribute(tsp)が記録されている
## $tsp
## [1] 1871 1970 1
##
## $class
## [1] "ts"
tsクラスを引数とする関数が、Rには複数備わっています。tsクラスを引数とする関数の一覧を以下の表3に示します。
関数名 | 適用する演算 |
---|---|
ts(x, frequency, start) | frequency周期で,startから始まるtsオブジェクトを作成する |
as.ts(x) | tsに変換する |
is.ts(x) | tかどうか確認する |
tsp(x) | tsオブジェクトを変換する |
cycle(x) | frequencyの周期の位置を返す |
frequency(x) | frequencyを返す |
deltat(x) | データの時間間隔を返す |
window(x, start, end) | startからendまでのデータを返す |
time(x) | 時間に変換する |
start(x) | 開始日時を返す |
end(x) | 終了日時を返す |
tsクラスの作成と演算
<- rep(1:3, 8) # 時系列の元になる値
value # tsクラスの変数を作成
<- ts(value, frequency = 1, start=c(2023))
tsobj # 2023年から2046年までのtsクラスのデータ
tsobj ## Time Series:
## Start = 2023
## End = 2046
## Frequency = 1
## [1] 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3
as.ts(1:12) # tsに変換
## Time Series:
## Start = 1
## End = 12
## Frequency = 1
## [1] 1 2 3 4 5 6 7 8 9 10 11 12
|> is.ts() # tsオブジェクトであることを確認
tsobj ## [1] TRUE
ts(value, frequency = 4, start=c(2023)) # 4半期ごとのデータ
## Qtr1 Qtr2 Qtr3 Qtr4
## 2023 1 2 3 1
## 2024 2 3 1 2
## 2025 3 1 2 3
## 2026 1 2 3 1
## 2027 2 3 1 2
## 2028 3 1 2 3
ts(value, frequency = 12, start=c(2023)) # 月次のデータ
## Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 2023 1 2 3 1 2 3 1 2 3 1 2 3
## 2024 1 2 3 1 2 3 1 2 3 1 2 3
<- ts(value, frequency = 4, start=c(2023))
tsobj2 |> tsp() # 2023年から2028年4Qまで四半期置きのデータ
tsobj2 ## [1] 2023.00 2028.75 4.00
|> cycle() # 四半期(cycle)についてのラベル
tsobj2 ## Qtr1 Qtr2 Qtr3 Qtr4
## 2023 1 2 3 4
## 2024 1 2 3 4
## 2025 1 2 3 4
## 2026 1 2 3 4
## 2027 1 2 3 4
## 2028 1 2 3 4
|> frequency() # frequencyは4
tsobj2 ## [1] 4
|> deltat() # データの間隔は1/4年
tsobj2 ## [1] 0.25
# 2025年1Qから2026年4Qまでのデータを返す
|> window(c(2025, 1), c(2026, 4))
tsobj2 ## Qtr1 Qtr2 Qtr3 Qtr4
## 2025 3 1 2 3
## 2026 1 2 3 1
|> time() # 各データの時点に変換
tsobj2 ## Qtr1 Qtr2 Qtr3 Qtr4
## 2023 2023.00 2023.25 2023.50 2023.75
## 2024 2024.00 2024.25 2024.50 2024.75
## 2025 2025.00 2025.25 2025.50 2025.75
## 2026 2026.00 2026.25 2026.50 2026.75
## 2027 2027.00 2027.25 2027.50 2027.75
## 2028 2028.00 2028.25 2028.50 2028.75
|> start() # 2023年1Qからのデータ
tsobj2 ## [1] 2023 1
|> end() # 2028年4Qまでのデータ
tsobj2 ## [1] 2028 4
時系列データを取り扱う場合に、必ずしもtsクラスのオブジェクトを用いないといけない、というわけではありません。日時データと値の2つのベクターを用いても、時系列の解析を行うことはできます。
時系列データの解析には、Stan (Carpenter et al. 2017)などの外部ツールを用いる場合もあるため、場合によってはtsクラスではないデータの方が取り扱いやすい場合もあります。
17.12 lubridateパッケージ
上記のように、Rには時間を取り扱うクラスとして、Date、POSIXct、POSIXlt、tsなどを備えています。ただし、フォーマットの設定や関数に見られるように、必ずしもすべてのクラスが時系列データの解析において使いやすい、というわけではありません。
Rでの日時データの取り扱いを簡単にするためのライブラリが、lubridate
パッケージ (Grolemund and Wickham 2011)です。lubridate
パッケージは日時データを取り扱うための関数のセットを提供しており、様々なフォーマットの文字列を簡単に日時データに変換し、演算に用いることができます。
lubridate
パッケージが提供する関数群を以下の表4に示します。
関数名 | 適用する演算 |
---|---|
ymd(x), mdy(x), dmy(x) | xを日付に変換 |
ymd_hms(x), ymd_hm(x) | xを日時に変換 |
hms(x) | xを時間に変換 |
parse_date_time(x, order) | xをorderに従い日時に変換 |
year(x) | xの年を返す |
year(x)<- | xの年を代入値に変換する |
month(x) | xの月を返す |
day(x) | xの日を返す |
hour(x) | xの時間を返す |
minute(x) | xの分を返す |
second(x) | xの秒を返す |
tz(x) | タイムゾーンを返す |
now() | 現在の日時を返す |
today() | 現在の日付を返す |
stamp(char)(x) | xをcharの文字列に合わせて返す |
duration(x, units) | 単位がunits,値がxの時間差(period)オブジェクトを作成 |
years(n) | n年のperiodオブジェクトを作成 |
months(n) | n月のperiodオブジェクトを作成 |
days(n) | n日のperiodオブジェクトを作成 |
hours(n) | n時間のperiodオブジェクトを作成 |
minutes(n) | n分のperiodオブジェクトを作成 |
seconds(n) | n秒のperiodオブジェクトを作成 |
am(x) | xが午前中ならTRUEを返す |
pm(x) | xが午後ならTRUEを返す |
interval(x, y) | xとyのintervalオブジェクトを作成 |
int_length(x) | xの期間の長さを返す |
int_overlaps(x, y) | xとyに時間の重なりがあればTRUEを返す |
17.12.1 日付データへの変換:ymd関数
文字列を日時データに変換する場合、as.POSIXlt
関数やas.Date
関数で、フォーマットを指定するのがRのデフォルトの手法です。この手順を簡単に行うことができる関数が、ymd
関数を含む関数群です。ymd
は、「year, month, day」の略で、この年月日の順で数値が記載された文字列や数値であれば、かなり適当に記載した文字列・数値であっても、正確に日時データに変換してくれます。
日本では年月日の順で日付を書くのが一般的ですが、アメリカでは月日年、ヨーロッパでは日月年の順で日付を書くことになっています。このように、年月日の順番が異なる場合には、ymd
関数ではなく、mdy
関数やdmy
関数を用いることで、日時データに簡単に変換することができます。
ymd・mdy・dmy関数でDateに変換
::p_load(lubridate)
pacman
# どんな書き方でも変換してくれる
ymd("20231020")
## [1] "2023-10-20"
ymd("2023/10/20")
## [1] "2023-10-20"
ymd("2023-10-20")
## [1] "2023-10-20"
ymd("23 10 20")
## [1] "2023-10-20"
ymd("2023年10月20日") # 漢字が入っていても変換可能
## [1] "2023-10-20"
ymd(20231020) # 数値でも変換可能
## [1] "2023-10-20"
ymd(231020)
## [1] "2023-10-20"
mdy("10/20/2023") # USでは月/日/年
## [1] "2023-10-20"
dmy("20/10/2023") # ヨーロッパでは日/月/年
## [1] "2023-10-20"
ym("2023/10") # yearとmonthだけのデータも対応できる
## [1] "2023-10-01"
17.12.2 日時データの変換:ymd_hms関数
時間を含むデータの場合には、ymd_hms
関数などの関数群を用います。こちらも、かなりいい加減な記載の日時データでも、簡単にPOSIXctクラスに変換してくれます(デフォルトのタイムゾーンはUTC、グリニッジ標準時)。タイムゾーンはtz引数に文字列で指定(TZ identifierで指定)することで変更できます。
ymd_hms関数でPOSIXctに変換
ymd_hms("2023/10/20 22:22:22") # POSIXctに変換
## [1] "2023-10-20 22:22:22 UTC"
ymd_hms("2023年10月20日 22時22分22秒") # POSIXctに変換
## [1] "2023-10-20 22:22:22 UTC"
ymd_hms(231020222222) # 数値も変換できる
## [1] "2023-10-20 22:22:22 UTC"
ymd_hms("2023年10月20日 22時22分22秒", tz="Asia/Tokyo") # JSTに変換
## [1] "2023-10-20 22:22:22 JST"
ymd
関数群やymd_hms
関数群などの機能を1つの関数に落とし込んだものが、parse_date_time
関数です。このparse_date_time
関数では、関数名で年月日の順番を指定するのではなく、orders
という引数で年月日、時間の順番を指定します。
parse_date_timeで日時データに変換
parse_date_time("2023/12/21", "ymd")
## [1] "2023-12-21 UTC"
parse_date_time("2023/12/21 12:25:30", "ymdHMS")
## [1] "2023-12-21 12:25:30 UTC"
lubridate
には、日時データから年や月などの一部を取り出す関数群として、year
、month
、week
、day
、hour
、minute
、second
が設定されています。日時データを引数に取り、関数に数値を代入することで、特定の値を変更することもできます。
また、日時データのタイムゾーンをtz
関数で取得することができ、日時データを引数に取ったtz
関数にタイムゾーンを代入することで、タイムゾーンを変更することもできます。
lubridateの日時データ演算に関する関数
<- ymd("2023/10/20") # Dateクラスの変数を作成
t year(t)
## [1] 2023
year(t) <- 2024 # 代入で変更できる
t## [1] "2024-10-20"
tz(t) # タイムゾーンを返す関数
## [1] "UTC"
tz(t) <- "Asia/Tokyo" # 代入でタイムゾーンも変更可能
tz(t)
## [1] "Asia/Tokyo"
17.12.3 現在時刻の取得:today関数とnow関数
Sys.Date
関数やSys.time
関数と同じような関数として、lubridate
にはtoday
関数とnow
関数が設定されています。
today・now関数
today() # 今日の日付
## [1] "2025-03-29"
now() # 今の日時
## [1] "2025-03-29 08:11:45 +09"
17.12.4 時刻を整形した文字列に変換:stamp関数
stamp
関数は日時データを整形し、文字列として返すための関数です。stamp
関数の引数は日時を表記するための文字列で、日時自体はどのような時間でも問題ありません。stamp
関数の後にカッコを付けて、カッコ内に文字列に変換したい日時データを与えます。この関数を実行すると、カッコ内の日時データを、stamp
関数の引数の形に従って整形した文字列に変換して返してくれます。
文字列が日付のみで、日時データがPOSIXctなどの時間を含むデータだと、正しく変更できない場合もあります。
stamp関数で文字列に変換する
stamp("1970/1/1 12:00:00")(now())
## Multiple formats matched: "%Y/%Om/%d %H:%M:%S"(1), "%Y/%d/%Om %H:%M:%S"(1), "%Y/%m/%d %H:%M:%S"(1), "%Y/%d/%m %H:%M:%S"(1)
## Using: "%Y/%Om/%d %H:%M:%S"
## [1] "2025/03/29 08:11:45"
stamp("1970/1/1 12:00:00に作成されたデータ")(now())
## Multiple formats matched: "%Y/%Om/%d %H:%M:%Sに作成されたデータ"(1), "%Y/%d/%Om %H:%M:%Sに作成されたデータ"(1), "%Y/%m/%d %H:%M:%Sに作成されたデータ"(1), "%Y/%d/%m %H:%M:%Sに作成されたデータ"(1)
## Using: "%Y/%Om/%d %H:%M:%Sに作成されたデータ"
## [1] "2025/03/29 08:11:45に作成されたデータ"
# うまくいかないときもある(月と日を曜日に変換している)。
stamp_date("1970年01月01日")(now())
## Multiple formats matched: "%Y年%Om%a%d%a"(1), "%Y年%d%a%Om%a"(1), "%Y年%m%a%d%a"(1), "%Y年%d%a%m%a"(1), "%Y年%Om月%d日"(1), "%Y年%d月%Om日"(1), "%Y年%m月%d日"(1), "%Y年%d月%m日"(1)
## Using: "%Y年%Om%a%d%a"
## [1] "2025年03土29土"
17.13 periodクラス
ココまではDateクラス、POSIXct・POSIXlt型に関するlubridate
の関数について示してきました。lubridate
には、Date・POSIXct・POSIXlt以外に、時間の間隔を取り扱うクラスとして、periodクラスが備わっています。
DateクラスやPOSIXctクラスは基本的に数値型ですので、足し算や引き算で日時を変更することができます。ただし、例えばPOSIXct型で1年3ヶ月と10日後の、3時間前といった変更をしたい場合には、すべて秒として換算し直して演算を行う必要があります。これはあまり直感的ではありませんし、月ごとに日数が異なっているため、正確に演算することも困難です。
periodでの演算
today()
## [1] "2025-03-29"
today() + 10 # 10日後
## [1] "2025-04-08"
now()
## [1] "2025-03-29 08:11:45 +09"
now() + 60 # 1分後
## [1] "2025-03-29 08:12:45 +09"
today() + 365 * 1 + 3 * 30 + 10 # 1年3ヶ月と10日後
## [1] "2026-07-07"
このような複雑な日時データの演算に対応するため、lubridate
ではperiodクラスのオブジェクトを作成し、このオブジェクトを演算に用いることができるようになっています。
periodクラスのオブジェクトを作成するには、duration
関数を用いる、または、years
、months
、days
、hours
、minutes
、seconds
の、「時間の単位+s」の名前が付いた関数を用います。
duration
関数は引数に数値と時間の単位を取り、引数の時間単位で数値の値を持つオブジェクトを作成する関数です(クラスはDuration)。このオブジェクトはDateクラスやPOSIXctクラスとの演算に用いることができます。
例えば、Periodクラスのオブジェクトであるmonths(20)
を用いて、「now() + months(20)
」とすると、現在時刻から20ヶ月後を演算することができます。「1年3ヶ月と10日後の、3時間前」といった複雑な計算も、このperiodクラスを用いれば簡単に行うことができます。
periodクラスを作成する関数群
duration(90, "seconds") # 90秒のperiod
## [1] "90s (~1.5 minutes)"
now() + duration(10, "years") # 10年後
## [1] "2035-03-29 20:11:45 +09"
now() + years(10) # 上と同じ
## [1] "2035-03-29 08:11:45 +09"
now() + months(20) # 20ヶ月後
## [1] "2026-11-29 08:11:45 +09"
now() + days(30)
## [1] "2025-04-28 08:11:45 +09"
now() + hours(40)
## [1] "2025-03-31 00:11:45 +09"
now() + minutes(50)
## [1] "2025-03-29 09:01:45 +09"
now() + seconds(60)
## [1] "2025-03-29 08:12:45 +09"
17.13.1 hms関数
時間に関するperiodクラスのオブジェクトを作成する場合には、ymd
関数のように、文字列を自動的にperiodクラスのオブジェクトに変換してくれる関数である、hms
関数を用いることができます。hms
関数は文字列を時・分・秒を持つperiodクラスのオブジェクトに変換し、返してくれます。ymd
とは異なり、hms
関数は数値をperiodに変換することはできません。
hms関数でperiodクラスオブジェクトを作成
hms("2:22:22")
## [1] "2H 22M 22S"
hms(22222) # エラー
## Warning in .parse_hms(..., order = "HMS", quiet = quiet): Some strings failed
## to parse
## [1] NA
17.13.2 時間の切り上げ・切り下げ
日時データを四捨五入する際には、Rのround
関数を用いることができます。ただし、切り下げ(floor
)や切り上げ(ceiling
)の関数は、DateクラスやPOSIXtクラスには対応していません。
日時の四捨五入・切り下げ・切り上げには、round_date
、floor_date
、ceiling_date
関数を用いることができます。切り上げ等の単位は、unit
引数に指定します。
日時の四捨五入
now() |> round_date(unit="month") # 月で四捨五入
## [1] "2025-04-01 +09"
now() |> floor_date(unit="hour") # 時間で切り下げ
## [1] "2025-03-29 08:00:00 +09"
now() |> ceiling_date(unit="hour") # 時間で切り上げ
## [1] "2025-03-29 09:00:00 +09"
17.13.3 am・pm関数
日時データが午前か午後かを判別する関数が、am
関数とpm
関数です。共に論理型(TRUE
・FALSE
)を返す関数で、引数が午前ならam
関数はTRUE
、pm
関数はFALSE
を返します。
am・pm関数
now() |> am()
## [1] TRUE
now() |> pm()
## [1] FALSE
17.13.4 interval
lubridate
には、ある期間(interval)を評価するためのクラスとして、Intervalクラスが設定されています。このIntervalクラスのオブジェクトはinterval
関数に始めと最後の日時を与えることで作成できます。Intervalの期間の長さはint_length
関数で、2つのIntervalクラスオブジェクトに重複があるかどうかはint_overlaps
関数を用いて判別できます。
Intervalの取り扱い
<- interval(ymd("2023-10-20"), ymd("2023-10-30"))
intr1 <- interval(ymd("2023-10-25"), ymd("2023-11-5"))
intr2
# 始めと最後の日が記録されている
intr1 ## [1] 2023-10-20 UTC--2023-10-30 UTC
|> class() # データ型はInterval
intr1 ## [1] "Interval"
## attr(,"package")
## [1] "lubridate"
int_length(intr1) # 期間の長さの単位は秒
## [1] 864000
int_overlaps(intr1, intr2) # 重複があればTRUEが返ってくる
## [1] TRUE