R用if语句改变多个列

时间:2018-06-18 17:29:01

标签: r if-statement mutate

我有这样的数据:

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

硬编码&#39;我可以写出很多像这样的行:

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}))

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

2 个答案:

答案 0 :(得分:3)

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

case_when正在使用between中的dplyr功能设置条件,然后使用~分配值。最后一个参数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:一列是原始列,其名称使用{{1 }和quo_name运算符,另一个是新值列,名称相同,但附加了:=。如果它不是要变异的列,则只返回原始列的_n。通过使用tibble,所有列都被绑定回一个数据帧。

imap_dfc

答案 1 :(得分:0)

你可以这样做,假设你的数字只取值1到5。

map_marlein <- function(x) {
  if (any(!x %in% 1:5)) {
    stop("Needs numbers from 1-5")
  }
  as.integer(cut(x, c(0,2,3, 10))) / 2 - 0.5
}

df[, paste0(names(df), "_n")] <- lapply(df[, names(df)], map_marlein)
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_01_p_n X01_02_n X01_02_p_n X01_03_n X01_03_p_n X01_04_n X01_05_n X01_06_n
1      3        2      3        1      1        3      5      4      3      0.5        0.0      0.5        0.0        0        0.5        1      1.0      0.5
2      4        3      1        1      5        2      2      3      3      1.0        0.5      0.0        0.0        1        0.0        0      0.5      0.5
3      2        1      3        1      2        2      4      1      2      0.0        0.0      0.5        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.5        0.5        1        0.0        0      0.5      1.0