【问题标题】:Change multiple values with ifelse in tidyverse在 tidyverse 中使用 ifelse 更改多个值
【发布时间】:2024-05-18 02:35:02
【问题描述】:

我有一个包含 20.000 个观察值和 5 个变量的数据集。现在我想在一些特定的观察中只改变一个变量。我知道我可以像这样对每一行都这样做:

test_data <- test_data%>%
  mutate(change_variable=ifelse(n=="1000","changevalue",changevariable))

我现在的问题是我需要像这样更改 500 个 Obersvations。有没有可能使这个过程自动化而不是编写 500 行的代码?每次更改相同的变量时,我在连接到正确的“n”值的数据框中都有该变量的正确值。

我希望你们中的某个人可以帮助我。

亲切的问候, 汤姆

【问题讨论】:

  • 正如@akrun 提到的,您应该发布一个可重现的示例。从您的问题中不清楚更改列中值的逻辑是什么。
  • 请考虑接受其中一个答案,谢谢。

标签: r if-statement dplyr tidyverse


【解决方案1】:

您可以在基本 R ifelse 语句中引用测试向量。每个测试将使用测试向量的行索引号。例如

cars$cyl (cars = mtcars) 生成一个测试向量,并针对每个cars$cyl 条目对其进行测试。将测试结果分配给cars$test进行检查。

cars <- mtcars
testvec <- sample(c(4, 6, 8), 32, replace = TRUE)
cars$test <- ifelse(cars$cyl == testvec, 'match', 'no match')
cars <- cbind(cars, testvec)
head(cars, 10)
                   mpg cyl  disp  hp drat    wt  qsec vs am gear carb     test testvec
Mazda RX4         21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4 no match       8
Mazda RX4 Wag     21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4 no match       8
Datsun 710        22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1    match       4
Hornet 4 Drive    21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1 no match       4
Hornet Sportabout 18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2 no match       4
Valiant           18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1 no match       4
Duster 360        14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4    match       8
Merc 240D         24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2 no match       6
Merc 230          22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2 no match       8
Merc 280          19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4 no match       8

【讨论】:

    【解决方案2】:

    我认为这可能是一个“加入”(合并)操作。

    library(dplyr)
    set.seed(2)
    mt <- sample_n(mtcars, 6)
    mt
    #                     mpg cyl  disp  hp drat    wt  qsec vs am gear carb
    # Toyota Corona      21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
    # Cadillac Fleetwood 10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
    # Valiant            18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
    # Ferrari Dino       19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
    # Merc 240D          24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
    # Chrysler Imperial  14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
    newgears <- data.frame(gear = c(2, 3, 4), newgear = c(22, 33, 44))
    newgears
    #   gear newgear
    # 1    2      22
    # 2    3      33
    # 3    4      44
    

    前提是您有一帧具有从原始值 (gear) 到新值 (newgear) 的映射。并非所有现有的gear 值都需要存在于newgears 中(我们会处理),如果在这个新框架中有额外的gear 值也不会有问题,因为它们将被忽略。

    有了这个,

    left_join(mt, newgears, by = "gear")
    #    mpg cyl  disp  hp drat    wt  qsec vs am gear carb newgear
    # 1 21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1      33
    # 2 10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4      33
    # 3 18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1      33
    # 4 19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6      NA
    # 5 24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2      44
    # 6 14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4      33
    

    由此,请注意我们有一个gear 值未映射到newgear。这是可以预料的,也是正常的,我们只需要考虑它。在我们的例子中,我们将coalescenewgear 然后gear;它的作用是使用newgear,除非它是NA,在这种情况下使用gear

    left_join(mt, newgears, by = "gear") %>%
      mutate(gear = coalesce(newgear, gear)) %>%
      select(-newgear)
    #    mpg cyl  disp  hp drat    wt  qsec vs am gear carb
    # 1 21.5   4 120.1  97 3.70 2.465 20.01  1  0   33    1
    # 2 10.4   8 472.0 205 2.93 5.250 17.98  0  0   33    4
    # 3 18.1   6 225.0 105 2.76 3.460 20.22  1  0   33    1
    # 4 19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
    # 5 24.4   4 146.7  62 3.69 3.190 20.00  1  0   44    2
    # 6 14.7   8 440.0 230 3.23 5.345 17.42  0  0   33    4
    

    我相信使用映射框架(此处为newgears)更容易维护和可视化,更不用说代码和在多种方式和地方使用。

    【讨论】:

    • 对不起伙计们,我是新来的,我想正因为如此,我很难以一种好的方式描述我的问题。这个解决方案对我有用。非常感谢!!
    【解决方案3】:

    如果我们只需要针对特定​​观察进行更改,请使用row_number()%in% 创建逻辑表达式。如果“changevalue”特定于前 500 个观察值,请将其创建为列

    library(dplyr)
    test_data$changevalue[1:500] <- vector_of_values
    test_data <- test_data %>%
       mutate(change_variable = ifelse(
             row_number() %in% 1:500, changevalue, changevariable))
    

    或者这也可以使用coalesce 来完成

    test_data %>%
        mutate(change_variable = coalesce(changevalue, changevariable))
    

    或者可以使用between

    test_data %>%
       mutate(change_variable = ifelse(between(row_number(), 1, 500),
            changevalue, changevariable))
    

    【讨论】:

    • 对不起,也许我需要说得更清楚。我在数据框中有 500 个不同值的 500 个观察数据。使用这种方法,我会给每个观察值赋予相同的值,不是吗?但我需要给每一行他特定的“changevalue”
    • @Sylababa 我请求您用一个可重复的小示例和预期的输出来更新您的帖子,以便它变得更加清晰。你的评论我不清楚。如果有特定的changevalue,为什么不能在数据中创建一个“changevalue”列并在将“changevlaue”更改为changevalue列后使用ifelse,就像这里一样
    • 一种处理此问题的方法,将您的数据框拆分为无需更正的部分以及需要更正的部分(即您的 500 行)。然后只需创建一个长度为 500 的向量,其中包含您需要替换/覆盖的值。更正后,您可以再次组合数据框。如果需要确保顺序,在拆分前将 row_number() 分配给列。在 bind_rows 之后,您可以按此列排序以获得旧的“顺序”。