一次性重塑多个值

20

我有一个长数据集,我想将其变宽,并且我很好奇是否有一种方法可以使用R中的reshape2或tidyr包在一步中完成所有操作。

数据框架df的样子是这样的:

id  type    transactions    amount
20  income       20          100
20  expense      25          95
30  income       50          300
30  expense      45          250

我想要达到这个目标:

id  income_transactions expense_transactions    income_amount   expense_amount
20       20                           25                 100             95
30       50                           45                 300             250

我知道可以通过reshape2来实现部分功能,例如:

dcast(df, id ~  type, value.var="transactions")

但是否有一种方法可以在一个步骤中重新塑造整个df,同时解决“transactions”和“amount”变量?并且最好使用新的更合适的列名?

2个回答

30
在 "reshape2" 中,您可以使用 recast 函数(尽管根据我的经验,这并不是一个广为人知的函数)。
library(reshape2)
recast(mydf, id ~ variable + type, id.var = c("id", "type"))
#   id transactions_expense transactions_income amount_expense amount_income
# 1 20                   25                  20             95           100
# 2 30                   45                  50            250           300

你也可以使用基本的R函数 reshape

reshape(mydf, direction = "wide", idvar = "id", timevar = "type")
#   id transactions.income amount.income transactions.expense amount.expense
# 1 20                  20           100                   25             95
# 3 30                  50           300                   45            250

或者,您可以像这样使用 data.table 进行meltdcast

library(data.table)
library(reshape2)
dcast.data.table(melt(as.data.table(mydf), id.vars = c("id", "type")), 
                 id ~ variable + type, value.var = "value")
#    id transactions_expense transactions_income amount_expense amount_income
# 1: 20                   25                  20             95           100
# 2: 30                   45                  50            250           300

在"data.table"的后续版本(1.9.8)中,您将能够直接执行此操作。如果我理解正确,@Arun试图实现的是在不必先melt数据的情况下进行重塑,这与目前使用recast发生的情况相同,它本质上是melt+dcast操作序列的包装器。

为了全面起见,这里是 tidyr 的方法:

library(dplyr)
library(tidyr)
mydf %>% 
  gather(var, val, transactions:amount) %>% 
  unite(var2, type, var) %>% 
  spread(var2, val)
#   id expense_amount expense_transactions income_amount income_transactions
# 1 20             95                   25           100                  20
# 2 30            250                   45           300                  50

这是一个很好的答案(启迪+好答案徽章在路上...),但不确定为什么我们需要使用tidyrdplyrdata.tablereshape等等这些东西,当使用基本的R语言就可以如此简单地完成。 - David Arenburg
@DavidArenburg,真的是大规模的速度。我是“reshape”的老粉丝,但如果有人处理远程大数据,它不会是我的首选建议。 - A5C1D2H2I1M1N2O1R2T1
现在我正在研究reshape的源代码,看起来它全部都是无尽的for/apply循环。可惜它不是用C/C++编写的,因为所有基本的R函数都应该是这样的。 - David Arenburg
6
reshape()很简单?”对此我只能说“哈哈哈哈”。 - hadley
3
@hadley,我不能代表David发言,但我认为他的评论并不是说reshape()很简单,而是意味着此处的reshape()方法实际上相当直截了当。 - A5C1D2H2I1M1N2O1R2T1
2
在这种情况下,“mess”与tidyr、dplyr、data.table、reshape2等工具打交道的整个意义在于,它们更好地推广到新问题,而reshape()则不行。 - hadley

6

从data.table v1.9.6+版本开始,我们可以同时转换多个value.var列(也可以在fun.aggregate中使用多个聚合函数)。请参见?dcast获取更多信息以及示例部分。

require(data.table) # v1.9.6+
dcast(dt, id ~ type, value.var=names(dt)[3:4])
#    id transactions_expense transactions_income amount_expense amount_income
# 1: 20                   25                  20             95           100
# 2: 30                   45                  50            250           300

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