R版本2.11.1 Windows 7上的32位
我得到数据train.txt如下:
USER_A USER_B ACTION
1 7 0
1 8 1
2 6 2
2 7 1
3 8 2
我将数据作为以下算法处理:
train_data=read.table("train.txt",header=T)
result=matrix(0,length(unique(train_data$USER_B)),2)
result[,1]=unique(train_data$USER_B)
for(i in 1:dim(result)[1])
{
temp=train_data[train_data$USER_B%in%result[i,1],]
result[i,2]=sum(temp[,3])/dim(temp)[1]
}
结果是train_data中每个USER_B的得分。分数定义为:
USER_B的得分=(USER_B的所有行动的总和)/(USER_B的推荐时间)
但是train_data非常大,我可能需要三天才能完成这个程序,所以我来这里寻求帮助,这个算法可以改进吗?
答案 0 :(得分:6)
运行您的示例,您想要的结果是计算每个唯一USER_B的平均ACTION:
[,1] [,2]
[1,] 7 0.5
[2,] 8 1.0
[3,] 6 2.0
您可以使用包ddply()
中的plyr
函数使用一行代码执行此操作
library(plyr)
ddply(train_data[, -1], .(USER_B), numcolwise(mean))
USER_B ACTION
1 6 2.0
2 7 0.5
3 8 1.0
或者,基数R中的函数tapply
也是如此:
tapply(train_data$ACTION, train_data$USER_B, mean)
根据表格的大小,您可以将执行时间提高20倍或更高。以下是具有一百万个条目的data.frame的system.time测试。你的算法需要116秒,ddply()需要5.4秒,而tapply需要1.2秒:
train_data <- data.frame(
USER_A = 1:1e6,
USER_B = sample(1:1e3, size=1e6, replace=TRUE),
ACTION = sample (1:100, size=1e6, replace=TRUE))
yourfunction <- function(){
result <- matrix(0,length(unique(train_data$USER_B)),2)
result[,1] <- unique(train_data$USER_B);
for(i in 1:dim(result)[1]){
temp=train_data[train_data$USER_B%in%result[i,1],]
result[i,2]=sum(temp[,3])/dim(temp)[1]
}
result
}
system.time(XX <- yourfunction())
user system elapsed
116.29 14.04 134.33
system.time(YY <- ddply(train_data[, -1], .(USER_B), numcolwise(mean)))
user system elapsed
5.43 1.60 7.19
system.time(ZZ <- tapply(train_data$ACTION, train_data$USER_B, mean))
user system elapsed
1.17 0.06 1.25
答案 1 :(得分:5)
除了@Andrie提供的方法之外,split()
然后lapply()
方法仍然更快:
> system.time(ZZ <- tapply(train_data$ACTION, train_data$USER_B, mean))
user system elapsed
1.025 0.011 1.062
> system.time(WW <- unlist(lapply(split(train_data$ACTION,
+ f = train_data$USER_B),
+ mean)))
user system elapsed
0.465 0.007 0.483
sapply()
对于这个问题也同样快:
> system.time(SS <- sapply(split(train_data$ACTION, f = train_data$USER_B),
+ mean))
user system elapsed
0.469 0.001 0.474
答案 2 :(得分:4)
@gavin在使用split
和lapply
的组合时已经证明了高性能。
包data.table
提供了更显着的性能提升~75%
library(data.table)
system.time({
VV <- as.data.table(train_data)[, list(ACTION=mean(ACTION)), by=USER_B]
})
user system elapsed
0.15 0.02 0.17
system.time(WW <- unlist(lapply(split(train_data$ACTION, f = train_data$USER_B),mean)))
user system elapsed
0.61 0.02 0.63
all(WW==VV$ACTION)
[1] TRUE
答案 3 :(得分:0)
您可以尝试tapply
:
train_data <- read.table("train.txt",header=T);
result <- tapply(train_data$ACTION,train_data$USER_B,function(x) sum(x)/length(x));
您可以使用mean
代替function..
,但我最近读到最后一个解决方案更快(如果您没有NA
等)。
我没有测试,但我相信这应该更快。如果您想要更快的解决方案,请查看Rcpp
和inline
个包...