具有大量行的矩阵

时间:2013-06-05 14:27:59

标签: performance r

我有一个矩阵(在这个例子中命名为点),有大量行(< 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))

我的理解是我做了很多索引,这就是为什么它很慢。 在此先感谢您的帮助!

4 个答案:

答案 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中使用许多函数(aggregatebytapply)。以下是使用聚合的示例。

> 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 

编辑:删除基准