我有一个包含三列的data.frame:
To Amount Type
Smith $1 A
John $5 B
Jeff $8 A
Smith $4 C
... ... ...
我需要将其转换为数据框,表明每个人收到的每种类型的金额。
Name TotalAmtOfTypeA TotalAmtOfTypeB TotalAmtOfTypeC ...
Smith $1 $0 $4
John $0 $5 $0
Jeff $8 $0 $0
...
原始data.frame长度超过300万行,因此解决方案越有效或并行化越好。解决方案是否涉及aggregate
?或者我应该调查plyr
?任何指导都将非常感谢!
答案 0 :(得分:2)
以下是两个选项:
library(tidyr)
spread(df, Type, Amount)
# To ordered.A ordered.B ordered.C
#1 Jeff $8 <NA> <NA>
#2 John <NA> $5 <NA>
#3 Smith $1 <NA> $4
或
library(reshape2)
dcast(df, To ~ Type, value.var = "Amount")
# To A B C
#1 Jeff $8 <NA> <NA>
#2 John <NA> $5 <NA>
#3 Smith $1 <NA> $4
或者,如果您将列类从因子更改为字符,则可以执行以下操作:
df$Amount <- as.character(df$Amount)
dcast(df, To ~ Type, value.var = "Amount", fill = "$0")
# To A B C
#1 Jeff $8 $0 $0
#2 John $0 $5 $0
#3 Smith $1 $0 $4
同样
spread(df, Type, Amount, fill = "$0")
# To A B C
#1 Jeff $8 $0 $0
#2 John $0 $5 $0
#3 Smith $1 $0 $4
注意:如果您将“金额”列保留为因子并尝试使用fill = "$0"
,则会收到如下错误消息:
警告消息:在
[<-.factor
(*tmp*
,is.na(已订购),值= 0)中: 无效因子水平,NA生成
如果您想在Amount列中删除那些“$”,以便您可以实际使用这些数字进行进一步处理,那么您可以在dplyr / tidyr链中执行此操作:
library(dplyr)
library(tidyr)
df %>%
mutate(Amount = as.numeric(gsub("\\$", "", Amount))) %>%
spread(Type, Amount, fill = 0)
# To A B C
#1 Jeff 8 0 0
#2 John 0 5 0
#3 Smith 1 0 4
答案 1 :(得分:2)
这是一个data.table
解决方案应该可以很快地运行:
数据
library(data.table)
n <- 1e6
dat <- data.table(Name = LETTERS[sample(26, n, TRUE)],
Amount = rpois(n, 100),
Type = letters[sample(26, n, TRUE)])
<强>代码强>
setkey(dat, Name, Type)
dat.agg <- dat[, .(Sum = sum(Amount)), by =.(Name, Type)]
dat.agg[, as.list(setattr(Sum, 'names', Type)), by = .(Name)]
<强>解释强>
第一个[.data.table
汇总data.table
以获得所有Name/Type
组合的总和。第二个[.data.table
以您希望的方式格式化data.table
。 setattr
用于获得良好的输出(根据Type
的级别对列进行调整。