将数值变量分类为组/箱/分段。

32
我想把一个数值变量(年龄)按照一定的区间划分为不连续的组别。我有下面这段代码:
data$agegrp(data$age >= 40 & data$age <= 49) <- 3
data$agegrp(data$age >= 30 & data$age <= 39) <- 2
data$agegrp(data$age >= 20 & data$age <= 29) <- 1

上述代码在survival包下无法运行。它给出了以下错误:

invalid function in complex assignment

能否指出错误在哪里?data是我正在使用的数据框。


4
使用 [ 进行子集选取,而不是使用 ( - Roland
3
您需要使用的函数是 cut - joran
@joan,你能演示一下如何使用cut命令吗? - leian
答案取决于你想要什么结果?a)只是一个整数(或NA)b)因子标签或实际上c)二分/虚拟变量的数组?findInterval()只能做第一个,而cut()两者都可以。findInterval()更快(O(log(no. of bins))),尽管这很少是问题。 - smci
4个回答

57

我会在这里使用findInterval()

首先,准备一些示例数据

set.seed(1)
ages <- floor(runif(20, min = 20, max = 50))
ages
# [1] 27 31 37 47 26 46 48 39 38 21 26 25 40 31 43 34 41 49 31 43

使用findInterval()对你的“ages”向量进行分类。

findInterval(ages, c(20, 30, 40))
# [1] 1 2 2 3 1 3 3 2 2 1 1 1 3 2 3 2 3 3 2 3

另外,如评论中所建议,cut()在这里也很有用:

cut(ages, breaks=c(20, 30, 40, 50), right = FALSE)
cut(ages, breaks=c(20, 30, 40, 50), right = FALSE, labels = FALSE)

@leian,你试过这段代码了吗?它应该是可以的。但是,在这里提问时最好包含一个最小化的可重现示例,以获取更有针对性的帮助。[https://dev59.com/eG025IYBdhLWcg3whGSx] - A5C1D2H2I1M1N2O1R2T1
但是这个findInterval()的结果变量名将会是什么? - leian
你想要它成为什么,就让它成为什么!从你的例子中,我会做类似于 data$agegrp <- findInterval(data$age, c(20, 30, 40)) 的操作。 - A5C1D2H2I1M1N2O1R2T1

29

我们可以使用 dplyr

library(dplyr)

data <- data %>% mutate(agegroup = case_when(age >= 40  & age <= 49 ~ '3',
                                             age >= 30  & age <= 39 ~ '2',
                                             age >= 20  & age <= 29 ~ '1')) # end function

与其他方法相比,dplyr 更易于编写和解释。


10
你也可以在 mutate 中使用 cut,而不是 case_when。例如:data %>% mutate(agegroup = cut(ages, breaks = c(20, 30, 40, 50), right = T, labels = F)) - stlba
@stlba 这是一个非常好的答案,非常感谢。labels=TRUE甚至会给出合理的标签。 - Ian

16

本答案提供了两种使用 data.table 包解决问题的方法,这将极大地提高处理速度。如果处理大型数据集,则这一点至关重要。

第一种方法:对之前答案的改编,现在使用data.table + 包括labels

library(data.table)

agebreaks <- c(0,1,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,500)
agelabels <- c("0-1","1-4","5-9","10-14","15-19","20-24","25-29","30-34",
               "35-39","40-44","45-49","50-54","55-59","60-64","65-69",
               "70-74","75-79","80-84","85+")

setDT(data)[ , agegroups := cut(age, 
                                breaks = agebreaks, 
                                right = FALSE, 
                                labels = agelabels)]

第二种方法:这是一种更为冗长的方法,但它也更清晰地说明了每个年龄组包含哪些内容:

setDT(data)[age <1, agegroup := "0-1"]
data[age >0 & age <5, agegroup := "1-4"]
data[age >4 & age <10, agegroup := "5-9"]
data[age >9 & age <15, agegroup := "10-14"]
data[age >14 & age <20, agegroup := "15-19"]
data[age >19 & age <25, agegroup := "20-24"]
data[age >24 & age <30, agegroup := "25-29"]
data[age >29 & age <35, agegroup := "30-34"]
data[age >34 & age <40, agegroup := "35-39"]
data[age >39 & age <45, agegroup := "40-44"]
data[age >44 & age <50, agegroup := "45-49"]
data[age >49 & age <55, agegroup := "50-54"]
data[age >54 & age <60, agegroup := "55-59"]
data[age >59 & age <65, agegroup := "60-64"]
data[age >64 & age <70, agegroup := "65-69"]
data[age >69 & age <75, agegroup := "70-74"]
data[age >74 & age <80, agegroup := "75-79"]
data[age >79 & age <85, agegroup := "80-84"]
data[age >84, agegroup := "85+"]

虽然这两种方法应该得到相同的结果,但我更喜欢第一种方法,有两个原因。(a)它更短,(2) 年龄组以正确的方式排序,在可视化数据时是至关重要的。


第二种方法似乎在R 3.2中无法工作。它会出现错误,找不到函数“:=”。 - Akshay Hazari
3
对我来说很有效。确保加载 data.tablelibrary(data.table);并且你正在使用 data.table(而不是数据框)setDT(your_dataframe) # 将你的 DF 转换为 data.table - rafa.pereira

4
假设你的年龄数据存储在名为 age 的数据框列中。你的数据框是 df,你想要一个新的列 age_grouping 来包含您年龄所属的“组”。
在这个例子中,假设你的年龄范围从0到100岁,你想按照每10年分组。以下代码将通过将这些区间存储在新的age grouping列中来实现:
df$age_grouping <- cut(df$age, seq(0, 100, 10))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接