使用data.table包重塑数据

3

我几天前问了同样的问题(点击这里),但没有提到使用 data.table 得出结果会更好。

"聚合解决方案"可以正常工作,但速度较慢!我正在寻找一种更快的解决方法。

我想要重塑以下数据框:

df <- data.frame(x=c("p1","p1","p2"),y=c("a","b","a"),z=c(14,14,16))
df
   x y  z
1 p1 a 14
2 p1 b 14
3 p2 a 16

以便它看起来像这个样子:

df2 <- data.frame(x=c("p1","p2"),a=c(1,1),b=c(1,0),z=c(14,16))
   x a b  z
1 p1 1 1 14
2 p2 1 0 16

在数据框 df 中,变量 y 的元素应该被拆分成新的变量,并且每个变量都应该进行虚拟编码。所有其他变量(在这种情况下只有 z)对于每个人(p1、p2等)都是相同的。唯一一个变量,在其中特定的人 p 有不同值的是变量 y。
我希望这样做的原因是需要通过变量 x 将此数据集与其他数据集合并。事实上,它需要每个人(p1、p2等)一行。

我本应该考虑到“自包含方面”,但当我发布这个问题时,我没有考虑到。因为eddi已经发布了一种方法,所以我想我会将其保留。不过,感谢您的评论。 - beginneR
1个回答

5

目前在data.table中转换成宽格式有点棘手,但我认为这个方法是可行的:

library(data.table)
dt = data.table(x=c("p1","p1","p2"),y=c("a","b","a"),z=c(14,14,16))

setkey(dt, x, y)
dt[CJ(unique(x), unique(y)), list(.N, z)][,
   setNames(as.list(c(N, z[!is.na(z)][1])), c(y, 'z')), by = x]
#    x a b  z
#1: p1 1 1 14
#2: p2 1 0 16

CJ部分通过所有唯一xy的组合连接,然后在该连接中使用隐藏的by-without-by计算计数,通过.N。得到这些数据之后,只需将它们水平放置到每个x上,再加上任何非NA值的z(我选择第一个),并使用as.list完成。最后,setNames正确设置列名。


1
@beginneR 解释已添加 - eddi
谢谢,这太棒了!但现在情况变得更加复杂了。如果还有另一个变量,比如y,例如z,其值也可能不同。是否有可能调整代码以适应这种情况?thelatemail使用Aggregate编辑了我在此处链接的问题的第一个答案,用于超过两列的情况。如果您的data.table解决方案也可以这样做,那就太完美了。请参阅我对“他”的答案在链接问题中的评论。(PS:抱歉链接到另一个问题) - beginneR
1
从我所看到的,另一个问题中的两个变量情况只是上述算法的两次独立运行 - 首先将键设置为“x”和“y”,然后将其设置为“x”和“z”,对于每种情况都执行上述操作,然后使用“cbind”合并结果。 - eddi
我得到了以下错误信息:"对于每个组,j 的列数不相同"。但是这个错误与 cbind() 无关。当我尝试你的答案中的代码仅针对单个变量时,出现了问题。还没有弄清楚为什么这在我的数据上不起作用。你有什么想法吗? - beginneR
@beginneR,这个错误意味着你的 by 参数在不同的值产生不同大小的 j-expressions 结果 - 尝试确定两个冲突的 by 值,然后你可能能够找出如何修复它;一种确定方法是在你的 j-expression 中添加一个 print 语句,这样你就能看到它在哪里中断了。 - eddi
我想我弄清楚了。我的行中所有值都相等,所以在您的第一次操作之后,我不仅有零和1值,还有“2”和“3”。我认为这就是问题所在。 - beginneR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接