28
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

Organization

lubridateパッケージ入門

※この記事はDo more with dates and times in R with lubridate 1.3.0を翻訳したものですが、とても雑にやったので原文と大分違っていると思います。

日付と時刻のパース

Rで日付や時刻を含むデータを扱う方法は大分ややこしいが、{lubridate}パッケージを使えばもっと単純にやれる。

例えば文字列をパースする場合、y, m, dを文字列に含まれる年月日の順序に合わせて並び替えた関数を使えばよい。例を見たほうがわかりやすいだろう。

library(lubridate)
> ymd("20110604")
[1] "2011-06-04"
> mdy("06-04-2011")
[1] "2011-06-04"
> dmy("4/6/2011")
[1] "2011-06-04"

これらの関数は様々な形式、セパレータを扱えるので、パースの手順を単純にできる。

もし文字列に時刻の情報もあるのなら、関数名に続けて_h, _hm, _hmsを追加することで、時間、時間と分、時間と分と秒を読み込むことができる。おそらく、ymd_hmsがもっとも一般的な形式だろう。もしタイムゾーンを指定したければtz=引数を使う。

> ymd_hms("2011-06-04 12:00:00", tz = "Pacific/Auckland")
[1] "2011-06-04 12:00:00 NZST"

情報の代入と抽出

second minute hour day wday yday week month year tz、これらの関数を使って日時から特定の情報を抽出できる。また、これらの関数を使って代入もできる。

> arrive <- ymd_hms("2011-06-04 12:00:00", tz = "Pacific/Auckland")
> second(arrive)
[1] 0
> second(arrive) <- 25
> second(arrive)
[1] 25

wdaymonthlabel=引数にTRUEを指定することで、出力を数値でなく曜日名や月名に変更できる。

> wday(arrive)
[1] 7
> wday(arrive, label = TRUE)
[1] Sat
Levels: Sun < Mon < Tues < Wed < Thurs < Fri < Sat
> month(arrive, label = TRUE)
[1] Jun
12 Levels: Jan < Feb < Mar < Apr < May < Jun < Jul < Aug < ... < Dec

タイムゾーン

with_tzは特定のタイムゾーンにおける時刻を表示する。例えばオークランドにで2011/7/1 9:00のとき、シカゴでは何時か知りたければ次のようにする。

> meeting <- ymd_hms("2011-07-01 09:00:00", tz = "Pacific/Auckland")
> meeting
[1] "2011-07-01 09:00:00 NZST"
> with_tz(meeting, "America/Chicago")
[1] "2011-06-30 16:00:00 CDT"

日時はそのままで、タイムゾーンのみを変更するにはforce_tz関数を使う。

> force_tz(meeting, "America/Chicago")
[1] "2011-07-01 09:00:00 CDT"

インターバル

{lubridate}はインターバルを表現するための専用のクラスを備えている。インターバルクラスのオブジェクトはinterval関数または二項演算子%--%を使って作成できる。

> arrive <- ymd_hms("2011-06-04 12:00:00", tz = "Pacific/Auckland")
> leave <- ymd_hms("2011-08-10 14:00:00", tz = "Pacific/Auckland")
> auckland <- interval(arrive, leave)
> auckland
[1] 2011-06-04 12:00:00 NZST--2011-08-10 14:00:00 NZST
> arrive %--% leave
[1] 2011-06-04 12:00:00 NZST--2011-08-10 14:00:00 NZST

int_overlaps関数は2つのインターバルに時期的な重なりがあるかどうかを確認する。

> jsm <- interval(ymd(20110720, tz="Pacific/Auckland"), ymd(20110831, tz="Pacific/Auckland"))
> jsm
[1] 2011-07-20 NZST--2011-08-31 NZST
> int_overlaps(auckland, jsm)
[1] TRUE

インターバルオブジェクトに対しては、int_start int_endなどの専用関数の他、setdiff union intersectのような集合演算も適用できる。

日付の計算

上述のインターバルは2つの特定の日時の間に定義されるものだった。{lubridate}はこれに加えて、一般的な時間間隔に関するクラスである、durationsperiodsを持っている。periodsを作成するには、時間の単位を複数形にした関数を使う。

> minutes(2)
[1] "2M 0S"

durationsを作るには、periodsを作成する関数の頭にdをつける。

> dminutes(2)
[1] "120s (~2 minutes)"

durationsクラスは数学的に正しい結果を返す。すなわち、durationsにおける1年は常に365日である。一方で、periodsは暦の上で受ける変動と同じ変動を受ける。この違いはうるう年の1月1日に「1年」を足す演算を見るとよく分かる。

> ymd(20120101) + years(1)
[1] "2013-01-01"
> ymd(20120101) + dyears(1)
[1] "2012-12-31"

durationsにおける1年は365日であるが、periodsにおける1年はうるう年では366日になる。

インターバルと組み合わせて期間の計算などができる。

> auckland / ddays(1)
[1] 67.08333

商と余りも計算できる。

> auckland %/% months(1)
 : シグネチャー Timespan#Timespan’ を持つメソッドが、関数 ‘%/%’ に対して選ばれました,
 対象シグネチャー Interval#Period’ です。
 "Interval#ANY", "ANY#Period" もまた有効かもしれません
[1] 2

余りの場合は新しいインターバルが返ってくるので、目的に応じてas.periodas.durationで変換すると良いだろう。

> auckland %% months(1)
[1] 2011-08-04 12:00:00 NZST--2011-08-10 14:00:00 NZST
> as.period(auckland %% months(1))
[1] "6d 2H 0M 0S"
> as.duration(auckland %% months(1))
[1] "525600s (~6.08 days)"

月の長さが変わる場合の算術演算

月や年の長さはしばしば変化するので、算術演算が直感的でなくなる場合がある。例えば1月31日に1ヶ月を足す場合を考えてみよう。パッと思いつくだけでも3通りの答があり得る。

  1. 2月31日 (単純に月に1を足す。こんな日は存在しないが。)
  2. 3月4日 (1月31日の31日後として計算。)
  3. 2月28日 (翌月末をうるう年ではないと仮定して計算。)

a + b - b = aというルールに従えるのは1のみであるが、しかし2月31日は日付として正しくない。{lubridate}では演算の結果として正しくない日付になる場合、NAを返すことになっている。これはversion 1.3.0からの変更なので古いバージョンの{lubridate}を使っていた場合は注意。

> jan31 <- ymd("20130131")
> jan31 + months(0:11)
 [1] "2013-01-31" NA           "2013-03-31" NA           "2013-05-31"
 [6] NA           "2013-07-31" "2013-08-31" NA           "2013-10-31"
[11] NA           "2013-12-31"

もし2の結果(31日を足した結果を表示)が欲しければ、floor_dateで月初の日付に変換した後にdays(31)を足すという手順を取る。

> floor_date(jan31, "month") + months(0:11) + days(31)
 [1] "2013-02-01" "2013-03-04" "2013-04-01" "2013-05-02" "2013-06-01"
 [6] "2013-07-02" "2013-08-01" "2013-09-01" "2013-10-02" "2013-11-01"
[11] "2013-12-02" "2014-01-01"

3の結果がほしければ、二項演算子%m+% %m-%を使うと、月末の日付を適当に調整してくれる。

> jan31 %m+% months(0:11)
 [1] "2013-01-31" "2013-02-28" "2013-03-31" "2013-04-30" "2013-05-31"
 [6] "2013-06-30" "2013-07-31" "2013-08-31" "2013-09-30" "2013-10-31"
[11] "2013-11-30" "2013-12-31"
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
28
Help us understand the problem. What are the problem?