LoginSignup
1
0

More than 5 years have passed since last update.

「2012-07-04 10:01:08」のような日時を5分など任意のスパンで丸める

Last updated at Posted at 2018-05-24

csvなどのデータを読み込んで "2017-09-01 13:15:23" のような時間の表記を含んでいるものをさあ集計しようとすると、秒まで入っているので、

  • 時間単位でまとめて集計したい とか
  • 月単位でまとめたい集計したい とか

の時に困ったりします。

「何かちゃんとしたやりかたあるんだろうなあ」と思いつつ文字列にして半ば強引に文字列操作でやってました。

# サンプルデータ
test <- as.POSIXct(c(
    "2017-09-01 14:31:21",
    "2017-09-01 15:40:43",
    "2017-09-01 16:20:26",
    "2017-09-01 17:22:16",
    "2017-09-01 18:30:37"
))

文字列で半ば力技

> # 時間で丸める
> paste(substr(test,1,14),"00",sep="")
"2017-09-01 15:00" "2017-09-01 15:00" "2017-09-01 16:00" "2017-09-01 16:00" "2017-09-01 16:00"

> # 月単位で丸める
> paste(substr(test,1,8),"01",sep="")
"2017-09-01" "2017-09-01" "2017-09-01" "2017-09-01" "2017-09-01"

これで集計はできなくはないけど、POSIXctせずに文字列のままいけるけど、
なんだかなあと思う日々。

それに5分とか15分とかでまとめたい時に逆に面倒になる。

丸めるならroundじゃない?

と思って調べてみると、できそう。

> # 分で丸める
> round(test,"mins")
[1] "2017-09-01 15:31:00 JST" "2017-09-01 15:41:00 JST" "2017-09-01 16:20:00 JST" "2017-09-01 16:22:00 JST" "2017-09-01 16:31:00 JST"

> # 時間で丸める
> round(test,"hours")
[1] "2017-09-01 16:00:00 JST" "2017-09-01 16:00:00 JST" "2017-09-01 16:00:00 JST" "2017-09-01 16:00:00 JST" "2017-09-01 17:00:00 JST"

> # 日で丸める
> round(test,"days")
[1] "2017-09-02 JST" "2017-09-02 JST" "2017-09-02 JST" "2017-09-02 JST" "2017-09-02 JST"

おお、いい感じ。
でも調子に乗ると、、

> # 月で丸めたい!
> round(test,"month")
 match.arg(units) でエラー: 
   'arg'  secs, mins, hours, days の一つでなければなりません 

> # 15分で丸めたい!
> round(test,"15 mins")
 match.arg(units) でエラー: 
   'arg'  secs, mins, hours, days の一つでなければなりません 

oh.. 使えるのは 秒、分、時間、日 の単位のみ。
あと一息、帯に短い。。

まさかcutが使えるとは。

数字のベクトルをよしなに切り分けてくれるcut。
この子が時間でも切り分けてくれるらしい。灯台下暗し。

> # 15分で丸める
> cut(test,"15 mins")
[1] 2017-09-01 14:31:00 2017-09-01 15:31:00 2017-09-01 16:16:00 2017-09-01 17:16:00 2017-09-01 18:16:00
16 Levels: 2017-09-01 14:31:00 2017-09-01 14:46:00 2017-09-01 15:01:00 2017-09-01 15:16:00 2017-09-01 15:31:00 ... 2017-09-01 18:16:00

> # 2時間で丸める
> cut(test,"2 hours")
[1] 2017-09-01 14:00:00 2017-09-01 14:00:00 2017-09-01 16:00:00 2017-09-01 16:00:00 2017-09-01 18:00:00
Levels: 2017-09-01 14:00:00 2017-09-01 16:00:00 2017-09-01 18:00:00

> # 月で丸める
> cut(test,"month")
[1] 2017-09-01 2017-09-01 2017-09-01 2017-09-01 2017-09-01
Levels: 2017-09-01

> # 年だってOK
> cut(test,"years")
[1] 2017-01-01 2017-01-01 2017-01-01 2017-01-01 2017-01-01
Levels: 2017-01-01

これはちょっとうれしい。
※ただしfactor形式になるので注意。

(追記)パッケージlubridateを使う。

コメントを頂いて、tidyverseの中のlubridateでもできるとのこと。
lubridateは ymd()だとか mdy()だとかくらいしか認知していなかったけど、こんなのもあるのね。

> library(lubridate)

> # 15分で丸める
> round_date(test,"15 mins")
[1] "2017-09-01 14:30:00 JST" "2017-09-01 15:45:00 JST" "2017-09-01 16:15:00 JST" "2017-09-01 17:15:00 JST" "2017-09-01 18:30:00 JST"


> # 2時間で丸める
> round_date(test,"2 hours")
[1] "2017-09-01 14:00:00 JST" "2017-09-01 16:00:00 JST" "2017-09-01 16:00:00 JST" "2017-09-01 18:00:00 JST" "2017-09-01 18:00:00 JST"

> # 月で丸める
> round_date(test,"month")
[1] "2017-09-01 JST" "2017-09-01 JST" "2017-09-01 JST" "2017-09-01 JST" "2017-09-01 JST"

> # 年だってOK
> round_date(test,"years")
[1] "2018-01-01 JST" "2018-01-01 JST" "2018-01-01 JST" "2018-01-01 JST" "2018-01-01 JST"

しかも返り値がPOSIXctのままで便利。
マニュアル見ると、
"week", "bimonth", "quarter"=="3 months", "halfyear" などでもOKらしい。

また、加えて、丸めるだけでなく、切り捨てや切り上げも出来て便利。

> test
[1] "2017-09-01 14:31:21 JST" "2017-09-01 15:40:43 JST" "2017-09-01 16:20:26 JST" "2017-09-01 17:22:16 JST"
[5] "2017-09-01 18:30:37 JST"

> # そのまま丸める
> round_date(test,unit="5 mins")
[1] "2017-09-01 14:30:00 JST" "2017-09-01 15:40:00 JST" "2017-09-01 16:20:00 JST" "2017-09-01 17:20:00 JST"
[5] "2017-09-01 18:30:00 JST"

> # 切り捨て(それより小さい最大)
> floor_date(test,unit="5 mins")
[1] "2017-09-01 14:30:00 JST" "2017-09-01 15:40:00 JST" "2017-09-01 16:20:00 JST" "2017-09-01 17:20:00 JST"
[5] "2017-09-01 18:30:00 JST"

> # 切り下げ(それより大きい最少)
> ceiling_date(test,unit="5 mins")
[1] "2017-09-01 14:35:00 JST" "2017-09-01 15:45:00 JST" "2017-09-01 16:25:00 JST" "2017-09-01 17:25:00 JST"
[5] "2017-09-01 18:35:00 JST"
> 

enjoy!

1
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0