我有一个矩阵(在这个例子中命名为点),有大量行(< 90,000),只有两列。
A B
1 10.1
2 9.2
3 4.5
1 8.9
1 0.7
我想创建另一个矩阵,其中只有列“A”中的唯一值和列“B”中与这些重复值相对应的值的平均值。结果: -
A B
1 6.56
2 9.20
3 4.50
目前,我正在使用这个(下面的代码),这需要花费很多时间。所以,如果有人能告诉我如何加快这些计算,我将非常感激。
uniquedata<-points[which(!duplicated(points[,"A"])),]
reps<-points[which(duplicated(points[,"A"])),]
result<-list()
intensity<-list()
for(i in c(1:length(uniquedata[,"A"]))){
result[[i]]<-which(uniquedata[i,"A"]==reps[,"A"])
}
for(j in c(1:length(result))){
if(length(result[[j]])!=0){
intensity[j]<-mean(c(reps[result[[j]],"B"],uniquedata[j,"B"]))
}else{
intensity[j]<-uniquedata[j,"B"]
}
}
points1<-cbind(uniquedata[,1],unlist(intensity))
我的理解是我做了很多索引,这就是为什么它很慢。 在此先感谢您的帮助!
答案 0 :(得分:3)
鉴于你有一个矩阵,确实需要转换为data.frame
。以下是使用rowsum
# assuming your matrix is called M
rowsum(M[,2],M[,1]) / rowsum(rep_len(1,nrow(M)), M[,1])
一些适当的基准
using.by <- function() x <- by(df1$val, df1$name, mean)
using.aggregate <- function() x <- aggregate(val ~ name, FUN = mean, data = df1)
using.ddply <- function() x <- ddply(df1, .(name), summarize, mu=mean(val))
using.tapply <- function() tapply(df1$val,df1$name,mean)
using.rowsum <- function () x <- rowsum(M[,2],M[,1]) / rowsum(rep_len(1,nrow(M)), M[,1])
using.data.table <- function() x <- DT[,mean(val),by=name]
library(microbenchmark)
set.seed(1)
n <- 1e6
df1 <- data.frame(name=sample(1:5, n, replace = TRUE),
val = runif(n))
M <- as.matrix(df1)
DT <- as.data.table(df1)
microbenchmark(using.by(), using.aggregate(), using.ddply(),
using.tapply(), using.rowsum(), using.data.table(),
times = 10)
Unit: milliseconds
# expr min lq median uq max neval
# using.by() 843.46550 854.22116 862.15995 868.75859 912.49406 10
# using.aggregate() 2416.37227 2451.60134 2482.25319 2498.54546 2501.58574 10
# using.ddply() 208.03686 209.29981 219.74203 253.46119 258.40935 10
# using.tapply() 819.30594 820.77757 830.07718 869.50280 987.24822 10
# using.rowsum() 192.36873 193.48971 194.42591 198.63762 238.91224 10
# using.data.table() 51.46841 52.37541 52.62934 53.05449 54.06227 10
毫不奇怪data.table
是明显的赢家!
答案 1 :(得分:2)
如果我理解了您的问题,那么您尝试按第一列汇总数据并计算第二列中值的平均值。您可以在R中使用许多函数(aggregate
,by
,tapply
)。以下是使用聚合的示例。
> my.data <- data.frame(name = sample(1:5, 1000, replace = TRUE), vals = runif(1000))
> head(my.data)
name vals
1 3 0.12357187
2 2 0.50271246
3 5 0.03868217
4 5 0.48045079
5 5 0.35684145
6 5 0.36128855
> aggregate(vals ~ name, FUN = mean, data = my.data)
name vals
1 1 0.4657559
2 2 0.4920722
3 3 0.5062826
4 4 0.5169585
5 5 0.4857688
答案 2 :(得分:0)
强制性数据。答案:
set.seed(42)
m <- cbind(a=sample(1:3,1e4,TRUE),b=rnorm(1e4))
library(data.table)
DT <- as.data.table(m)
DT[,mean(b),by=a]
# a V1
# 1: 3 -0.01237034
# 2: 1 0.01064392
# 3: 2 -0.02411601
答案 3 :(得分:0)
这是一个多年生的事。 This密切相关,有更多的基准测试和一些更先进的方法,如键设置。为了完整起见,这里有一些其他方法:
重现性:
set.seed(1)
df1 <- data.frame(name=sample(1:5, 1000, replace = TRUE),
val = runif(1000))
head(df1)
给出:
name val
1 2 0.53080879
2 2 0.68486090
3 3 0.38328339
4 5 0.95498800
5 2 0.11835658
6 5 0.03910006
tapply
可以被认为是制作一个交叉分类表,然后将函数应用于它,如下所示:
tapply(df1$val,df1$name,mean)
给出:
1 2 3 4 5
0.4946062 0.4822890 0.5110930 0.5030683 0.4604779
plyr
对于'split / apply / combine'的更复杂变体非常有用:
library(plyr)
ddply(df1, .(name), summarize, mu=mean(val))
给出:
name mu
1 1 0.4946062
2 2 0.4822890
3 3 0.5110930
4 4 0.5030683
5 5 0.4604779
还有
by(df1, df1$name, mean)
给出了这个(相当笨拙的)输出:
df1$name: 1
name val
1.0000000 0.4946062
------------------------------------------------------------
df1$name: 2
name val
2.000000 0.482289
------------------------------------------------------------
df1$name: 3
name val
3.000000 0.511093
------------------------------------------------------------
df1$name: 4
name val
4.0000000 0.5030683
------------------------------------------------------------
df1$name: 5
name val
5.0000000 0.4604779
编辑:删除基准