假设我有两个数据框“值”和“权重”,我想按类别(A,B,C)计算加权中位数(第1年,第2年):
values <- data.frame(TICKER=c("A","A","B","B","B","C","C","C","C"), year1=c(1,2,3,4,5,6,7,8,9), year2=c(9,8,7,6,5,4,3,2,1))
weights <- data.frame(TICKER=c("A","A","B","B","B","C","C","C","C"), year1=c(0.3,0.7,0.25,0.25,0.5,0.1,0.1,0.6,0.2), year2=c(0.6,0.4,0.3,0.5,0.2,0.4,0.2,0.1,0.3))
为此我想使用ddply和weightedMedian函数(包matrixStats)。
output <- ddply(values, .(TICKER), colwise(weightedMedian(values, weights), na.rm=TRUE))
但是,我收到错误消息:
"(list) object cannot be coerced to type 'double'"
有人知道如何调整代码以获得有效的解决方案吗?
我尝试将数据帧转换为矩阵(通过as.matrix),因为weightedMedian需要矩阵作为输入。但是,这没有用。 到目前为止我找到的唯一解决方案是使用子集进行循环(但是,这非常慢且不太优雅)
output <- matrix(data=0, nrow=3, ncol=2)
for (i in 2:ncol(values)){
for (j in 1:length(unique(values$TICKER))){
values.j <- subset(values, values$TICKER == as.character(unique(values$TICKER)[j]))
weights.j <- subset(weights, weights$TICKER == as.character(unique(values$TICKER)[j]))
output[j,(i-1)] <- weightedMedian(values.j[,i], weights.j[,i], na.rm=TRUE)
}}
任何帮助将不胜感激。非常感谢。
答案 0 :(得分:2)
除了OP提到的weightedMedian
功能外,Hmisc
包还提供了更为通用的wtd.quantile
功能。
我将data.frames拆分为列表,并将这些函数应用于具有嵌套sapply
s的年份变量。比较下面的结果,似乎weightedMedian
产生了所需的结果。
要准备数据,请将值和权重沿其TICKER分成列表。
# split values and weights into lists by category
valuesList <- split(values, values$TICKER)
weightsList <- split(weights, values$TICKER)
如果我在上面的代码中使用OP问题中的weightedMedian
,我会得到以下内容:
library(matrixStats)
sapply(names(valuesList),
function(i) sapply(names(valuesList[[i]])[-1],
function(j) weightedMedian(valuesList[[i]][[j]],
w=weightsList[[i]][[j]])))
A B C
year1 1.7 4.333333 8
year2 8.6 6.125000 3
另一个包Hmisc
具有加权分位数函数wtd.quantile
。
# load Hmisc package
library(Hmisc)
sapply(names(valuesList),
function(i) sapply(names(valuesList[[i]])[-1],
function(j) {
wtd.quantile(valuesList[[i]][[j]],
weights=weightsList[[i]][[j]], probs=0.5)}))
返回
myMedians
A B C
year1.50% 2 5 9
year2.50% 9 7 4
从检查开始,matrixStats
的结果似乎更合理。例如,TICKER == C,year == 2不应该是4。
答案 1 :(得分:1)
如果您希望保留在plyr / weightedStats上下文中,我首先将两个data.frames
合并,然后使用您的值的已知列索引与ldply
一起运行ddply
变量:
df <- data.frame(values,wt=weights)
output <- lapply(names(values)[-1],
function(i) ddply(df,.(TICKER),
function(x) setNames(weightedMedian(x=x[,i],w=x[,match(i,names(x))+ncol(x)/2]),i)))
然后,您可以执行以下操作将结果转换为单个data.frame
do.call('join',output)
给你
TICKER year1 year2
1 A 1.700000 8.600
2 B 4.333333 6.125
3 C 8.000000 3.000
顺便说一句,您的错误消息的原因是您只是“切片”。您在values
调用整个weights
data.frame时的weightedMedian
数据框。