このデータセットからダミー変数を作成したいと思います。
DF<-structure(list(A = c(1, 2, 3, 4, 5), B = c("1,3,2", "2,1,3,6",
"3,2,5,1,7", "3,7,4,2,6,5", "4,10,7,3,5,6")), .Names = c("A", "B"),
row.names = c(NA, 5L), class = "data.frame")
> DF
A B
1 1 1,3,2
2 2 2,1,3,6
3 3 3,2,5,1,7
4 4 3,7,4,2,6,5
5 5 4,10,7,3,5,6
望ましい出力は次のようになります。
A 1 2 3 4 5 6 7 8 9 10
1 1 1 1 0 0 0 0 0 0 0
2 1 1 1 0 0 1 0 0 0 0
3 1 1 1 0 1 0 1 0 0 0
4 0 1 1 1 1 1 1 0 0 0
5 0 0 1 1 1 1 1 0 0 1
strsplit
このようなことを効率的に行う方法はありますか?または を使用できますifelse
。元のデータセットは非常に大きく、行数が多く (>10k)、列 B に値 (>15k) があります。dummy
パッケージの関数dummies
は期待どおりに動作しません。
同様のケースも見つかりました:1つの列を複数の列に分割するしかし、私のケースでは、上記のリンクからの回答は非常に遅くなります (Dell i7-2630QM、8Gb、Win7 64 ビット、R 2.15.3 64 ビットで最大 15 分)。
ご回答をよろしくお願いいたします。
ベストアンサー1
アップデート
ここで言及した関数は、現在 CRAN で入手可能な「splitstackshape」というパッケージに移動されています。CRAN のバージョンは、この元のバージョンよりもかなり高速です。速度は、for
この回答の最後に記載されている直接ループ ソリューションで得られる速度とほぼ同じになるはずです。詳細なベンチマークについては、@Ricardo の回答を参照してください。
インストールして使用し、concat.split.expanded
目的の結果を得ます。
library(splitstackshape)
concat.split.expanded(DF, "B", fill = 0, drop = TRUE)
# A B_01 B_02 B_03 B_04 B_05 B_06 B_07 B_08 B_09 B_10
# 1 1 1 1 1 0 0 0 0 0 0 0
# 2 2 1 1 1 0 0 1 0 0 0 0
# 3 3 1 1 1 0 1 0 1 0 0 0
# 4 4 0 1 1 1 1 1 1 0 0 0
# 5 5 0 0 1 1 1 1 1 0 0 1
元の投稿
以前、私はこの種の分割だけでなく、他の分割も行う関数を書きました。 という関数はconcat.split()
、ここ。
サンプルデータの使用法は次のようになります。
## Keeping the original column
concat.split(DF, "B", structure="expanded")
# A B B_1 B_2 B_3 B_4 B_5 B_6 B_7 B_8 B_9 B_10
# 1 1 1,3,2 1 1 1 NA NA NA NA NA NA NA
# 2 2 2,1,3,6 1 1 1 NA NA 1 NA NA NA NA
# 3 3 3,2,5,1,7 1 1 1 NA 1 NA 1 NA NA NA
# 4 4 3,7,4,2,6,5 NA 1 1 1 1 1 1 NA NA NA
# 5 5 4,10,7,3,5,6 NA NA 1 1 1 1 1 NA NA 1
## Dropping the original column
concat.split(DF, "B", structure="expanded", drop.col=TRUE)
# A B_1 B_2 B_3 B_4 B_5 B_6 B_7 B_8 B_9 B_10
# 1 1 1 1 1 NA NA NA NA NA NA NA
# 2 2 1 1 1 NA NA 1 NA NA NA NA
# 3 3 1 1 1 NA 1 NA 1 NA NA NA
# 4 4 NA 1 1 1 1 1 1 NA NA NA
# 5 5 NA NA 1 1 1 1 1 NA NA 1
NA を 0 に再コーディングするには手動で行う必要があります。おそらく関数を更新してオプションを追加し、同時にこれらのより高速なソリューションの 1 つを実装するでしょう :)
temp <- concat.split(DF, "B", structure="expanded", drop.col=TRUE)
temp[is.na(temp)] <- 0
temp
# A B_1 B_2 B_3 B_4 B_5 B_6 B_7 B_8 B_9 B_10
# 1 1 1 1 1 0 0 0 0 0 0 0
# 2 2 1 1 1 0 0 1 0 0 0 0
# 3 3 1 1 1 0 1 0 1 0 0 0
# 4 4 0 1 1 1 1 1 1 0 0 0
# 5 5 0 0 1 1 1 1 1 0 0 1
アップデート
関数のオーバーヘッドのほとんどは、からconcat.split
への変換や列名の変更などによるものと思われます。分割を行うために実際に使用されるコードは、matrix
data.frame
ガスッ for
ループしますが、テストしてみると、パフォーマンスがかなり良いことがわかります。
b = strsplit(DF$B, ",")
ncol = max(as.numeric(unlist(b)))
temp = lapply(b, as.numeric)
## Set up an empty matrix
m = matrix(0, nrow = nrow(DF), ncol = ncol)
## Fill it in
for (i in 1:nrow(DF)) {
m[i, temp[[i]]] = 1
}
## View your result
m