如何用dplyr对分组数值变量按动态断点生成分类变量
基于外部分组断点用dplyr创建分类变量
这个需求很实用,尤其是当你需要根据业务规则(而非组内统计量)给不同分组的数值变量做分箱时,我们可以通过整理断点数据框+连接数据集+动态分箱这几个步骤来实现,下面结合你的例子详细说明:
第一步:构造并处理外部断点数据
首先,先把你提供的brk对象转换成标准的R数据框,然后将宽格式的断点列转成长格式,去掉缺失值后按分组整理成有序的断点向量列表:
library(tidyverse) # 构造你提供的brk数据 brk <- tibble( vs = c(0, 0, 1, 1), am = c(0, 1, 0, 1), breakPoint_1 = c(14.0, 17.0, 19.0, 28.4), breakPoint_2 = c(15.0, 19.0, 21.0, NA), breakPoint_3 = c(17.0, NA, NA, NA) ) # 处理断点:转成长格式,清理NA,按组整理成有序向量列表 brk_processed <- brk %>% pivot_longer( cols = starts_with("breakPoint_"), names_to = NULL, # 不需要保留断点列名 values_to = "breakpoint" ) %>% filter(!is.na(breakpoint)) %>% # 去掉缺失的断点 arrange(vs, am, breakpoint) %>% # 确保断点从小到大排序 group_by(vs, am) %>% summarise(breakpoints = list(breakpoint), .groups = "drop")
第二步:连接数据集并动态分箱
接下来把处理好的断点和mtcars数据集通过分组键vs和am连接,然后用cut()函数结合分组断点给mpg创建分类变量。这里我们用purrr::map2()来处理每个观测对应的断点,灵活性更强:
# 连接数据并创建分类变量 result <- mtcars %>% rownames_to_column("car") %>% # 可选:保留车型名称方便查看 mutate(vs = as.integer(vs), am = as.integer(am)) %>% # 确保分组键类型一致 left_join(brk_processed, by = c("vs", "am")) %>% # 按vs和am连接断点 mutate( mpg_category = map2_chr( .x = mpg, .y = breakpoints, .f = function(x, bp) { # 生成分箱:自动覆盖所有mpg范围(-Inf到Inf),包含断点最小值 cut( x, breaks = c(-Inf, bp, Inf), include.lowest = TRUE, labels = paste0("Level ", seq_along(c(bp, Inf))) # 自动生成对应数量的标签 ) } ) ) %>% ungroup() # 查看结果示例 result %>% select(car, vs, am, mpg, mpg_category)
自定义标签说明
如果你不想用默认的Level 1/2/3这类标签,也可以根据断点数量自定义,比如用case_when()判断断点长度后设置对应的标签:
result_custom <- mtcars %>% rownames_to_column("car") %>% mutate(vs = as.integer(vs), am = as.integer(am)) %>% left_join(brk_processed, by = c("vs", "am")) %>% group_by(vs, am) %>% mutate( mpg_category = case_when( length(breakpoints[[1]]) == 3 ~ cut( mpg, breaks = c(-Inf, breakpoints[[1]], Inf), labels = c("极低油耗", "低油耗", "中油耗", "高油耗"), include.lowest = TRUE ), length(breakpoints[[1]]) == 2 ~ cut( mpg, breaks = c(-Inf, breakpoints[[1]], Inf), labels = c("低油耗", "中油耗", "高油耗"), include.lowest = TRUE ), length(breakpoints[[1]]) == 1 ~ cut( mpg, breaks = c(-Inf, breakpoints[[1]], Inf), labels = c("低油耗", "高油耗"), include.lowest = TRUE ) ) ) %>% ungroup()
这样就能完美实现基于外部分组断点的动态分箱需求啦!
内容的提问来源于stack exchange,提问作者Dra
相关产品推荐
相关产品推荐

