【问题标题】:Recoding by an order in r在 r 中按顺序重新编码
【发布时间】:2021-02-21 17:04:48
【问题描述】:

我有一个数据重新编码难题。这是我的示例数据的样子:

df <- data.frame(
  id = c(1,1,1,1,1,1,1, 2,2,2,2,2,2, 3,3,3,3,3,3,3),
  scores = c(0,1,1,0,0,-1,-1, 0,0,1,-1,-1,-1, 0,1,0,1,1,0,1),
  position = c(1,2,3,4,5,6,7, 1,2,3,4,5,6, 1,2,3,4,5,6,7),
  cat = c(1,1,1,1,1,0,0, 1,1,1,0,0,0, 1,1,1,1,1,1,1))

   id scores position cat
1   1      0        1   1
2   1      1        2   1
3   1      1        3   1
4   1      0        4   1
5   1      0        5   1
6   1     -1        6   0
7   1     -1        7   0
8   2      0        1   1
9   2      0        2   1
10  2      1        3   1
11  2     -1        4   0
12  2     -1        5   0
13  2     -1        6   0
14  3      0        1   1
15  3      1        2   1
16  3      0        3   1
17  3      1        4   1
18  3      1        5   1
19  3      0        6   1
20  3      1        7   1

数据集中有三个 id,行按positon 变量排序。对于每个id,以-1开头的分数后的第一行需要为0cat变量需要为1。例如,对于id=1,第一行将是6th 位置,在该行中,得分应为0cat 变量需要为1。对于那些没有scores=-1 的 id,我保持原样。

所需的输出应如下所示:

   id scores position cat
1   1      0        1   1
2   1      1        2   1
3   1      1        3   1
4   1      0        4   1
5   1      0        5   1
6   1      0        6   1
7   1     -1        7   0
8   2      0        1   1
9   2      0        2   1
10  2      1        3   1
11  2      0        4   1
12  2     -1        5   0
13  2     -1        6   0
14  3      0        1   1
15  3      1        2   1
16  3      0        3   1
17  3      1        4   1
18  3      1        5   1
19  3      0        6   1
20  3      1        7   1

有什么推荐吗?? 谢谢

【问题讨论】:

    标签: r recode


    【解决方案1】:

    这可能就是你所追求的

    df %>% 
    group_by(id) %>%
    mutate(i = which(scores == -1)[1]) %>% # find the first row == -1
    mutate(scores = case_when(position == i & scores !=0 ~ 0, T ~ scores), # update the score using position & i
    cat = ifelse(scores == -1,0,1)) %>% # then update cat
    select (-i) # remove I
    
    

    【讨论】:

    • 嗨@e.matt,感谢您的回复。这适用于第一种情况,但您的解决方案为第二种情况重新编码了最后一行。
    • 哪个 id 和值不正确,很确定这与您想要的输出相匹配
    • 在第 13 行中,此过程将分数重新编码为 0,但它应该将第 11 行的 score 重新编码为 0,这是案例 2 的第一个条件。
    【解决方案2】:

    在尝试了一些事情并从@Ricky 和@e.matt 那里得到了一些想法之后,我想出了一个解决方案。

    df %>%
      filter(scores == -1) %>%                         # keep cases where var = 1
      distinct(id, .keep_all = T) %>%           # keep distinct cases based on group
      mutate(first = 1) %>%                        # create first column
      right_join(df, by=c("id","scores","position","cat")) %>% # join back original dataset
      mutate(first = coalesce(first, 0)) %>%       # replace NAs with 0
    mutate(scores = case_when(
      first == 1 ~ 0,
      TRUE~scores)) %>%
    mutate(cat = case_when(
        first == 1 ~ 1,
        TRUE~cat))
    

    这提供了我想要的输出。

       id scores position cat first
    1   1      0        1   1     0
    2   1      1        2   1     0
    3   1      1        3   1     0
    4   1      0        4   1     0
    5   1      0        5   1     0
    6   1      0        6   1     1
    7   1     -1        7   0     0
    8   2      0        1   1     0
    9   2      0        2   1     0
    10  2      1        3   1     0
    11  2      0        4   1     1
    12  2     -1        5   0     0
    13  2     -1        6   0     0
    14  3      0        1   1     0
    15  3      1        2   1     0
    16  3      0        3   1     0
    17  3      1        4   1     0
    18  3      1        5   1     0
    19  3      0        6   1     0
    20  3      1        7   1     0
    

    【讨论】:

      【解决方案3】:

      这是一个data.tableoneliner

      library( data.table )
      setDT(df)
      df[ df[, .(cumsum( scores == -1 ) == 1), by = .(id)]$V1, `:=`( scores = 0, cat = 1) ]
      
      #     id scores position cat
      #  1:  1      0        1   1
      #  2:  1      1        2   1
      #  3:  1      1        3   1
      #  4:  1      0        4   1
      #  5:  1      0        5   1
      #  6:  1      0        6   1
      #  7:  1     -1        7   0
      #  8:  2      0        1   1
      #  9:  2      0        2   1
      # 10:  2      1        3   1
      # 11:  2      0        4   1
      # 12:  2     -1        5   0
      # 13:  2     -1        6   0
      # 14:  3      0        1   1
      # 15:  3      1        2   1
      # 16:  3      0        3   1
      # 17:  3      1        4   1
      # 18:  3      1        5   1
      # 19:  3      0        6   1
      # 20:  3      1        7   1
      

      【讨论】:

        【解决方案4】:

        您可以使用 dplyr 包按照这些方式做一些事情:

        library(dplyr)
        
        df = mutate(df, cat = ifelse(scores == -1, 1, cat),
                        scores = ifelse(scores == -1, 0, scores))
        

        使用mutate() 函数,我根据ifelse() 条件语句重新分配scorescat 字段的值。对于分数,如果分数为-1,则将该值替换为0,否则保持分数不变。对于cat,它还会检查scores 是否等于-1,但在满足条件时将赋值为1,或者在不满足条件时赋值为cat

        编辑

        在我们在 cmets 中讨论之后,我认为这些方面的内容应该会有所帮助(您可能必须修改逻辑,因为我不完全遵循此处所需的输出):

        for(i in 1:nrow(df)){
            # Check if score is -1
            if(df[i, 'scores'] == -1){
                # Update values for the next row
                df[i+1, 'scores'] <- 0
                df[i+1, 'cat'] <- 1
            }
        }
        

        抱歉,我没有真正遵循所需的输出,希望这有助于您找到答案!

        【讨论】:

        • 嗨@Ricky,感谢您的回复。您的解决方案将所有 -1 分数重新编码为 0 并且没有更改 cat 变量。你得到想要的输出了吗?就我而言,我做不到。应该知道任何其他图书馆吗?
        • @amisos55 哎呀,对不起。这是因为我在cat 之前覆盖了scores 变量。我调整了答案以更改顺序,现在输出看起来对我来说是正确的,如果仍然不正确,请告诉我!
        • 6th 行已正确修改。但例如,它没有保留7th 行。 7th 行应该有分数 -1cat 0。它应该保持不变。它应该只修改6th 行,之后的第一行具有第一个分数-1
        • 对不起,我误解了你的问题。如果您需要以这种方式相互抵消,我会推荐一种 for 循环方法,请给我一分钟时间来更新我的答案
        • 我用 for 循环选项更新了答案。可能还不是您所需要的,但希望您能够根据自己的需要对其进行调整,对不起,我没有完全遵循 ?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-07-23
        • 1970-01-01
        • 1970-01-01
        • 2012-01-11
        • 1970-01-01
        • 1970-01-01
        • 2019-07-12
        相关资源
        最近更新 更多