如何在不使用循环的情况下计算R中的中间区间百分位数?

时间:2014-07-12 04:30:35

标签: r dplyr percentile

我有一组具有不同组的数据 - 对于这个例子,我们只说两组 - 我想计算一个中间区间百分位数,但我想使用dplyr(所以没有循环)。

以下是我的数据和目前的情况:

library(dplyr);
group<-c("A","A","A","A","A","A","A","A","A","A","A","B","B","B","B","B","B","B","B","B","B","B")
score<-c(1,2,3,4,5,6,7,8,9,10,10,9,10,7,8,4,5,10,11,12,13,10)
my_orig_df<-data.frame(group,score)
mydf<-my_orig_df %.%
  group_by(group) %.%
  mutate (   Cum= round( cume_dist(score),2) , myPTILE=percent_rank(score)) 
mydf

要清楚,我希望组A的第一个值为.05,而不是.09,也不是0。 虽然结果很接近,但它们并不完全符合我的预期。

我可以通过嵌套循环获得所需的结果(但这不是我想要的):

 Ugroup<-unique (group)
for (i in 1:length(Ugroup)) {
  temp<-subset(mydf,group==Ugroup[i]) 
  for(j in 1:length(temp$score)) {
    ptile<-c(ptile,    ((sum(temp$score==temp$score[j])/2)+sum(temp$score<temp$score[j]))   /length(temp$score))
  } }

当我使用带有多个组的大型数据集的循环(上面)运行代码时,时间就成了问题。

我尝试了以下内容:row_number(score); ntile(score, 99); min_rank(score); dense_rank(score); percent_rank(score); cume_dist(score)但没有一个会导致我正在寻找的内容。任何想法都将不胜感激。

1 个答案:

答案 0 :(得分:1)

这似乎与你的循环产生相同的东西。虽然不使用dplyr

f <- function(z) sapply(z,function(x) (sum(z==x)/2+sum(z<x))/length(z))
ptile <- as.vector(t(aggregate(score~group,my_orig_df,f)[,-1]))
ptile
#  [1] 0.04545455 0.13636364 0.22727273 0.31818182 0.40909091 0.50000000 0.59090909
#  [8] 0.68181818 0.77272727 0.90909091 0.90909091 0.40909091 0.59090909 0.22727273
# [15] 0.31818182 0.04545455 0.13636364 0.59090909 0.77272727 0.86363636 0.95454545
# [22] 0.59090909

这是一个可能更快的data.table解决方案。

library(data.table)
DT <- as.data.table(my_orig_df)
ptile.dt <- DT[,sapply(score,function(x)(sum(score==x)/2+sum(score<x))/.N),by=group]$V1

identical(ptile,ptile.dt)
# [1] TRUE