R中的群体中位数

时间:2013-10-29 12:58:04

标签: r data.table plyr

在下面的代码中,我想知道是否有人会对如何使用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来有效地按组计算值。我的实际数据和函数更复杂但结构相同:我需要使用具有公共标识符的行中的数据来计算函数,不包括焦点行。我无法找到一种方法来有效和优雅地做到这一点。

2 个答案:

答案 0 :(得分:1)

我会选择辅助功能,然后使用与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)

答案 1 :(得分: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

在您的情况下,这样的事情是否可行将取决于您尝试计算的统计数据。