我有一个数据框,其中包含一个分类变量,它保存了不定长的字符串列表(这一点很重要,否则这个问题就会成为这个问题或这个问题的重复),例如:
df <- data.frame(x = 1:5)
df$y <- list("A", c("A", "B"), "C", c("B", "D", "C"), "E")
df
x y 1 1 A 2 2 A, B 3 3 C 4 4 B, D, C 5 5 E
所需的形式是对于在 df$y
中出现的任何唯一字符串,创建一个虚拟变量,即:
data.frame(x = 1:5, A = c(1,1,0,0,0), B = c(0,1,0,1,0), C = c(0,0,1,1,0), D = c(0,0,0,1,0), E = c(0,0,0,0,1))
x A B C D E 1 1 1 0 0 0 0 2 2 1 1 0 0 0 3 3 0 0 1 0 0 4 4 0 1 1 1 0 5 5 0 0 0 0 1
这种天真的方法可行:
> uniqueStrings <- unique(unlist(df$y))
> n <- ncol(df)
> for (i in 1:length(uniqueStrings)) {
+ df[, n + i] <- sapply(df$y, function(x) ifelse(uniqueStrings[i] %in% x, 1, 0))
+ colnames(df)[n + i] <- uniqueStrings[i]
+ }
然而,对于大数据框来说,它非常丑陋、懒惰和缓慢。
有什么建议吗?tidyverse
里的一些花哨东西?
更新:下面我列出了3种不同的方法。我在我的笔记本电脑上(Windows 7,32GB RAM)使用真实数据集测试了它们,该数据集包含100万行,每行包含一个长度为1到4的字符串列表(共约350个唯一字符串值),总大小为200MB。因此预期结果是一个1M x 350的数据框。tidyverse
(@Sotos) 和 base
(@joel.wilson) 方法运行时间太长,导致我不得不重新启动R。然而,qdapTools
(@akrun) 的方法表现非常出色:
> system.time(res1 <- mtabulate(varsLists))
user system elapsed
47.05 10.27 116.82
所以这就是我将采纳的方法。
data.frame(x = df$x, t(sapply(df$y, function(l){table(factor(l, levels = LETTERS[1:5]))})))
- alistairelevels = unique(unlist(df$y))
而不是LETTERS[1:5]
? - Sotos