家計簿を CSV ファイルで記入して、R で加工して、ggplot2 で表示

f:id:joker1110:20120216180219p:image:w360

背景

家計簿をつけることは、自分の経済状況を把握する上で、とても重要な指標になる。家計簿をつけることができる人間は、自己管理や忍耐力などのさまざまな面で評価される。しかしながら、私にとって「家計簿をつける」ことは非常に困難だ。だって面倒なんだもん。
通常の家計簿では、費目(品名など)や用途(消耗品、嗜好品など)なんかで分けて、月ごとに合計出して・・・なんてやるわけです。こんなの面倒すぎて、やってられない。菓子パンは食料品か嗜好品か?なんてことで悩みたくない。つーか、そんなに詳細につけたところで、意味があるのか?後で見直して、「あー、先月は嗜好品がちょっと多かったなぁ。今月は抑えるか。」なんてことになるのか?なる人は立派です。ていうかそういう人は家計簿つけれないとかで悩まないんだろう。私は悩む。家計簿をつけたい!でも面倒。どうにか簡単に楽しくできないものか。

目的

家計簿を、出来る限り有益な情報を残しつつ、簡単につけることができる方法を模索する。

思考

家計簿の意味は、

  1. 収入と出費を明確にすることで、現状を把握しコントロールする
  2. 過去から現在までの傾向を探ることで、将来的な予測を行うことができる

といったところか。
1.に関しては、金銭の動きだけを記すことで事足りる。
2.に関しては、何に出費したのか、その目的はなんだったのか、といった情報もいくらか盛り込まないといけないだろう。つまり、家計簿で費目を分けて細かく記述する意味は、将来予測のためである。となるともちろん、統計的な知識が必要になる。逆に言えば、どんなに細かい情報を残していたとしても、それを分析する力がなければ意味が無い(それにこういうデータは分析者が欲しい情報とは異なることが多いのだ)。以上のことをふまえて、どこまで細かくつけるか、ではなく、どういった予測が行いたいのか、に注目することで、記述法が見えてきた。
私が知りたい予測は、何にいくら使いそうか、なんてことじゃない。そんなのは大体変わらないし、変わるとしても計画的に購入しているから問題ない。ここで知りたいのは、「どこで使いそうか」だ。つまり、コンビニで弁当を買うのとスーパーで買うのとでは、後者のほうが明らかに安い(前者が明らかにおいしい)。買うもの自体は変わらないのに、買う場所によって金額が違うのだ。つまり、家計簿によって、どこで出費する傾向が強いかが分かれば、その場所に行くことを制限する抑止力として働き、結果として利益につながるはずだ。

実験

記述する項目は、時間、場所、金額の3点にする。こうすると、レシート1枚が一つのデータセットになる。記述するファイルは何でも良いけど、ここでは CSV ファイル(カンマ区切りのデータ)とする。つまり、

datetime place expense
2012-01-05 03:51:00 A店 1240
2012-01-07 20:26:00 G店 1413
2012-01-05 23:07:00 B店 440
2012-01-05 23:21:00 A店 548
2011-12-19 15:48:00 E店 438
2012-01-02 22:54:00 A店 557
2012-01-07 05:09:00 A店 1341
2012-01-07 20:29:00 B店 480
... ... ...

みたいな感じ。データは決して自分で整理せず、あくまでレシート内容を1行に書くに留める。整理は EXCEL なんかだと煩雑になるので、R で行うことにする(趣味の問題か)。
まずはデータの読み込み。

options(encoding="SJIS")
cost <- read.csv("HouseholdAccountBook.csv",header=T)

これで、cost にデータフレームとして読み込まれる。
次に、時間を計算するために数値として変換する。

cost$datetime <- as.POSIXct(cost$datetime,'%Y-%m-%d %H:%M:%S') # 時間文字列を数値として扱うために変換
cost <- cost[order(cost$datetime),] # 時間順に昇順ソート
cost <- cbind(cost, data.frame(month=format(cost$datetime,"%Y年%m月"),day=format(cost$datetime,"%d"))) # データに月と日のカテゴリ変数を追加

