R使用if语句改变多列

标签 r if-statement dplyr

我有这样的数据:

cols <- c("X01_01","X01_01_p", "X01_02","X01_02_p", "X01_03","X01_03_p", "X01_04", "X01_05","X01_06")
set.seed(111)
values <- replicate(9, sample(1:5, 4, replace = TRUE)) 
df <- as.data.frame(values)  

所以我的 df 看起来像这样:

    X01_01 X01_01_p X01_02 X01_02_p X01_03 X01_03_p X01_04 X01_05 X01_06
1      3        2      3        1      1        3      5      4      3
2      4        3      1        1      5        2      2      3      3
3      2        1      3        1      2        2      4      1      2
4      3        3      3        3      4        2      2      3      4

我有一些列用于突变(不是全部)以及新列的名称。

cols_to_mutate <- c("X01_01_p","X01_02_p", "X01_03_p", "X01_04", "X01_05","X01_06")
new_cols <- c("X01_01_n","X01_02_n", "X01_03_n", "X01_04_n", "X01_05_n","X01_06_n")

每个突变都是相同的:

  • 如果值为 1 或 2,则新值必须为 0
  • 如果值为 3,则新值必须为 0.5
  • 如果值为 4 或 5,则新值必须为 1

最终我的 df 看起来像这样:

    X01_01 X01_01_p X01_02 X01_02_p X01_03 X01_03_p X01_04 X01_05 X01_06 X01_01_n X01_02_n X01_03_n X01_04_n X01_05_n X01_06_n
1      3        2      3        1      1        3      5      4      3      0.0      0.0      0.5        1      1.0      0.5
2      4        3      1        1      5        2      2      3      3      0.5      0.0      0.0        0      0.5      0.5
3      2        1      3        1      2        2      4      1      2      0.0      0.0      0.0        1      0.0      0.0
4      3        3      3        3      4        2      2      3      4      0.5      0.5      0.0        0      0.5      1.0

在“硬编码”中,我可以写很多这样的行:

df <- mutate(df, X01_01_n = ifelse(X01_01_p <= 2, 0, (ifelse(X01_01_p == 3, 0.5, 1))))
df <- mutate(df, X01_02_n = ifelse(X01_02_p <= 2, 0, (ifelse(X01_02_p == 3, 0.5, 1))))

但是,我当然正在寻找一种更奇特、更快的方法来做到这一点,但我搜索了又搜索,但没有找到解决方案。我尝试过:

df <- cbind(df,apply(df[,cols_to_mutate],2, function(x) if (x < 3) { 0} else if (x > 3) {1} else {.5}))

但这不起作用。任何想法都会很棒!!

最佳答案

如果保留前面的列并进行变异并不重要,则可以在用于变异的函数内使用 mutate_atcase_when

case_when 正在利用 dplyr 中的 Between 函数来设置条件,然后用 ~ 赋值>。最后一个参数 T ~ NA_real_NA 分配给与任何条件都不匹配的任何观测值。

library(tidyverse)

cols_to_mutate <- c("X01_01_p","X01_02_p", "X01_03_p", "X01_04", "X01_05","X01_06")

df %>%
  mutate_at(cols_to_mutate, function(x) {
    case_when(
      between(x, 1, 2) ~ 0,
      x == 3 ~ 0.5,
      between(x, 4, 5) ~ 1,
      T ~ NA_real_
    )
  })
#>   X01_01 X01_01_p X01_02 X01_02_p X01_03 X01_03_p X01_04 X01_05 X01_06
#> 1      3      0.0      3      0.0      1      0.5      1    1.0    0.5
#> 2      4      0.5      1      0.0      5      0.0      0    0.5    0.5
#> 3      2      0.0      3      0.0      2      0.0      1    0.0    0.0
#> 4      3      0.5      3      0.5      4      0.0      0    0.5    1.0

如果有必要保留原始列并为重新缩放的列指定新名称,这里有一些 rlang + purrr 技巧。我所做的是对数据框的列进行 imap 处理。如果名称位于要变异的列列表中,我使用与上面相同的 case_when ,并输出一个包含两列的 tibble:一列是原始列,其使用 quo_name:= 运算符分配的名称,另一个是新值列,名称相同但附加了 _n。如果它不是要改变的列,它只返回原始列的 tibble 。通过使用 imap_dfc,所有列都重新绑定(bind)到一个数据帧中。

df %>%
  imap_dfc(function(x, name) {
    if (name %in% cols_to_mutate) {
      new_vals <- case_when(
        between(x, 1, 2) ~ 0,
        x == 3 ~ 0.5,
        between(x, 4, 5) ~ 1,
        T ~ NA_real_
      )
      tibble(!!quo_name(name) := x, !!quo_name(paste0(name, "_n")) := new_vals)
    } else {
      tibble(!!quo_name(name) := x)
    }
  })
#> # A tibble: 4 x 15
#>   X01_01 X01_01_p X01_01_p_n X01_02 X01_02_p X01_02_p_n X01_03 X01_03_p
#>    <int>    <int>      <dbl>  <int>    <int>      <dbl>  <int>    <int>
#> 1      3        2        0        3        1        0        1        3
#> 2      4        3        0.5      1        1        0        5        2
#> 3      2        1        0        3        1        0        2        2
#> 4      3        3        0.5      3        3        0.5      4        2
#> # ... with 7 more variables: X01_03_p_n <dbl>, X01_04 <int>,
#> #   X01_04_n <dbl>, X01_05 <int>, X01_05_n <dbl>, X01_06 <int>,
#> #   X01_06_n <dbl>

关于R使用if语句改变多列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50914681/

相关文章:

python - rpy2 中的 fitdistr

C#如何检查if语句的哪一部分是正确的

r - 带有百分比标签的 Ggplot 堆积条形图

r - 如何按年份统计分组负值

r - 合并具有多个分隔符的列

R:从深度嵌套的 XML 文件中将 XML 节点值提取到数据帧中

r - 如何分配r中向量的一半

MySQL IF...THEN 语法错误

c++ - 如何在 C++ 中执行先前执行的代码行

基于跨多个变量的查找表重新编码