論理の流刑地

地獄の底を、爆笑しながら闊歩する

Rで縦断データを使うときの前処理でやること集

なんか追加すべき内容があったときに随時更新系のやつ。

Introduction


経済学徒・政治学徒・社会学徒etcにおいてパネルデータの分析をするとき、だいたいStataを使用するのがデファクトスタンダードになっている。
たしかにStataはパネルデータ分析をするうえで良いソフトだけど、まぁでも個人的にはRに慣れ親しんでいるからRの中で完結させたいという欲もある。

そこでRでパネルデータを分析するうえでの参考資料を漁ると、下のURLにあるように、データができあがっている状態でどう分析するかについては、それなりに使える記事があったりする。
(ちなみに下の関連記事でも言及した通り、plm()を使って固定効果モデルを推計するときは、自分で補正しないとStataと推計値がズレるので注意)

そのいっぽうで、分析にいたるまでの実際の工数の比率とかを考えると、
案外つまづくのが、パネルデータをパネルデータとして分析するためのデータの整形・変換の工程である。

そこで、備忘として、縦断データ分析のさいの手順を記録しとく次第。
まあ、そんなに難しい内容はないんだけど。

縦断データを前処理 in R

前提として、提供される元データは、wide型(1ケース=1個人)であるとする。
基本的にデータを二次利用する場合は、この形で提供されるのが多いからだ。
また、各段階の処理をラクにするためにHadley神が与えたもうたtidyr,dplyrの両パッケージを入れておくこと。

変数名の命名規則

通常縦断データを分析するときには、時変(time-dependent)変数と時不変(time-constant)変数を作成・利用することになる。

時不変のほうは好きに変数名をつければよいが、時変変数に関してはどの変数に関しても統一の規則で、対応する時点を指定する。
具体的には、「変数名_tn]という形がおすすめ(たとえば各時点の賃金だったらwage_t1,wage_t2,,,wage_tKといった感じ)である。

別にtである必然性はなく第何「波」を重視してwage_w1でもいいし、「年」単位だったらwage_y1とかでもいいが、とにかく重要なのは、すべての時変変数に共通した「時点を表す接尾辞」をつけることである。

おろそかにしがちだが、適当にやってると後々泣きをみるのでしっかりやっておく。

tidyr::pivot_longer()を用いたWide形式からLong形式への変換

細かい仕様は上であげた過去記事や下のURLを参照してほしいが、tidyrパッケージの神機能pivotを使うことで、この変換がアホほど簡単にできてしまう。

上記のような時変変数の命名規則を遵守していたと仮定すると、以下のような簡略なコードでの変換が可能

#「~_t[n]で時変変数の名前が定義されている場合」
df_long <- as.data.frame( tidyr::pivot_longer(
df_wide ,
cols=matches("_t.+$") , 
names_to = c(".value", "time") , 
names_pattern= "(.*)_t(.*)")
)

あまりにも簡単すぎて感涙にむせぶ。
ちなみにcolsでは正規表現を利用している。$は最後尾のアンカー、.+は任意の文字が1文字以上の意味である。

時変変数に共通の処理はどうすべきか問題

いちいち書くことでもないかもしれないことだけど一応。
時変変数に対して何か共通の処理をする(例:対数をとる、時変変数間で加減乗除をして新変数を作るetc.)ときは、Long型にしてしまってからdplyr::mutateなどを使って、演算処理を行うほうが各段に工数削減できるので、そうすべきである。

個人レベルでの統計量(平均,分散etc.)に基づく変数を作成するときはgroup_by⇒mutate⇒ungroupのコンボを使う


たとえば、ハイブリッドモデル(参照:太郎丸先生の解説)を適用するときなど、個人内平均を表す新たな変数をつくりたいことがある。

こういう時は、ロング型にしたデータフレームに対し、group_by()を使って個人IDを単位としてgroup化し、
その後にmutate()を使って新変数を作成したあと、ungroup()で元の形式に戻す*1

#変数yの平均を新変数y_aveとして追加する例

## IDによるグループ化
grp_byID  <-  dplyr::group_by( long_df, ID )
## mutateで新変数作成
grp_byID_add <- dplyr::mutate(  grp_byID ,
y_ave = mean( y , na.rm=T)
) 
## 元の形式にもどす
long_df_v2  <- as.data.frame( dplyr::ungroup( grp_by_ID_add ))

これはパネルデータに限らず階層的構造をもつデータには共通に使えるワザなので、覚えて損はない。

Conclusion

ヒトは忘れる動物だから、知識は何度も使って身に染み込ませるしかないわね。

www.youtube.com

Enjoy!!

*1:ungroupの返り値はtibble型なので、データフレームに戻したい時は型キャストする