まずは蝋の翼から。

学んだことを書きながら確認・整理するためのメモブログ。こういうことなのかな?といったことをふわっと書いたりしていますが、理解が浅いゆえに的はずれなことも多々あると思うのでツッコミ歓迎

tsの週次データについてと、ついでにtsibbleについて

Rのtsクラスの振る舞いがよくわからなかったのでメモ。ついでにtibble形式のtsであるtsibbleについても。

基本

tsクラスは時系列(Time Series)情報をindexとして持ったデータ型。 時系列ってなんやねんと思うが、要するに「ある単位においてどういう粒度があるデータか」、例えば「1年という単位で粒度4(四半期)」とか、「1年という単位で粒度12(月次)」とか「1年という単位で粒度52(週次)」とかそういう構造を情報として付与したデータ。 各粒度間の間隔は同一(空欄含む)。

tsクラスの使い方としては、周期の粒度(frequency)と、データの開始時点を指定する。

月次データ

以下のような月次データを考える。

df_month = tibble(month = seq(as.Date("2018-02-01"), as.Date("2018-05-01"), by = "month"),
                  v = 1:4)
# A tibble: 4 x 2
# month          v
# <date>     <int>
#   1 2018-02-01     1
# 2 2018-03-01     2
# 3 2018-04-01     3
# 4 2018-05-01     4

このような月次の場合は、frequencyは12となる。また、データの開始月は2018年の2番目の月である2018年2月なのでc(2018,2)と指定する。

df_month %>% 
  ts(frequency = 12, start = c(2018,2))

#                  month v
# Feb 2018 17563 1
# Mar 2018 17591 2
# Apr 2018 17622 3
# May 2018 17652 4

ここで注意したいのは、month列に入っている値から判定しているわけではなく、あくまで12個毎に次の周期となるデータを作成しているだけということ。そのため、データは昇順に並び替えてから渡す必要がある。

# 順番が適していない場合(降順)
df_month %>% 
  arrange(-v) %>% 
  ts(frequency = 12, start = c(2018,2))
# month v
# Feb 2018 17652 4
# Mar 2018 17622 3
# Apr 2018 17591 2
# May 2018 17563 1

今回、startはc(2018,2)だが、これは「データは、周期が2018であり、周期内で2番目から始まっている」という解釈を与えていることになる。このことから、例えば上のデータにstart=c(2018,1)とすると、2018/02の値が2018/01として認識されてしまう。

df_month %>% 
  ts(frequency = 12, start = c(2018,1))
# month v
# Jan 2018 17563 1
# Feb 2018 17591 2
# Mar 2018 17622 3
# Apr 2018 17652 4

また、例えば2018/01, 2018/02, 2018/04のデータしか入っていない場合にts変換をすると2018/03が欠損しているにもかかわらず前寄せになるので2018/04の値が2018/03になる。そのため、欠損がある場合はその部分をNAにしたデータを作成する必要がある。

df_month %>% 
  filter(month != '2018-04-01') %>% 
  ts(frequency = 12, start = c(2018,2))
# month v
# Feb 2018 17563 1
# Mar 2018 17591 2
# Apr 2018 17652 4

month列はあくまで値の1つとして認識され、ts型内では暗黙的に数値型に変換されるので日付'2018-02-01'は数値型に変換された17563として型変換される。

また、周期内で何番目か、という部分は一部frequencyでは自動で適した値になる。例えばfrequencyが12なら月名が表示されるし4なら四半期名が表示される。

週次データ

以下のようなデータで考える。

df_week = tibble(week = seq(as.Date("2018-01-08"), as.Date("2018-01-29"), by = "week"),
                  v = 1:4)

# A tibble: 4 x 2
# week           v
# <date>     <int>
#   1 2018-01-08     1
# 2 2018-01-15     2
# 3 2018-01-22     3
# 4 2018-01-29     4

週次のためfrequency=52とし、2018年の1週目開始なのでstart=c(2018,1)とする。

df_week %>% 
  ts(frequency = 52, start = c(2018,1))

# Time Series:
#   Start = c(2018, 1) 
# End = c(2018, 4) 
# Frequency = 52 
# week v
# 2018.000 17539 1
# 2018.019 17546 2
# 2018.038 17553 3
# 2018.058 17560 4

周期内で何番目か、という部分は一部frequencyでは自動で適した値になる

と書いたように月次の場合は月名が出るが週次の場合は、2018 week1のようには出ずに2018.019のように出る。これは、1/52 = 0.19より、周期数 + 0.19*(week_no - 1)として表示される。

これについては割とどうしようもなさそう。また、年によっては53週になったり、うるう年のときは54週になったりするがその場合はどうするかというとこれもどうしようもなさそう。

[参考]

stackoverflow.com

tsibble

tsibbleはts情報を持ったtibbleのようなもの。概要は以下参照

speakerdeck.com

試しに、先程と同様の月次データをtsibbleに変換すると以下のようになる。

df_month = tibble(month = seq(as.Date("2018-02-01"), as.Date("2018-05-01"), by = "month"),
                  v = 1:4) %>% 
  tsibble::as_tsibble()

# A tsibble: 4 x 2 [1D]
# month          v
# <date>     <int>
#   1 2018-02-01     1
# 2 2018-03-01     2
# 3 2018-04-01     3
# 4 2018-05-01     4

frequencyは[1D]なので1日刻み...。frequencyは自動で算出されるようだが、ドキュメントを読むとデータ型で判定されているようだ。

cran.rstudio.com

Date: “day” (D)

今回はDate型だったので[1D]と判定された模様。月次にしたい場合はyearmonth型に変換する必要がある。これはtsibble::yearmonthで変換ができる模様。

df_month = tibble(month = seq(as.Date("2018-02-01"), as.Date("2018-05-01"), by = "month"),
                  v = 1:4) %>% 
  mutate(month = tsibble::yearmonth(month)) %>% 
  tsibble::as_tsibble()

# A tsibble: 4 x 2 [1M]
# month     v
# <mth> <int>
#   1 2018  2     1
# 2 2018  3     2
# 3 2018  4     3
# 4 2018  5     4

[余談]forecastでの扱いについて

ARIMAなどでforecastを使うと、予測値が出てくる。

data_forecast

# Point Forecast
# Jun 2018       1
# Jul 2018       2
# Aug 2018       3
# Sep 2018       4
# Oct 2018       5
# Nov 2018       6
# Dec 2018       7

また、mean部分を抜き出すとtsで予測値が出てくる。

data_forecast$mean

#      Jun Jul Aug Sep Oct Nov Dec
# 2018 1   2   3   4   5   6   7

time()を使うとTime Series部分を抜き出すことができる。このとき出てくる値は周期数 + (1/12)*(week_no - 1)として出てくる。

time(data_forecast$mean)

#           Jun          Jul            Aug           Sep          Oct            Nov      Dec
# 2018 2018.417 2018.500 2018.583 2018.667 2018.750 2018.833 2018.917

この値はas.Dateで日付型に変換することで、その年月の初日(1日)として取得ができる。

as.Date(time(data_forecast$mean))

# [1] "2018-06-01" "2018-07-01" "2018-08-01" "2018-09-01" "2018-10-01" "2018-11-01" "2018-12-01"

ただし、これはあくまで月次の場合なので週次などでは変換ができない。
おそらく、as.Date()の使用上の問題。

では、どうやって日付として抜き直せるかというと、わからないです。
私は現状では、testとして与えたtsの元データ(ts変換前)の日付部分だけ抽出して、それを貼り付けています。