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