【问题标题】:Percentile for Each Observation w/r/t Grouping Variable每个观测值的百分位数 w/r/t 分组变量
【发布时间】:2010-01-29 06:09:02
【问题描述】:

我有一些如下所示的数据。它按变量“年份”分组,我想提取分数的每个观察值的百分位数,相对于它来自的年份,最好作为向量。

Year   Score
2001   89
2001   70
2001   72
2001   ...
..........
2004   87
2004   90

等等

我该怎么做? aggregate 不起作用,我认为 apply 也不起作用。

【问题讨论】:

    标签: r


    【解决方案1】:

    跟进 Vince 的解决方案,您也可以通过 plyrby 进行此操作:

    ddply(df, .(years), function(x) transform(x, percentile=ecdf(x$scores)(x$scores)))
    

    【讨论】:

    • 这很漂亮。我知道必须有一种单行方式来做到这一点,即使它需要加载一个包。
    • 或者更简单一点:ddply(df, .(years), transform, percentile = ecdf(scores)(scores))
    【解决方案2】:

    使用ave

    ave(d1$scores, d1$year, FUN=function(x) ecdf(x)(x))
    

    【讨论】:

    • 我认为这是最好的解决方案 - 它使用来自统计数据的函数并且是单行的。干得好!
    【解决方案3】:

    我可能会误解,但我认为可以这样:

    > years = c(2006, 2006, 2006, 2006, 2001, 2001, 2001, 2001, 2001)
    > scores = c(13, 65, 23, 34, 78, 56, 89, 98, 100)
    > tapply(scores, years, quantile)
    $`2001`
      0%  25%  50%  75% 100% 
      56   78   89   98  100 
    
    $`2006`
       0%   25%   50%   75%  100% 
    13.00 20.50 28.50 41.75 65.00 
    

    这是对的吗?

    我的意思是每个的实际百分位数 观察。 ——瑞安·罗萨里奥

    编辑:

    我认为这样可以做到:

    > tapply(scores, years, function(x) { f = ecdf(x); sapply(x, f) })
    $`2001`
    [1] 0.4 0.2 0.6 0.8 1.0
    
    $`2006`
    [1] 0.25 1.00 0.50 0.75
    

    使用您的数据:

    > tapply(scores, years, function(x) { f = ecdf(x); sapply(x, f) })
    $`2000`
    [1] 0.3333333 0.6666667 1.0000000
    
    $`2008`
    [1] 0.5 1.0
    

    编辑 2:

    这可能更快:

    tapply(scores, years, function(x) { f = ecdf(x); f(x) })
    

    f() 被矢量化了:-)

    最后,修改,我保证 :-)。如果你想要名字:

    > tapply(scores, years, function(x) { f = ecdf(x); r = f(x); names(r) <- x; r })
    $`2000`
         1000      1700      2000 
    0.3333333 0.6666667 1.0000000 
    
    $`2008`
    1500 2000 
     0.5  1.0 
    

    【讨论】:

      【解决方案4】:

      使用 data.table 也很简单。仅出于完整性考虑,也是查找 data.table 解决方案的简便方法。

      library(data.table)
      year <- rep(2001:2005, 2)
      score <- round(rnorm(10, 35, 3))
      
      dt <- data.table(score)
      
      
      dt[, .(Percentile = ecdf(score)(score)), by = list(year)]
      

      【讨论】:

        【解决方案5】:

        你也可以这样做:

        # first I'll create two dummy variables (Year, Score)
        year <- rep(2001:2005, 2)
        score <- round(rnorm(10, 35, 3))
        
        # then coerce variables to data frame
        d <- data.frame(year, score)
        
        # then you can use split() function to apply
        # function to each stratum of grouping variable
        sapply(split(score, year), function(x) quantile(x, probs=seq(.1, .9, .1)))
        

        输出会是这样的:

             2001 2002 2003 2004 2005
        10%  34.3 32.1 34.3 29.6 36.1
        20%  34.6 32.2 34.6 30.2 36.2
        30%  34.9 32.3 34.9 30.8 36.3
        40%  35.2 32.4 35.2 31.4 36.4
        50%  35.5 32.5 35.5 32.0 36.5
        60%  35.8 32.6 35.8 32.6 36.6
        70%  36.1 32.7 36.1 33.2 36.7
        80%  36.4 32.8 36.4 33.8 36.8
        90%  36.7 32.9 36.7 34.4 36.9
        

        如果您愿意,可以使用 t() 函数来转置行和列。编写函数将是解决此类问题的好方法。我强烈推荐 Hadley Wickam 编写的 plyr 包。

        希望这会有所帮助! 万事如意!

        【讨论】:

          【解决方案6】:

          我找到了一个方法,但它需要一个循环。

          group.pctiles <- function(group.var, comparable) {
              unique.vals <- unique(group.var)
              pctiles <- vector(length = length(group.var))
              for (i in 1:length(unique.vals)) {
                  slice <- which(group.var == unique.vals[i])
                  F <- ecdf(comparable[slice])
                  group.pctiles <- F(comparable[slice])
                  pctiles[slice] <- group.pctiles
              }
              return(pctiles)
          }
          

          group.var 是对数据进行分组的变量。在我的问题示例中,它是年份。可比较包含我们想要找到百分位数的值。在我的问题中,可比较的是分数。

          对于以下数据,我得到以下结果:

          Year,School,Fees
          2000,10,1000
          2008,1,1050
          2008,4,2000
          2000,3,1700
          2000,1,2000
          
          > group.pctiles(dat, dat$Year, dat$Fees)
          [1] 0.3333333 0.5000000 1.0000000 0.6666667 1.0000000
          

          然后,我可以将这些百分位数重新绑定到原始 data.frame 中以进行分析、报告等。

          谁有不需要循环的解决方案?

          【讨论】:

            【解决方案7】:

            怎么样:

            Year <- c(2000,2008,2008,2000,2000)
            Fees <- c(1000,1050,2000,1700,2000)
            dat <- data.frame(Fees,Year,result=NA)
            res <- tapply(Fees,Year,function(x) rank(x,ties.method="max")/length(x))
            for(i in 1:length(res))
               dat[Year==as.numeric(names(res)[i]),"result"] <-res[[i]]
            

            产生:

              Fees Year    result
            1 1000 2000 0.3333333
            2 1050 2008 0.5000000
            3 2000 2008 1.0000000
            4 1700 2000 0.6666667
            5 2000 2000 1.0000000
            

            【讨论】:

              猜你喜欢
              • 2022-12-09
              • 2017-03-23
              • 1970-01-01
              • 1970-01-01
              • 2019-03-27
              • 2022-01-14
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多