1

我有一个矩阵(在此示例中命名为点),其中包含大量行(<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

4 回答 4

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是明显的赢家!

于 2013-06-06T00:05:36.260 回答
2

如果我理解您的问题,您正在尝试按第一列汇总数据并计算第二列中值的平均值。aggregate您可以在 R ( , 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
于 2013-06-05T14:32:44.497 回答
0

强制性 data.table 答案:

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
于 2013-06-05T14:36:19.560 回答
0

这是一种多年生植物。是密切相关的,并且有更多的基准测试和一些更高级的方法,如键设置。为了完整起见,这里有一些其他方法:

使可重现:

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对于“拆分/应用/组合”的更复杂变体很有用:

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 

编辑:基准测试已删除

于 2013-06-05T23:10:43.427 回答