在dcast中,value.var可以是一个列表或具有多个值变量吗?

39

dcast.data.table 的帮助文件中,有一个说明注释称已经实现了一项新功能:“dcast.data.table 允许 value.var 列为 list 类型”。

我理解这意味着可以将多个值变量包含在一个列表中,即以以下格式:

dcast.data.table(dt, x1~x2, value.var=list('var1','var2','var3'))

但是我们遇到了一个错误:'value.var' must be a character vector of length 1.

是否存在这样的功能,如果不存在,有什么其他一行代码的替代方案?

编辑:回复下面的评论

有些情况下,您可能有多个变量要作为value.var处理。例如,假设x2由3个不同的周组成,并且您有2个值变量(如盐和糖的消耗),您想将这些变量在不同的周之间转换。当然,您可以将2个值变量“融合”成单个列,但为什么要使用两个函数来完成某件事,而不是像reshape一样在一个函数中完成呢?

(注:我还注意到reshape不能像dcast一样将多个变量视为时间变量。)

因此,我的观点是,我不明白为什么这些函数不允许在value.vartime.var中包括多个变量,就像我们允许在id.var中使用多个变量一样。


3
你误解了文档。data.table列可以是列表类型,这样的列现在可以作为value.var列。 - Roland
2
@Arun,我不太确定这会是一个很大的改进(或者说我可能没有正确理解问题)。有多个'value.var'的事实是否意味着数据并非完全“molten”?Alex:你能否更新你的问题,走出假设的范畴,给出一个你可能想要用这些多个'value.var'做什么的例子?也许你正在考虑像我在这个答案中所做的那样? - A5C1D2H2I1M1N2O1R2T1
@Arun,我已经详细阐述了这篇文章的目的和我的问题。 - AlexR
相关问题:https://dev59.com/1l4d5IYBdhLWcg3wDe31 - landroni
3个回答

49

从data.table的v1.9.6版本开始,我们可以同时转换多个value.var列(并且在fun.aggregate中使用多个聚合函数)。请参见?dcastEfficient reshaping using data.tables文档获取更多信息。

以下是我们如何使用dcast

dcast(setDT(mydf), x1 ~ x2, value.var=c("salt", "sugar"))
#    x1 salt_1 salt_2 salt_3 sugar_1 sugar_2 sugar_3
# 1:  1      3      4      6       1       2       2
# 2:  2     10      3      9       5       3       6
# 3:  3     10      7      7       4       6       7

12

更新

显然,修复起来要容易得多...


从技术上讲,你说“显然没有这样的功能”并不完全正确。在recast函数中有这样一个功能(隐藏了熔融和铸造过程),但似乎Hadley忘记完成该函数或者其他什么原因导致该函数返回操作相关的list

这是一个最小的例子...

一些示例数据:

set.seed(1)
mydf <- data.frame(x1 = rep(1:3, each = 3),
                   x2 = rep(1:3, 3),
                   salt = sample(10, 9, TRUE),
                   sugar = sample(7, 9, TRUE))

mydf
#   x1 x2 salt sugar
# 1  1  1    3     1
# 2  1  2    4     2
# 3  1  3    6     2
# 4  2  1   10     5
# 5  2  2    3     3
# 6  2  3    9     6
# 7  3  1   10     4
# 8  3  2    7     6
# 9  3  3    7     7

您似乎想要实现的效果是:

reshape(mydf, idvar='x1', timevar='x2', direction='wide')
#   x1 salt.1 sugar.1 salt.2 sugar.2 salt.3 sugar.3
# 1  1      3       1      4       2      6       2
# 4  2     10       5      3       3      9       6
# 7  3     10       4      7       6      7       7

recast 的实际运用。(请注意,这些值在我们所期望的尺寸和维度上都是符合预期的。)

library(reshape2)
out <- recast(mydf, x1 ~ x2 + variable, measure.var = c("salt", "sugar"))
### recast(mydf, x1 ~ x2 + variable, id.var = c("x1", "x2"))
out
# $data
#      [,1] [,2] [,3] [,4] [,5] [,6]
# [1,]    3    1    4    2    6    2
# [2,]   10    5    3    3    9    6
# [3,]   10    4    7    6    7    7
# 
# $labels
# $labels[[1]]
#   x1
# 1  1
# 2  2
# 3  3
# 
# $labels[[2]]
#   x2 variable
# 1  1     salt
# 2  1    sugar
# 3  2     salt
# 4  2    sugar
# 5  3     salt
# 6  3    sugar

我不确定这是一个未完成的函数,还是另一个函数的帮助程序。

所有信息都在那里,可以重新组合数据,很容易编写这样的函数:

recast2 <- function(...) {
  inList <- recast(...)
  setNames(cbind(inList[[2]][[1]], inList[[1]]),
           c(names(inList[[2]][[1]]), 
             do.call(paste, c(rev(inList[[2]][[2]]), sep = "_"))))
}
recast2(mydf, x1 ~ x2 + variable, measure.var = c("salt", "sugar"))
#   x1 salt_1 sugar_1 salt_2 sugar_2 salt_3 sugar_3
# 1  1      3       1      4       2      6       2
# 2  2     10       5      3       3      9       6
# 3  3     10       4      7       6      7       7

再次提到,recast2方法的一个潜在优势是能够同时进行聚合和重塑。


感谢您抽出时间阅读这篇文章。我之前不知道有recast,它似乎可以实现melt+cast的功能。我想补充一下,在reshape包中(但不是reshape2),recast已经完整实现了,并且可以达到与您的recast2函数相同的效果。 - AlexR
1
@AlexR,看到我在帖子顶部的更新了吗?显然,只需要将cast改为dcast就可以了,这是在recast代码中的修改。 - A5C1D2H2I1M1N2O1R2T1

11

使用A5C1D2H2I1M1N2O1R2T1的回答中的样本数据框mydf

使用tidyr编辑2016年12月

tidyr包已经取代了Reshape2。

library(tidyr)
mydf  %>% 
    gather(variable, value, -x1, -x2)  %>% 
    unite(x2_variable, x2, variable)  %>% 
    spread(x2_variable, value)

#   x1 1_salt 1_sugar 2_salt 2_sugar 3_salt 3_sugar
# 1  1      3       1      4       2      6       2
# 2  2     10       5      3       3      9       6
# 3  3     10       4      7       6      7       7

基于reshape2的原始答案

@AlexR在他的问题中补充道:

当然,你可以将2个值变量“融合”成一列,

对于那些寻找基于reshape2的答案的人,以下是如何融合数据,然后基于“变量”使用dcast的方法。

dt2 <- melt(mydf, id = c("x1", "x2")) 

变量列现在将包含“var1”,“var2”,“var3”。您可以通过以下方式实现所需效果:
dt3 <- dcast(dt2, x1 ~ x2 + variable, value.var="value")
dt3
#   x1 1_salt 1_sugar 2_salt 2_sugar 3_salt 3_sugar
# 1  1      3       1      4       2      6       2
# 2  2     10       5      3       3      9       6
# 3  3     10       4      7       6      7       7

在这个函数调用中,value.var是可选的,因为dcast将自动猜测它。


1
2016年12月的更新是我认为现在最灵活的方法。+1 - Morgan Ball
1
现在,在 tidyr中,gatherspread已被pivot_widerpivot_longer取代。 - filups21

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