dcast 中的 value.var 可以是一个列表还是有多个值变量?

Posted

技术标签:

【中文标题】dcast 中的 value.var 可以是一个列表还是有多个值变量?【英文标题】:can the value.var in dcast be a list or have multiple value variables? 【发布时间】:2014-05-28 04:34:41 【问题描述】:

dcast.data.table 的帮助文件中,有一条说明已经实现了一项新功能:“dcast.data.table 允许 value.var 列属于列表类型”

我认为这意味着一个列表中可以有多个值变量,即采用以下格式:

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

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

是否有这样的功能,如果没有,还有其他单线替代方案吗?

编辑:回复下面的 cmets

在某些情况下,您希望将多个变量视为value.var。例如,假设 x2 包含 3 个不同的周,并且您有 2 个值变量,例如盐和糖的消耗量,并且您希望将这些变量转换为不同的周。当然,您可以将 2 个值变量“融合”到一列中,但是当您可以像 reshape 那样在一个函数中完成时,为什么还要使用两个函数呢?

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

所以我的意思是,我不明白为什么这些函数不允许在value.vartime.var 中灵活地包含多个变量,就像我们允许id.var 中的多个变量一样。

【问题讨论】:

您误解了文档。 data.table 列可以是 list 类型,这样的列现在可以是 value.var 列。 @Arun,我不完全确定这将是一个巨大的改进(或者我可能没有正确理解这个问题)。有多个value.vars 的事实不是意味着数据没有完全“融化”吗?亚历克斯:您能否更新您的问题以跳出假设领域,并举例说明您可能想对这些多个value.vars 做什么?也许你在想我在this answer 所做的事情? @Arun 我已经详细说明了这篇文章的目的和我的询问。 相关问题:***.com/questions/27247078/… 相关:Convert data from long format to wide format with multiple measure columns 【参考方案1】:

更新

显然,the fix was much easier...


从技术上讲,您“显然没有这样的功能”的说法并不完全正确。 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 方法的一个可能优势是能够在同一步骤中进行聚合和重塑。

【讨论】:

感谢您抽出宝贵的时间阅读此内容。我不知道重铸似乎会融化+铸造。我想补充一点,reshape 包(但不是 reshape2)中的 recast 是完整的,并且与您的 recast2 功能相同。 @AlexR,请在帖子顶部查看我的更新。显然,所需要的只是将recast 代码中的cast 更改为dcast【参考方案2】:

从 data.table v1.9.6 开始,我们可以同时转换多个value.var 列(也可以在fun.aggregate 中使用多个聚合函数)。请参阅?dcast 和Efficient 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

【讨论】:

【参考方案3】:

使用来自A5C1D2H2I1M1N2O1R2T1's answer 的样本数据框mydf

使用 tidyr 编辑 2016 年 12 月

Reshape2 已替换为 tidyr package。

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 会自动猜测它。

【讨论】:

2016 年 12 月的更新在我看来是目前最灵活的方法。 +1 现在gatherspread 已被pivot_widerpivot_longer 在tidyr 中取代。

以上是关于dcast 中的 value.var 可以是一个列表还是有多个值变量?的主要内容,如果未能解决你的问题,请参考以下文章

Spark是不是支持melt和dcast [重复]

在 Hadoop 或 MySQL 中重塑 dcast 表

R语言学习笔记(十七):data.table包中melt与dcast函数的使用

根据data.table中列的最大值自定义dcast内部的聚合函数?

dcast 警告:“缺少聚合函数:默认为长度”

在 R 中,自定义由 dcast.data.table 创建的列的名称