我的data.frame
具有相同长度的组(id
)
id | amount
--------------
A | 10
A | 54
A | 23
B | 34
B | 76
B | 12
我想将按组 id
转换为:
id |
----------------------
A | 10 | 54 | 23
B | 34 | 76 | 12
最有效的方法是什么?
我之前使用的是reshape
和dcast
,但确实非常慢! (我有很多数据,并希望加快这个瓶颈)
有更好的策略吗?使用data.table
或矩阵?任何帮助将不胜感激!
# Little data.frame
df <- data.frame(id=c(2,2,2,5,5,5), amount=as.integer(c(10,54,23,34,76,12)))
# Not so little data.frame
set.seed(10)
df <- data.frame(id = rep(sample(1:10000, 10000, replace=F),100), amount=as.integer(floor(runif(1000000, -100000,100000))))
# Create time variable
df$time <- ave(as.numeric(df$id), df$id, FUN = seq_along)
# The base R reshape strategy
system.time(df.reshape <-reshape(df, direction = "wide", idvar="id", timevar="time"))
user system elapsed
6.36 0.31 6.69
# The reshape2 dcast strategy
require(reshape2)
a <- system.time(mm <- melt(df,id.vars=c('id','time'),measure.vars=c('amount')))
b <- system.time(df.dcast <- dcast(mm,id~variable+time,fun.aggregate=mean))
a+b
user system elapsed
14.44 0.00 14.45
更新
使用每个组长度相等的事实,您可以使用matrix
- 函数。
df.matrix <- data.frame(id=unique(df$id), matrix(df$amount, nrow=(length(unique(df$id))), byrow=T))
user system elapsed
0.03 0.00 0.03
注意:此方法假定data.frame由id
预先排序。
答案 0 :(得分:2)
矩阵方法将使用:
system.time({ df.reshape <-matrix(df$amount, nrow=10000, byrow=TRUE);
rownames(df.reshape)<- df$id[1:10000]
} )
user system elapsed
0.010 0.006 0.016
答案 1 :(得分:1)
试试这个:
dFrame<-data.frame(id = c(rep("A",3),rep("B",3)),amount = c(10,54,23,34,76,12))
newFrame<-cbind(data.frame(id = unique(dFrame$id)),matrix(as.numeric(unlist(tapply(dFrame$amount,dFrame$id,identity))),nrow=length(unique(dFrame$id)),byrow=T))
包围可能会关闭,我试着小心 - 我目前没有可用的R口译员
基于您提供的df示例代码的基准测试结果:
replications elapsed relative user.self sys.self user.child sys.child
1 1 4.193 1 4.056 0.064 0 0
答案 2 :(得分:1)
这不是reshape
的问题。来自基地的aggregate
应该能够处理这个问题。
df.out <- aggregate(amount ~ id, data=df, c)
# running on the small data
# id amount.1 amount.2 amount.3
# 1 2 10 54 23
# 2 5 34 76 12
这不是你想要的吗?
好吧,似乎DWin
解决方案的改编版本是最快的。但是,结果将按id
排序。如果你不想那样,那么Aditya
似乎就是那个用的。
以下是功能和基准测试结果:
使用aggregate
:
AGG <- function() {
df.agg <- aggregate(amount ~ id, data=df, c)
}
使用Aditya
的
SEC <- function() {
df.sec <- cbind(data.frame(id = unique(df$id)),
matrix(as.numeric(unlist(tapply(df$amount, df$id, identity))),
nrow = length(unique(df$id)), byrow = T))
}
使用Dwin
的修改版本:
DWIN_M <- function() {
df1 <- df[with(df, order(id)), ]
idx <- df$id[!duplicated(df$id)]
df.dwin <- cbind(data.frame(id=idx),
as.data.frame(matrix(df1$amount,
nrow=length(idx), byrow=TRUE)))
}
基准:
require(rbenchmark)
benchmark(AGG(), SEC(), DWIN_M(), replications=3, order="elapsed")
# test replications elapsed relative user.self sys.self user.child sys.child
# 3 DWIN_M() 3 4.175 1.000 4.148 0.000 0 0
# 2 SEC() 3 17.568 4.208 17.449 0.016 0 0
# 1 AGG() 3 24.529 5.875 24.306 0.044 0 0
如果我犯了任何错误,请告诉我。