【问题标题】:R Custom Max FunctionR 自定义最大功能
【发布时间】:2019-06-01 04:03:52
【问题描述】:
data=data.frame("person"=c(1,1,1,1,2,2,2,2,3,3,3,3,4,4,4),
                "score"=c(1,2,3,2,2,1,2,3,2,3,1,4,1,4,3),
                "WANT"=c(1,2,3,3,2,1,2,3,2,3,3,4,1,4,NA))

我们会跟踪每个人的分数,直到他们达到“精通” (3) 或卓越 (4)。如果一个人得分优秀 (4),则保留该值并删除该人的下一个分数(请参阅第 4 个人;而不是 NA 只想删除该行)。如果一个人得分为精通 (3),则该值将被结转,除非他们得分为 4,这将取代 3 的得分。否则,这些值将保持原样。我试过 cummax func 但不知道如何应用这样的规则。

下面是我的尝试

data$want = ave(data$score, data$person, FUN = function(x) cummax(replace(x, is.na(x), -1)))

【问题讨论】:

    标签: r max


    【解决方案1】:

    您可以使用您指定的规则编写自定义函数,并将其应用于组中的每个人,如下所示,

    library(dplyr)
    
    count_3_4 <- function(vec){
      max = 0
      for(i in seq_along(vec)){
        if(vec[i] > max){
          max = vec[i]
          if(max == 3 || max == 4){
            vec[i] = max
          }
        }else if(max == 4 && vec[i] < max){
          vec[i] = NA
        }else{
          if(max == 3 || max == 4){
            vec[i] = max
          }
        }
      }
      return(vec)
    }
    
    data=data.frame("person"=c(1,1,1,1,2,2,2,2,3,3,3,3,4,4,4),
                    "score"=c(1,2,3,2,2,1,2,3,2,3,1,4,1,4,3),
                    "WANT"=c(1,2,3,3,2,1,2,3,2,3,3,4,1,4,NA))
    
    data%>%
      group_by(person)%>%
      mutate(TestVal = count_3_4(score)) %>%
      ungroup()
    

    【讨论】:

    • 非常感谢,有没有更短或更简单的方法?我还不习惯那种量级的函数编写。
    • 非常感谢,但这与预期的输出不符。
    【解决方案2】:

    我们可以使用cummax 来获得高于3 或更高的分数,或者保持score 不变。要在前 4 个之后获得 NAs,我们可以将 replaceduplicated 4 个值作为 NA

    library(dplyr)
    
    data %>%
      group_by(person) %>%
        mutate(WANT2 = ifelse(score >= 3 | (row_number() >= which.max(score == 3)), 
                       cummax(score), score), 
                WANT2 = replace(WANT2, duplicated(WANT2 == 4) & WANT2 == 4, NA))
    
    
    #   person score  WANT WANT2
    #    <dbl> <dbl> <dbl> <dbl>
    # 1      1     1     1     1
    # 2      1     2     2     2
    # 3      1     3     3     3
    # 4      1     2     3     3
    # 5      2     2     2     2
    # 6      2     1     1     1
    # 7      2     2     2     2
    # 8      2     3     3     3
    # 9      3     2     2     2
    #10      3     3     3     3
    #11      3     1     3     3
    #12      3     4     4     4
    #13      4     1     1     1
    #14      4     4     4     4
    #15      4     3    NA    NA
    

    【讨论】:

    • person 1 row 4 是 2 但应该是 3
    • 嗨,您好像删除了一个编辑,我只是​​想知道您是否可以修改您共享的代码,非常感谢
    • @bvowe 对不起,我添加了一个额外的条件来检查。你现在可以检查吗?
    【解决方案3】:

    data.table 的选项。将'data.frame'转换为'data.table'(setDT(data)),按'person'分组,指定i选择'score'大于等于3的行,得到cummax 'score'的值并将其分配给'WANT2',将NA元素替换为'score'值(pmax),将每个'person'的重复'4'值设置为NA

    library(data.table)
    setDT(data)[score >=3,  WANT2 := cummax(score), person
         ][, WANT2 := pmax(score, WANT2, na.rm = TRUE), person]
    i1 <- data[WANT2 == 4, .I[duplicated(WANT2)], person]$V1
    data[i1, WANT2 := NA]     
    data
    #    person score WANT WANT2
    # 1:      1     1    1     1
    # 2:      1     2    2     2
    # 3:      1     3    3     3
    # 4:      1     2    3     2
    # 5:      2     2    2     2
    # 6:      2     1    1     1
    # 7:      2     2    2     2
    # 8:      2     3    3     3
    # 9:      3     2    2     2
    #10:      3     3    3     3
    #11:      3     1    3     1
    #12:      3     4    4     4
    #13:      4     1    1     1
    #14:      4     4    4     4
    #15:      4     3   NA    NA
    

    或者创建一个重复值 4 的索引

    setDT(data)[, ind := NA^(duplicated(cumsum(score == 4)) & 
             shift(score) == 4), person]
    

    然后在指定i 以选择分数大于或等于4 的行时按人获取'score' 的累积最大值

    data[score >=3, WANT2 := cummax(score), person]
    

    并使用pmaxNA 元素替换为'score',同时确保重复的4 是NA(使用'ind')

    data[, WANT2 := pmax(score, WANT2, na.rm = TRUE) * ind]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多