【问题标题】:Ifelse with dplyr in RIfelse 在 R 中使用 dplyr
【发布时间】:2020-05-11 18:18:57
【问题描述】:

我想使用 dplyr 将每个 ID 的 DV 列中的 NA 值替换为该人特定时间点的 DV 值:

  • 我想将每个 ID 的时间 2 的 NA(DV 列)替换为该特定 ID 的时间 4 的 DV 值。
  • 我想将每个 ID 的时间 4 的 NA(DV 列)替换为该特定 ID 的时间 0 的 DV 值。

我不知道如何使用 dplyr。 这是我的数据集:

ID   TIME  DV
1      0   5
1      2   NA
1      4   4 
2      0   3
2      2   3
2      4   NA
3      0   7
3      2   NA
3      4   9

预期输出:

ID   TIME  DV
1      0   5
1      2   4
1      4   4 
2      0   3
2      2   3
2      4   3
3      0   7
3      2   9
3      4   9

感谢任何建议。 最好的,

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    我同意@akrun 的观点,也许fill 总体上很合适,但你的规则建议处理事情的方式有点不同(因为"updown" 不遵守你的规则)。

    library(dplyr)
    # library(tidyr)
    dat %>%
      tidyr::pivot_wider(id_cols = "ID", names_from = "TIME", values_from = "DV") %>%
      mutate(
        `2` = if_else(is.na(`2`), `4`, `2`),
        `4` = if_else(is.na(`4`), `0`, `4`)
      ) %>%
      tidyr::pivot_longer(-ID, names_to = "TIME", values_to = "DV")
    # # A tibble: 9 x 3
    #      ID TIME     DV
    #   <int> <chr> <int>
    # 1     1 0         5
    # 2     1 2         4
    # 3     1 4         4
    # 4     2 0         3
    # 5     2 2         3
    # 6     2 4         3
    # 7     3 0         7
    # 8     3 2         9
    # 9     3 4         9
    

    通过查看中间管道可能有助于可视化这是在做什么:

    dat %>%
      tidyr::pivot_wider(id_cols = "ID", names_from = "TIME", values_from = "DV")
    # # A tibble: 3 x 4
    #      ID   `0`   `2`   `4`
    #   <int> <int> <int> <int>
    # 1     1     5    NA     4
    # 2     2     3     3    NA
    # 3     3     7    NA     9
    dat %>%
      tidyr::pivot_wider(id_cols = "ID", names_from = "TIME", values_from = "DV") %>%
      mutate(
        `2` = if_else(is.na(`2`), `4`, `2`),
        `4` = if_else(is.na(`4`), `0`, `4`)
      )
    # # A tibble: 3 x 4
    #      ID   `0`   `2`   `4`
    #   <int> <int> <int> <int>
    # 1     1     5     4     4
    # 2     2     3     3     3
    # 3     3     7     9     9
    

    【讨论】:

      【解决方案2】:

      我们可以在按“ID”分组后使用fill

      library(dplyr)
      library(tidyr)
      df1 %>%
         arrange(ID, TIME) %>%
         # or as @r2evans mentioned
         #arrange(ID, factor(TIME, levels = c(0, 2, 4))) %>%
         group_by(ID) %>%
         fill(DV, .direction = 'downup')
      # A tibble: 9 x 3
      # Groups:   ID [3]
      #     ID  TIME    DV
      #  <int> <int> <int>
      #1     1     0     5
      #2     1     2     4
      #3     1     4     4
      #4     2     0     3
      #5     2     2     3
      #6     2     4     3
      #7     3     0     7
      #8     3     2     9
      #9     3     4     9
      

      数据

      df1 <- structure(list(ID = c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L), TIME = c(0L, 
      2L, 4L, 0L, 2L, 4L, 0L, 2L, 4L), DV = c(5L, NA, 4L, 3L, 3L, NA, 
      7L, NA, 9L)), class = "data.frame", row.names = c(NA, -9L))
      

      【讨论】:

      • @OneyKanta 我会在group_by 之前添加arrange,如果它没有排序,那么 2 将始终在 0 之后,4 在 2 之后
      • 我想知道规则(if is.na(2) then 4, if is.na(4) then 0)是否会使事情复杂化一点。
      • 兑现这一点的另一种选择是factor(TIME),按照规则对其进行排序,然后fill 向下。 (也许在那之后不factoring。)
      • Oney,您在上面评论中的规则与您在问题中的规则不同(而且更多!)。如果它对于获得答案真的很重要,那么你需要保持清晰和一致。这需要在问题本身中,而不是隐藏在 cmets 中(通常可以被读者隐藏或跳过)。 (并且您的预期输出与评论中修改后的规则不一致。当您更新规则时,我建议您也更新您的预期输出。)
      • @akrun 非常感谢您的建议。我现在得到了我想要的 :))
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-11
      • 2016-06-28
      • 1970-01-01
      • 2013-06-19
      • 2021-10-31
      • 2021-01-25
      • 2020-04-20
      相关资源
      最近更新 更多