さらに、月別の累積金額を追記しておく。

cum <- by(cost$expense,cost$month,cumsum) # 月ごとの累積金額
cum.d <- data.frame()
for(c in cum){ # 累積金額をデータフレームに
  cum.d <- rbind(cum.d, data.frame(cum.expense=c))
}
cost <- cbind(cost,cum.d) # 元データに結合

また、月別の合計金額をグラフ中にテキストで表示するために準備。

cost.cum <- as.data.frame(xtabs(expense~month, cost)) # 月別合計金額
colnames(cost.cum) <- c("month","cum.expense") # 列名を元データに合わせる
cost.cum <- merge(cost,cost.cum) # 元データとマージ(日時を付加するため)

準備完了。いよいよ ggplot2 でグラフ化する。

g <- ggplot(cost) # 元データ
g <- g + geom_bar(aes(x=datetime,weight=expense,group=place,fill=place),colour="grey90",binwidth=1*24*60*60) # 横軸に日時、縦軸に金額、場所ごとに色分け、幅は1日ごとに
g <- g + geom_point(aes(x=datetime,y=cum.expense),colour=cCyan,shape=1,size=3) # 累積金額をポイントで
g <- g + geom_line(aes(x=datetime,y=cum.expense),colour=cCyan) # ラインで
g <- g + geom_text(data=cost.cum,aes(x=datetime,y=cum.expense,label=cum.expense),hjust=1.2,vjust=0.5) # 月別合計金額を最後の点の横に記述
g <- g + geom_smooth(aes(x=datetime,y=cum.expense)) # 近似曲線
g <- g + scale_x_datetime(major="1 week", format="%b%d") # 横軸を週刻みに
g <- g + facet_grid(.~month,scales="free") # 月別にグラフを分ける
g <- g + opts(title=sprintf("家計簿")) # グラフタイトル
g <- g + labs(x="日付",y="出費") # 軸名
g
grid.gedit("text", gp=gpar(fontfamily="HiraMaruProN-W4")) # 日本語に対応するため(Mac以外の場合はfontfamilyをいじる必要がある)

出来た図がこれ。
f:id:joker1110:20120128213710p:image:w640
なかなかいい感じ。累積金額が直線的に伸びているのが分かるし、どこで購入しているかも分かりやすい。
次に、場所ごとの合計金額を月別に表示してみよう。まずはデータを加工する。

each.cost <- as.data.frame(xtabs(expense~place+month,cost)) # 場所別の月別合計(その月にどこでいくら使ったか)
each.cum <- by(each.cost$Freq,each.cost$month,cumsum) # 場所別にしたときの累積(後でテキストで記述するため)
each.cum.d <- data.frame()
for(c in each.cum){ # 累積金額をデータフレームに
  each.cum.d <- rbind(each.cum.d, data.frame(cum.expense=c))
}
each.cost <- cbind(each.cost,each.cum.d) # 場所別の月別合計に結合

さて、図示。

g <- ggplot(each.cost)
g <- g + geom_bar(aes(x=month,weight=Freq,fill=place,colour=place),colour="grey90") # 場所別で積み重ねる
g <- g + geom_text(aes(x=month,y=cum.expense-Freq/2,label=paste(place,"=",Freq,sep=""),group=month),position=position_jitter(),size=4) # 場所別の合計金額をグラフ内に記述
g <- g + opts(title=sprintf("家計簿(場所別)")) # タイトル
g <- g + labs(x="月",y="出費(累積)") # 軸名
g
grid.gedit("text", gp=gpar(fontfamily="HiraMaruProN-W4")) # 日本語用

f:id:joker1110:20120128214755p:image:w640
A店での出費が多いなぁ。なんてことが分かりやすい。今後は CSV データを記入していくだけで、R が図にしてくれる。もっと詳細な分析がしたかったら、そのまま R の関数に当てはめることが可能だ。

結論

家計簿は、時間と場所と金額さえ分かれば、傾向がつかめる。データは CSV 形式で記入して、R でデータを加工して、ggplot2 で図示する。今後は、レシート内容を CSV に記入するだけで、出費を把握できる。