R语言数据框操作:根据行值为对应行赋值1
问题与需求
原数据框定义如下:
id <- c(1001, 1002) col2 <- c(5, 2) col3 <- c(1, 4) df <- data.frame(id, col2, col3)
需要将其转换为新数据框,满足:
- 每个
id重复固定行数(此处为5行,等于原数据中所有列的最大值) - 对
col2、col3这类列,在对应id分组内的第n行(n为原数据框中该id对应列的数值)标记为1,其余行标记为0 - 保留原列名,最终结果如下:
id <- c(rep(1001, 5), rep(1002, 5)) col2 <- c(0,0,0,0,1, 0,1,0,0,0) col3 <- c(1,0,0,0,0,0,0,0,1,0) df_results <- data.frame(id, col2, col3)
实现方案
方法一:使用tidyverse(推荐,灵活易扩展)
先加载依赖包,再通过管道操作完成转换:
library(tidyverse) df_results <- df %>% group_by(id) %>% # 为每个id生成1到最大列值的行号列表 mutate(row_num = list(1:max(c_across(col2:col3)))) %>% unnest(row_num) %>% # 逐列判断行号是否等于原列值,转换为0/1 mutate(across(col2:col3, ~as.integer(row_num == .x))) %>% select(-row_num) %>% ungroup()
方法二:使用Base R(无需外部包)
如果不想加载第三方包,可通过基础函数实现:
# 定义每个id需要重复的行数(此处取原数据中所有列的最大值) n_rows <- max(df[, -1]) # 生成id列 id_col <- rep(df$id, each = n_rows) # 生成col2和col3的0/1向量 col2_vec <- unlist(lapply(df$col2, function(x) as.integer(1:n_rows == x))) col3_vec <- unlist(lapply(df$col3, function(x) as.integer(1:n_rows == x))) # 组合成结果数据框 df_results <- data.frame(id = id_col, col2 = col2_vec, col3 = col3_vec)
两种方法都能得到目标结果,tidyverse方案更适合后续列数增加的场景,只需调整col2:col3的列范围即可;Base R方案则更轻量化。
内容的提问来源于stack exchange,提问作者Zipsa
相关产品推荐
相关产品推荐

