【问题标题】:Selecting a large range of values to recode in R选择大范围的值以在 R 中重新编码
【发布时间】:2021-10-25 19:37:50
【问题描述】:

我想跨多个列重新编码大量变量。这是一个例子 df

df <- data.frame(
  id_number = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
  age = c(10, 11, 12, 13, 14, 15, 16, 17, 18, 19),
  abc1 = c(501, 502, 503, 504, 505, 506, 507, 508, 509, 510),
  abc2 = c(501, 502, 501, 501, 502, 501, 502, 503, 501, 502),
  abc3 = c(501, 506, 501, 501, 510, 501, 510, 501, 501, 501),
  abc4 = c(507, 505, 501, 501, 501, 501, 501, 501, 501, 501)
)

df

列 abc1:abc4 的值为 501:510,我正在尝试一次将所有这些列的 501:508 重新编码为 91、509 为 92 和 510 为 93。 这是我尝试过的-

library(dplyr)
df1 <- 
  df %>%
  mutate(across(
    abc1:abc4,
    ~ recode(
      .x,
      `501:508` = 91L,
      `509` = 92L,
      `510` = 93L
          )
  ))

但我得到一个错误

x 由强制引入的 NA ℹ 输入..1across(abc1:abc4, ~recode(.x, `501:508` = 91L, `509` = 92L, `510` = 93L)).NAs 由coercionProblem 引入mutate() 输入..1。 x 被视为 NA 的未替换值,因为 .x 不兼容。请详细指定替换或提供.default

但是,如果我一个一个地更改值,它会起作用,但我想一次全部完成,因为我的真实数据有一​​个很长的值列表。我是不是在这部分做错了什么

`501:508` = 91L,

谢谢!

上面的后续问题

假设 abc1:abc4 的值更大,并且还有一组 1-175 范围内的值。 abc1:abc4 = c(1:175, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510)。我只是调整了上一个示例中的值来说明这一点。

df1 <- data.frame(
  id_number = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
  age = c(10, 11, 12, 13, 14, 15, 16, 17, 18, 19),
  abc1 = c(14, 158, 170, 504, 505, 506, 507, 508, 509, 510),
  abc2 = c(501, 502, 501, 501, 45, 501, 502, 59, 501, 100),
  abc3 = c(89, 506, 12, 501, 510, 13, 510, 501, 11, 501),
  abc4 = c(32, 505, 35, 501, 501, 56, 501, 12, 501, 501)
)

df1

现在我想将它们一起重新编码,其中 1:175 = 90、501:508 = 91、509 = 92 和 510 - 93 一次跨列 abc1:abc4。 @akrun 的答案中的“nm1”如何设置在这里。有没有更简单的方法来做到这一点?谢谢!

【问题讨论】:

    标签: r dataframe dplyr recode


    【解决方案1】:

    一个更简单的选择是匹配一个命名向量

    library(dplyr)
    nm1 <- setNames(rep(c(91, 92, 93), c(8, 1, 1)), 501:510)
    df1 <- df %>%
         mutate(across(abc1:abc4, ~  nm1[as.character(.x)]))
    

    -输出

    df1
       id_number age abc1 abc2 abc3 abc4
    1          1  10   91   91   91   91
    2          2  11   91   91   91   91
    3          3  12   91   91   91   91
    4          4  13   91   91   91   91
    5          5  14   91   91   93   91
    6          6  15   91   91   91   91
    7          7  16   91   91   93   91
    8          8  17   91   91   91   91
    9          9  18   92   91   91   91
    10        10  19   93   91   91   91
    

    命名向量的使用也适用于recode

    df %>% 
       mutate(across(abc1:abc4, ~ recode(., !!!  nm1)))
    

    -输出

       id_number age abc1 abc2 abc3 abc4
    1          1  10   91   91   91   91
    2          2  11   91   91   91   91
    3          3  12   91   91   91   91
    4          4  13   91   91   91   91
    5          5  14   91   91   93   91
    6          6  15   91   91   91   91
    7          7  16   91   91   93   91
    8          8  17   91   91   91   91
    9          9  18   92   91   91   91
    10        10  19   93   91   91   91
    

    对于更新的情况,我们可以使用 rep 扩展命名向量

    nm2 <- setNames(rep(c(90, 91, 92, 93), c(175, 8, 1, 1)), c(1:175, 501:510))
    df1 %>%
          mutate(across(abc1:abc4, ~  nm2[as.character(.x)]))
       id_number age abc1 abc2 abc3 abc4
    1          1  10   90   91   90   90
    2          2  11   90   91   91   91
    3          3  12   90   91   90   90
    4          4  13   91   91   91   91
    5          5  14   91   90   93   91
    6          6  15   91   91   90   90
    7          7  16   91   91   93   91
    8          8  17   91   90   91   90
    9          9  18   92   91   90   91
    10        10  19   93   90   91   91
    

    或者使用相同的向量,然后用case_when创建条件

    df1 %>% 
       mutate(across(abc1:abc4, ~ case_when(. %in% 1:175 ~ 90, 
           TRUE ~ nm1[as.character(.)])))
        id_number age abc1 abc2 abc3 abc4
    1          1  10   90   91   90   90
    2          2  11   90   91   91   91
    3          3  12   90   91   90   90
    4          4  13   91   91   91   91
    5          5  14   91   90   93   91
    6          6  15   91   91   90   90
    7          7  16   91   91   93   91
    8          8  17   91   90   91   90
    9          9  18   92   91   90   91
    10        10  19   93   90   91   91
    

    【讨论】:

    • 谢谢@akrun。工作完美!您能否解释一下我在原始代码中选择值 501:508 时的错误?
    • @rais 根据?recodeThis is a vectorised version of switch():switch 寻找完全匹配。反引号要求它从字面上搜索不存在的字符串“501:508”并且它没有进行序列评估
    • 哦,有道理。这很有帮助。再次感谢您!
    • 你能帮我解决我在我的 OP 中添加的后续问题吗?谢谢
    • 谢谢!你能解释一下使用“as.character”的理由吗?
    【解决方案2】:

    另一个dplyr 选项

    > df %>%
    +   mutate(across(abc1:abc4, ~ 90 + as.integer(cut(., c(500, 508, 509, 510)))))
       id_number age abc1 abc2 abc3 abc4
    1          1  10   91   91   91   91
    2          2  11   91   91   91   91
    3          3  12   91   91   91   91
    4          4  13   91   91   91   91
    5          5  14   91   91   93   91
    6          6  15   91   91   91   91
    7          7  16   91   91   93   91
    8          8  17   91   91   91   91
    9          9  18   92   91   91   91
    10        10  19   93   91   91   91
    

    遵循与上述类似想法的基本 R 选项

    idx <- startsWith(names(df), "abc")
    df[idx] <- 90 + as.integer(cut(unlist(df[idx]), c(500, 508, 509, 510)))
    

    给予

    > df
       id_number age abc1 abc2 abc3 abc4
    1          1  10   91   91   91   91
    2          2  11   91   91   91   91
    3          3  12   91   91   91   91
    4          4  13   91   91   91   91
    5          5  14   91   91   93   91
    6          6  15   91   91   91   91
    7          7  16   91   91   93   91
    8          8  17   91   91   91   91
    9          9  18   92   91   91   91
    10        10  19   93   91   91   91
    

    【讨论】:

    • 那个`+cut()`选项很棒。
    • @MartinGal 哈哈,谢谢。这只是在玩数学把戏:P
    • 谢谢@ThomasIsCoding。考虑它的好方法:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-23
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 2014-07-23
    相关资源
    最近更新 更多