1

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

4

2 回答 2

2

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

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

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

于 2013-10-29T13:37:44.433 回答
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)
于 2013-10-29T13:28:44.643 回答