选择大范围的值在 R 中重新编码

Selecting a large range of values to recode in R

我想跨多个列重新编码大量变量。这是一个例子 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 由带有 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”将如何在此处设置。有没有更简单的方法来做到这一点?谢谢!

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

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

另一个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