R语言如何按id分组将多列正值拆分为独立多行
R实现多列1值拆分为独热独立行方案
针对tibble中每行多个列取值为1、需要拆分为每行仅保留一个1值列其余置0的需求,最简洁的实现基于tidyverse工具链完成,代码可直接运行得到预期结果:
library(tidyverse) # 示例输入数据 dat <- tibble(id = 1:4, col1 = c(0, 1, 1, 0), col2 = c(1, 0, 1, 0), col3 = c(1, 1, 0, 1)) # 核心处理代码 result <- dat %>% pivot_longer(cols = starts_with("col"), names_to = "col_name", values_to = "val") %>% filter(val == 1) %>% pivot_wider(names_from = col_name, values_from = val, values_fill = 0) %>% select(id, col1, col2, col3)
运行后输出结果和预期完全一致:
> result # A tibble: 7 × 4 id col1 col2 col3 <dbl> <dbl> <dbl> <dbl> 1 1 0 1 0 2 1 0 0 1 3 2 1 0 0 4 2 0 0 1 5 3 1 0 0 6 3 0 1 0 7 4 0 0 1
处理逻辑拆解
- 宽表转长表:将
col1/col2/col3三个指标列的列名、取值拉平为长结构,原本一行多列的记录会拆分为「id+单个列名+对应取值」的多行条目 - 过滤零值行:仅保留取值为1的记录,也就是每个id下原本为正值的列对应条目
- 长表转回宽表:将过滤后的长表恢复为原表的列结构,没有匹配值的列通过
values_fill = 0自动补0,自然实现每行仅一个列为1、其余同组列置0的效果 - 调整列顺序:将输出列顺序和原始输入表对齐,保证格式统一
如果不想依赖tidyverse包,也可以用base R实现相同效果:
# base R 实现方案 col_vars <- grep("^col", names(dat), value = TRUE) res_list <- apply(dat, 1, function(row) { id_val <- row[["id"]] one_cols <- names(which(row[col_vars] == 1)) t(sapply(one_cols, function(oc) { new_row <- setNames(rep(0, length(col_vars)), col_vars) new_row[oc] <- 1 c(id = id_val, new_row) })) }) result <- as_tibble(do.call(rbind, res_list))
内容的提问来源于stack exchange,提问作者Maël
相关产品推荐
相关产品推荐

