【问题标题】:Medians by group in RR中按组的中位数
【发布时间】:2013-10-29 12:58:04
【问题描述】:

在下面的代码中,我想知道是否有人对如何使用 plyr 或 data.table 优雅地计算 med.val2 有任何见解。

library(plyr)

设置示例数据

data <- data.frame(id1 = 1:20, id2 = rep(letters[1:4], 5), vals=rnorm(20))

先循环计算组中位数

data$med.val <- rep(0, 20)
for (ind in 1:20) data$med.val[ind] <- median(data$vals[data$id2==data$id2[ind]])

现在使用 plyr

data <- ddply(data, .(id2), mutate, med.val.plyr=median(vals))

应该相等

all.equal(data$med.val, data$med.val.plyr)

具有相同 id2 的行的中位数,不包括焦点行

# Median of values corresponding to 
# data$id1!=data$id1[ind] & data$id2==data$id2[ind]
data$med.val2 <- rep(0, 20)
for (ind in 1:20) data$med.val2[ind] <- median(data$vals[data$id1!=data$id1[ind] & data$id2==data$id2[ind]])

在 R 中,我通常使用 plyr 或 data.table 来有效地按组计算值。我的实际数据和函数更复杂但结构相同:我需要使用具有公共标识符的行中的数据来计算函数,不包括焦点行。而且我想不出一种有效而优雅的方法。

【问题讨论】:

    标签: r data.table plyr


    【解决方案1】:

    一种可能的数据表解决方案:

    dt = data.table(data)
    dt[,med.val3 := sapply(.SD$id1, function(x) median(.SD[id1!=x,vals])), by=id2]
    

    编辑时:这个解决方案以及@shadow 的解决方案都相对简洁和优雅。他们也将尽可能高效地从这种解决方案中获得希望。但是,除非您可以编写更有效的实现,否则计算任何留一法统计都将是 O(n^2) 操作(或更糟)。对于平均值和中位数之类的东西,这非常简单,例如:

    looMedian<-function(x){
      rng<-range(x)
      bigMedian<-median(c(x,rng[2]+1))
      smallMedian<-median(c(x,rng[1]-1))
      med<-median(x)
      ret<-ifelse(x<med,bigMedian,smallMedian)  
      wm<-which(x==med)
      if(length(wm)==0)
        return(ret)
      ret[wm]<-median(x[-wm[1]])
      ret
    }
    

    这比简单的解决方案效率更高:

    looMedianSlow<-function(x){
      sapply(seq_along(x),function(z) median(x[-z]))
    }
    
    
    > xx<-rnorm(100)
    > all.equal(looMedianSlow(xx),looMedian(xx))
    [1] TRUE
    > xx<-rnorm(101)
    > all.equal(looMedianSlow(xx),looMedian(xx))
    [1] TRUE
    > microbenchmark(looMedianSlow(xx),looMedian(xx))
    Unit: microseconds
                  expr      min       lq    median        uq       max neval
     looMedianSlow(xx) 5174.193 5264.951 5308.5075 5398.6950 44771.062   100
         looMedian(xx)  241.462  248.513  260.0685  278.3615  3495.796   100
    

    在您的情况下是否可能发生这样的事情取决于您尝试计算的统计数据。

    【讨论】:

      【解决方案2】:

      我会选择辅助功能,然后使用与median 相同的方法。

      med2 <- function(x) sapply(seq_along(x), function(ind) median(x[-ind]))
      data <- ddply(data, .(id2), mutate, med.val2.plyr=med2(vals))
      all.equal(data$med.val2, data$med.val2.plyr)
      

      或者data.table 做同样的方式:

      dt <- data.table(data, key="id2")
      med2 <- function(x) sapply(seq_along(x), function(ind) median(x[-ind]))
      dt[, med.val2.dt:=med2(vals), by=id2]
      all.equal(dt$med.val2, dt$med.val2.dt)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-09-22
        • 1970-01-01
        • 1970-01-01
        • 2021-12-15
        • 1970-01-01
        相关资源
        最近更新 更多