如何将多列身高体重数据转换为结构化表格并生成appt_num列?
问题描述
需要将如下原始表格:
| record_id | height_1 | height_1_v1 | height_1_v1_v1 | weight_1 | weight_1_v1 | weight_1_v1_v1 |
|---|---|---|---|---|---|---|
| 10 | NA | NA | 5ft6in | NA | NA | 154 |
| 10 | 5ft6in | NA | NA | 152 | NA | NA |
| 10 | NA | 5ft6in | NA | NA | 131 | NA |
| 11 | NA | NA | 5.11 | NA | NA | 138 |
| 11 | NA | 5.11 | NA | NA | 131 | NA |
转换为目标结构的表格:
| record_id | appt_num | height | weight |
|---|---|---|---|
| 10 | 1 | 5ft6in | 152 |
| 10 | 2 | 5ft6in | 153 |
| 10 | 3 | 5ft6in | 154 |
| 11 | 1 | 5.11 | 131 |
| 11 | 2 | 5.11 | 138 |
尝试过pivot_longer()、gather()未成功,用coalesce()接近目标但无法生成appt_num列,求实现方法。
解决方案
可以通过拆分列名分组+重塑数据的方式实现,核心是用pivot_longer拆分出测量类型和预约序号,再整理有效数据并生成appt_num:
library(tidyverse) # 模拟原始数据 df <- tibble( record_id = c(10,10,10,11,11), height_1 = c(NA, "5ft6in", NA, NA, NA), height_1_v1 = c(NA, NA, "5ft6in", NA, "5.11"), height_1_v1_v1 = c("5ft6in", NA, NA, "5.11", NA), weight_1 = c(NA, 152, NA, NA, NA), weight_1_v1 = c(NA, NA, 153, NA, 131), weight_1_v1_v1 = c(154, NA, NA, 138, NA) ) # 数据转换步骤 result <- df %>% # 把所有height/weight列转为长格式,拆分列名为测量类型和版本号 pivot_longer( cols = -record_id, names_to = c("measure", "version"), names_pattern = "(height|weight)_(.*)", values_drop_na = TRUE ) %>% # 给每个record_id+measure分组,计算预约序号 group_by(record_id, measure) %>% # 通过统计版本号中"v"的数量+1,生成连续的appt_num mutate(appt_num = dense_rank(str_count(version, "v") + 1)) %>% ungroup() %>% # 转回宽格式,拆分出height和weight列 pivot_wider( id_cols = c(record_id, appt_num), names_from = measure, values_from = value ) %>% # 按record_id和appt_num排序 arrange(record_id, appt_num)
代码解释
- 第一步
pivot_longer:将所有height/weight相关列转为长格式,用正则names_pattern拆分出测量类型(height/weight)和版本标识(1、1_v1等),同时自动过滤NA值。 - 生成
appt_num:按record_id和measure分组,通过统计版本标识中"v"的数量+1,得到对应的预约序号,再用dense_rank确保序号连续无断层。 - 第二步
pivot_wider:将长格式的测量类型列重新拆分为height和weight列,最终得到目标结构。
内容的提问来源于stack exchange,提问作者ktbkr
相关产品推荐
相关产品推荐

