【问题标题】:Create column with grouped values based on another column基于另一列创建具有分组值的列
【发布时间】:2015-03-10 06:26:35
【问题描述】:

我确定以前有人问过这个问题,但我不知道要搜索什么,所以我提前道歉。

假设我有以下数据框:

grades <- data.frame(a = 1:40, b = sample(45:100, 40))

使用 deplyr,我想创建一个新变量来指示学生获得的成绩,基于以下标准:90-100 = 优秀,80-90 = 非常好,等等。

我认为我可以使用以下方法通过在 mutate() 中嵌套 ifelse() 来获得该结果:

grades %>%
mutate(ifelse(b >= 90, "excellent"), 
       ifelse(b >= 80 & b < 90, "very_good"),
       ifelse(b >= 70 & b < 80, "fair"),
       ifelse(b >= 60 & b < 70, "poor", "fail"))

这不起作用,因为我收到错误消息“缺少参数,没有默认值”)。我认为“否”最终会是“失败”,但显然我的语法错误。

如果我先单独过滤原始数据,然后调用ifelse,可以得到这个,如下:

a <- grades %>%
     filter( b >= 90) %>%
     mutate(final = ifelse(b >= 90, "excellent"))

和 rbind a、b、c 等。显然,这不是我想要的,但我想了解 ifelse() 的语法。我猜后者是可行的,因为没有任何值不符合标准,但是当有多个 ifelse 时,我仍然不知道如何让它工作。

【问题讨论】:

  • 你可以使用cut函数来做到这一点

标签: r if-statement dplyr


【解决方案1】:

使用级别和标签定义向量,然后在b 列上使用cut

levels <- c(-Inf, 60, 70, 80, 90, Inf)
labels <- c("Fail", "Poor", "fair", "very good", "excellent")
grades %>% mutate(x = cut(b, levels, labels = labels))
    a   b         x
1   1  66      Poor
2   2  78      fair
3   3  97 excellent
4   4  46      Fail
5   5  89 very good
6   6  57      Fail
7   7  80      fair
8   8  98 excellent
9   9 100 excellent
10 10  93 excellent
11 11  59      Fail
12 12  51      Fail
13 13  69      Poor
14 14  75      fair
15 15  72      fair
16 16  48      Fail
17 17  74      fair
18 18  54      Fail
19 19  62      Poor
20 20  64      Poor
21 21  88 very good
22 22  70      Poor
23 23  85 very good
24 24  58      Fail
25 25  95 excellent
26 26  56      Fail
27 27  65      Poor
28 28  68      Poor
29 29  91 excellent
30 30  76      fair
31 31  82 very good
32 32  55      Fail
33 33  96 excellent
34 34  83 very good
35 35  61      Poor
36 36  60      Fail
37 37  77      fair
38 38  47      Fail
39 39  73      fair
40 40  71      fair

或者使用data.table:

library(data.table)
setDT(grades)[, x := cut(b, levels, labels)]

或者只是在基础 R 中:

grades$x <- cut(grades$b, levels, labels)

注意

在再次仔细查看您的初始方法后,我注意到您需要在cut 调用中包含right = FALSE,因为例如,90 分应该是“优秀”,而不仅仅是“非常好”。所以它用于定义区间应该在哪里闭合(左或右),默认在右边,这与OP的初始做法略有不同。所以在 dplyr 中,它会是:

grades %>% mutate(x = cut(b, levels, labels, right = FALSE))

并相应地在其他选项中。

【讨论】:

  • 谢谢。这可能是一个更优雅的解决方案,但 Andrew Taylor 的回复解释了我原来的解决方案有什么问题。
【解决方案2】:

所有ifelses 都必须在彼此之内。试试这个:

mutate(ifelse(b >= 90, "excellent", 
       ifelse(b >= 80 & b < 90, "very_good",
       ifelse(b >= 70 & b < 80, "fair",
       ifelse(b >= 60 & b < 70, "poor", "fail")))))

【讨论】:

  • 谢谢,我现在明白了。
  • 仅供参考,在 R 中使用多个嵌套的 ifelse 语句是非常低效的方法。我强烈建议使用其他建议的解决方案。
  • 我也同意应该使用 cut 方法,无论是否已通过修复 ifelse 代码来回答。 ifelse 可能非常有用,所以我很高兴你现在能理解它。
  • 我意识到 cut 函数是一种更好的方法。我最初将此标记为答案,因为我了解了为什么会收到错误消息以及如何修复它。但我将另一个答案标记为正确,因为它是解决问题的更好方法。
【解决方案3】:
grades$c = grades$b # creating a new column 
#and filling in the grades
grades$c[grades$c >= 90] = "exellent"
grades$c[grades$c <= 90 &  grades$c >= 80] = "very good"
grades$c[grades$c <= 80 &  grades$c >= 70] = "fair"
grades$c[grades$c <= 70 &  grades$c >= 60] = "poor"
grades$c[grades$c <= 60] = "fail"

【讨论】:

    猜你喜欢
    • 2022-01-23
    • 2021-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多