餡子付゛録゛

ソフトウェア開発ツールの便利な使い方を紹介。

「年/月」の形式を月末日でDate型に変更

月次データで「年/月」と言う形式(e.g. 2013/11、2014/2)は良く見かけると思いますが、Rのread.table関数でデータフレームに読み込むと文字列型*1になってしまいます。日付型でないと、subset関数などで絞り込むときに不便ですね*2。しかし、as.Date関数はこの形式を日付型に変えてくれません。そこで、ちょっとした細工をしてみましょう。
日経平均.txtと言うファイルを読み込みます。

df1 <- read.table("日経平均.txt", header=TRUE, sep="\t")

中身は、こんな感じです。

年月 始値 高値 安値 終値
1994/01 17369.74 20229.12 17369.74 20229.12
1994/02 20416.34 20416.34 18931.39 19997.20
1994/03 20216.62 20677.77 19111.92 19111.92

as.Dateをすると、こんな悲劇に。日付がないのがいけない模様です。

as.Date(df1$年月,"%Y/%m")
[1] NA NA NA NA NA NA NA NA NA

gsubで置換して日付を足せば変換できます。

df1$年月日 <- as.Date(gsub("([0-9]+)/([0-9]+)", "\\1/\\2/1", df1$年月))

これをsubset(df1, 年月日>="2013-1-1" & 年月日<="2013-12-31")のように絞り込めます。

日付を月末にする

少し応用して、2013-12-31のように月末値を代入しましょう。月末日は毎月かわりますし、うるう年の処理もいることに注意してください。
まずは月始日*3で、Date型ではなく、POSIXlt型の変数を作ります。

tmpDate <- as.POSIXlt(gsub("([0-9]+)/([0-9]+)", "\\1/\\2/1", df1$年月))

tmpDate$yearで年から1900を引いたものが、tmpDate$monで月から1を引いたものが、tmpDate$mdayで日が取得できます。これから翌月の月始日の日付を作成します。12月の翌月は、年が一つ増えて、1月に戻ることに注意してください。

nextMonth <- ISOdate(tmpDate$year+1900+(tmpDate$mon+1==12)*1, ((tmpDate$mon+1) %% 12)+1, 1)

他の環境に習熟している人は、mktimeではなくISOdateかと思うかも知れません。
翌月の月始日の24時間前(=3600*24秒)が当月の月末です。

df1$年月日 <- as.Date(nextMonth - 3600*24)

別解

見直して、コードの見通しを改善しました。

tmpDate <- as.POSIXlt(gsub("([0-9]+)/([0-9]+)", "\\1/\\2/1", df1$年月))
tmpDate$mon <- tmpDate$mon + 1 # 1ヶ月ずらす(桁上がり処理はされる)
tmpDate$mday <- 0 # 翌月の0日目は、当月の月末
df1$年月日 <- as.Date(tmpDate)

*1:正確には因子になります。

*2:文字列として2013/2と2013/11を比較すると、2013/11のほうが小さくなります。2013/02としてあれば良いのですが。

*3:必ず1日です。