これも同じことを100回調べるので備忘用シリーズ
なんかStataとかよりwide↔longの相互変換のやりかたがわかりにくいのよな。
Introduction
基本的にはstats::reshape()を使う。
tidyrパッケージを使う方法もあるけど、とりあえずベーシックなやり方をまとめとく。
参考URL
とりあえずトレーニング用データとしてmlogitパッケージのTrainデータを読み込んどく
library(mlogit) data(Train) head(Train) id choiceid choice price_A time_A change_A comfort_A price_B time_B change_B comfort_B 1 1 1 A 2400 150 0 1 4000 150 0 1 2 1 2 A 2400 150 0 1 3200 130 0 1
Wide to Long
関数作った
いろいろ調べた...結果reshapeの引数指定がめんどくさいので、ラッパー関数を作った
##---Wide to Longの変換用関数---## ##[引数定義]## #[1]dta , 変換対象のデータフレーム #[2]vary_vname ,characterのvector。longにしたい対象の変数のindexを除いた部分(Ex: wage1, wage2,,,って感じだったら"wage") #[3]vary_idx , longにしたい対象の変数のindexをあらわすvector(Ex: wage1, wage2,,,wage10だったら1:10) #[4]sep , vary_vnameとvary_idxの間に区切り文字があればそれを指定 #[5]lev_vname , vary_idxを水準としてもつ新変数の名前(charcter) wideToLong <- function(dta ,vary_vname, vary_idx ,sep=NULL,lev_vname="LEVEL"){ if(is.null(sep)){ sep <- ""} vary_prm <- lapply(vary_vname , function(vname){ return( paste(vname ,vary_idx, sep=sep)) })#lapply id_vnames <- setdiff( colnames(dta), unlist( vary_prm)) long_df <- reshape(data = dta ,direction="long",idvar = id_vnames, varying =vary_prm, v.names = vary_vname ,sep=sep,times=vary_idx,timevar=lev_vname) rownames(long_df) <- c() return(long_df ) } #function
実行
dta_w <- wideToLong( Train, c("price","time","change","comfort"),c("A","B"),sep="_",lev_vname="AorB") head(dta_w) id choiceid choice AorB price time change comfort 1 1 1 A A 2400 150 0 1 2 1 2 A A 2400 150 0 1 3 1 3 A A 2400 115 0 1
悪くないね。
tidyrの神機能"pivot"
(こっから追記@19/10/21)
自分の検索スキルを恨むべきなのだが、上のような行儀のよろしくない関数をかく必要はなくて
tidyrのver1.0.0で追加されたpivotingを使うことで、より高速かつ汎用的なwide to longの整形をすることができる。
参考URL
- 雑訳vignette: Pivoting (tidyr 1.0.0) | Atusy's blog
- tidyr 1.0.0の新機能 pivot_*() / tidyr-pivot - Speaker Deck
先ほどと同じ処理を行う
tra_L <- tidyr::pivot_longer( Train , price_A:comfort_B , names_to = c(".value","Type"), names_pattern="(.*)_(.*)" ) head(as.data.frame(tra_L)) id choiceid choice Type price time change comfort 1 1 1 A A 2400 150 0 1 2 1 1 A B 4000 150 0 1 3 1 2 A A 2400 150 0 1 4 1 2 A B 3200 130 0 1 5 1 3 A A 2400 115 0 1 6 1 3 A B 4000 115 0 0
あらシンプル!
第三引数のnames_toにおける".value"が肝で、これにより、新しく作る変数の名前として元の変数名(の部分文字列)を使うことができる。
たとえば身長と体重のT期間にわたるデータがheight1, weight1,height2, weight2,,,, height_T, weight_Tという変数で入っている場合はc(".value","time")といった形で指定すると、long型になった整形先データにはheight, weight , timeという変数ができる。
第四引数のname_patternは正規表現を用いて、新しい変数に相当する箇所を指定する。
パネルデータなどの変換などの用途に対してもとても強力である。
くわしくは参考URL1の「一行に複数の観測値がある場合」の箇所を参考にしてほしい。
これ本当に汎用性が高い