使用基于另一列的分组值创建列

时间:2015-01-12 13:14:12

标签: r if-statement dplyr

我确定之前已经问过,但我不知道要搜索什么,所以我提前道歉。

假设我有以下数据框:

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

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

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

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

和rbind a,b,c等等。显然,这不是我想要的方式,但我想理解ifelse()的语法。我猜测后者是有效的,因为没有任何值不符合标准,但是当有多个ifelse时,我仍然无法弄清楚如何让它工作。

3 个答案:

答案 0 :(得分:15)

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

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)

注意

在仔细研究了您的初始方法之后,我注意到您需要在right = FALSE电话中加入cut,因为例如,90分应该是“优秀的”,而不仅仅是“很好”。因此,它用于定义间隔应该关闭的位置(左侧或右侧),默认值位于右侧,这与OP的初始方法略有不同。所以在dplyr中,它将是:

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

因此在其他选项中。

答案 1 :(得分:5)

所有ifelse都需要在彼此之内。试试这个:

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

答案 2 :(得分:0)

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"