有一个很好的解释here描述了如何通过选择最大变量来消除数据框中的重复项。
我还可以看到如何使用最小变量来选择副本。
我现在的问题是如何显示所有重复项的平均值?
例如:
z <- data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,5,2))
# id var
# 1 2
# 1 4
# 2 1
# 2 3
# 3 5
# 4 2
我想要输出:
# id var
# 1 3 mean(2,4)
# 2 2 mean(1,3)
# 3 5
# 4 2
我目前的代码是:
averages<-do.call(rbind,lapply(split(z,z$id),function(chunk) mean(chunk$var)))
z<-z[order(z$id),]
z<-z[!duplicated(z$id),]
z$var<-averages
我的代码运行速度非常慢,并且比选择最大值的方法长大约10倍。如何优化此代码?
答案 0 :(得分:5)
使用data.table
library(data.table)
z <- data.frame(id=sample(letters, 6e5, replace = TRUE),var = rnorm(6e5))
fn1 <- function(z){
z$var <- ave(z$var, z$id, FUN=mean)
return(unique(z))
}
fn2 <- function(z) {
t(sapply(split(z,z$id), function(x) sapply(x,mean)))
}
fn3 <- function(z){
data.table(z)[,list(var = mean(var)), 'id']
}
library(rbenchmark)
benchmark(f1 <- fn1(z), f2 <- fn2(z), f3 <- fn3(z), replications = 2)
est replications elapsed relative user.self sys.self
1 f1 <- fn1(z) 2 3.619 8.455607 3.331 0.242
2 f2 <- fn2(z) 2 0.586 1.369159 0.365 0.220
3 f3 <- fn3(z) 2 0.428 1.000000 0.341 0.086
答案 1 :(得分:4)
我认为split()
和unsplit()
是单向的。
dupMean <- function(x)
{
result <- split(x[, 2], x[, 1])
result <- lapply(result, mean)
result <- unsplit(result, unique(x[, 1]))
return(result)
}
或者,用plyr保存一行:
require(plyr)
dupMean <- function(x)
{
result <- split(x[, 2], x[, 1])
result <- laply(result, mean)
return(result)
}
的更新强> 的 只是为了好奇,这里是建议的各种功能的比较。 Ramnath(fn3)看起来是我电脑上的赢家。
require(plyr)
require(data.table)
require(rbenchmark)
fn1 <- function(z){
z$var <- ave(z$var, z$id, FUN=mean)
return(unique(z))
}
fn2 <- function(z) {
t(sapply(split(z,z$id), function(x) sapply(x,mean)))
}
fn3 <- function(z){
data.table(z)[,list(var = mean(var)), 'id']
}
fn4 <- function(x)
{
result <- t(sapply(split(x,x$id), function(y) sapply(y,mean)))
return(result)
}
fn5 <- function(x)
{
x$var <- ave(x$var, x$id, FUN=mean)
x <- unique(x)
return(x)
}
fn6 <- function(x)
{
result <- do.call(rbind,lapply(split(x,x$id),function(chunk) mean(chunk$var)))
return(data.frame(id = unique(x[, 1]), var = result))
}
fn7 <- function(x)
{
result <- split(x[, 2], x[, 1])
result <- lapply(result, mean)
result <- unsplit(result, unique(x[, 1]))
return(data.frame(id = unique(x[, 1]), var = result))
}
fn8 <- function(x)
{
result <- split(x[, 2], x[, 1])
result <- laply(result, mean)
return(data.frame(id = unique(x[, 1]), var = result))
}
z <- data.frame(id = rep(c(1,1,2,2,3,4,5,6,6,7), 1e5), var = rnorm(1e6))
benchmark(f1 <- fn1(z), f2 <- fn2(z), f3 <- fn3(z), f4 <- fn4(z), f5 <- fn5(z), f6 <- fn6(z), f7 <- fn7(z), f8 <- fn8(z), replications = 2)
结果:
test replications elapsed relative user.self sys.self
1 f1 <- fn1(z) 2 13.45 20.692308 13.27 0.15
2 f2 <- fn2(z) 2 3.54 5.446154 3.43 0.09
3 f3 <- fn3(z) 2 0.65 1.000000 0.54 0.10
4 f4 <- fn4(z) 2 3.62 5.569231 3.50 0.09
5 f5 <- fn5(z) 2 13.57 20.876923 13.25 0.25
6 f6 <- fn6(z) 2 3.53 5.430769 3.36 0.14
7 f7 <- fn7(z) 2 3.34 5.138462 3.28 0.03
8 f8 <- fn8(z) 2 3.34 5.138462 3.26 0.03
答案 2 :(得分:2)
我会使用ave
和unique
的组合:
z <- data.frame(id=rep(c(1,1,2,2,3,4),1e5),var=rnorm(6e5))
z$var <- ave(z$var, z$id, FUN=mean)
z <- unique(z)
更新:在实际计算解决方案之后,这里的速度要快一些。
z <- data.frame(id=rep(c(1,1,2,2,3,4),1e5),var=rnorm(6e5))
system.time({
averages <- t(sapply(split(z,z$id), function(x) sapply(x,mean)))
})
# user system elapsed
# 1.32 0.00 1.33
system.time({
z$var <- ave(z$var, z$id, FUN=mean)
z <- unique(z)
})
# user system elapsed
# 4.33 0.02 4.37