R语言中按隔列规则重塑宽格式数据框的技术咨询
解决宽格式成对测试数据的整理问题
嘿,我太懂你现在的困扰了——这种把同一患者的多次测试用成对连续列存储的格式,处理起来确实很别扭。咱们直接用R里的tidyverse工具来把它转成更易用的长格式,一步到位!
首先先把你给出的示例数据明确下来,方便后续操作:
df1 <- data.frame( id = c("A","B"), test1 = c("10-12-16", "12-10-17"), test1_result = c("20", "3"), test2 = c("10-01-17", "11-12-17"), test2_result = c("18", "4"), test3 = c("12-03-18", NA), test3_result = c("15", "NA"), stringsAsFactors = FALSE )
核心解决方案:用pivot_longer转长格式
tidyverse里的pivot_longer函数专门处理这种宽转长的场景,尤其是这种有规律的成对列名。咱们可以用正则表达式匹配列名里的测试编号,把日期和结果对应起来:
library(tidyverse) df_long <- df1 %>% pivot_longer( cols = -id, # 除了id列之外的所有列都要转换 names_to = c("test_number", ".value"), # 把列名拆成两部分:测试编号,以及值的类型(日期/结果) names_pattern = "test(\\d+)_(.*)|test(\\d+)" # 正则匹配:要么是testN_result,要么是testN ) %>% # 统一测试编号的列名(合并正则生成的两个临时列) mutate(test_number = coalesce(test_number, `test(\\d+)`)) %>% select(-`test(\\d+)`) %>% # 重命名日期列,让它更直观 rename(test_date = test) %>% # 把结果转成数值型(按需选择) mutate(test_result = as.numeric(test_result))
运行完这段代码后,你得到的df_long就是标准的长格式了,每一行对应一个患者的一次测试记录,结构大概是这样:
# A tibble: 6 × 4 id test_number test_date test_result <chr> <chr> <chr> <dbl> 1 A 1 10-12-16 20 2 A 2 10-01-17 18 3 A 3 12-03-18 15 4 B 1 12-10-17 3 5 B 2 11-12-17 4 6 B 3 NA NA
额外说明
- 如果你的测试列名有更复杂的规律,只需要调整
names_pattern里的正则表达式就行,核心是把测试的标识和值的类型区分开。 - 如果想过滤掉测试日期或结果为NA的记录,可以在管道最后加
filter(!is.na(test_date), !is.na(test_result))。 - 要是你还在使用旧版本的tidyverse,也可以用
gather函数,但pivot_longer的可读性和灵活性更强,更推荐使用。
内容的提问来源于stack exchange,提问作者r_mvl
相关产品推荐
相关产品推荐

