如何为R的pivot_longer设置names_pattern实现宽表转长表?
问题:嵌套宽格式数据转长格式的pivot_longer参数设置
我有如下嵌套结构的宽格式数据框,希望使用R语言的pivot_longer函数将其转换为指定结构的长格式数据框,提取出variable、x和freq字段,请问应使用何种names_pattern参数?
源数据框结构:
structure(list(or = c(0, 0, 1, 1, 0, 0), agegrp = structure(list( x = c("<65", ">=65", "<65", ">=65", "<65", ">=65"), freq = c(10L, 16L, 6L, 6L, 9L, 14L)), class = "data.frame", row.names = c(NA, -6L)), asian = structure(list(x = c(0, 1, 0, 1, 0, 1), freq = c(15L, 11L, 4L, 8L, 13L, 10L)), class = "data.frame", row.names = c(NA, -6L)), SEX = structure(list(x = c("Female", "Male", "Female", "Male", "Female", "Male"), freq = c(7L, 19L, 6L, 6L, 10L, 13L )), class = "data.frame", row.names = c(NA, -6L))), row.names = c(NA, -6L), class = c("tbl_df", "tbl", "data.frame"))
期望得到的长表结构:
or variable x freq 1 agegrp <65 6 1 agegrp >=65 6 1 asian 0 4 1 asian 1 8 1 SEX Female 6 1 SEX Male 6
解决方案
针对这种嵌套列的宽格式数据,可通过pivot_longer的参数组合实现转换,关键是利用names_pattern匹配嵌套列结构,具体代码如下:
library(tidyr) library(dplyr) # 加载源数据 df <- structure(list(or = c(0, 0, 1, 1, 0, 0), agegrp = structure(list( x = c("<65", ">=65", "<65", ">=65", "<65", ">=65"), freq = c(10L, 16L, 6L, 6L, 9L, 14L)), class = "data.frame", row.names = c(NA, -6L)), asian = structure(list(x = c(0, 1, 0, 1, 0, 1), freq = c(15L, 11L, 4L, 8L, 13L, 10L)), class = "data.frame", row.names = c(NA, -6L)), SEX = structure(list(x = c("Female", "Male", "Female", "Male", "Female", "Male"), freq = c(7L, 19L, 6L, 6L, 10L, 13L )), class = "data.frame", row.names = c(NA, -6L))), row.names = c(NA, -6L), class = c("tbl_df", "tbl", "data.frame")) # 转换为长格式 long_df <- df %>% pivot_longer( cols = -or, # 保留or列,其余列转为长格式 names_to = "variable", # 外层列名作为variable字段 values_to = c("x", "freq"), # 嵌套的x和freq对应目标字段 names_pattern = "(.*)" # 捕获外层列的完整名称 ) %>% filter(or == 1) # 筛选出or=1的行,匹配期望结果 # 查看结果 print(long_df)
参数说明:
cols = -or:指定除or列外,所有列参与格式转换。names_to = "variable":将原外层列名(agegrp、asian、SEX)赋值给新字段variable。values_to = c("x", "freq"):每个嵌套列都包含x和freq子字段,直接指定这两个作为目标字段,pivot_longer会自动匹配嵌套列中的同名子字段。names_pattern = "(.*)":正则表达式匹配外层列的完整名称,因为只需要提取外层列名作为variable,用(.*)捕获全部内容即可。
运行代码后即可得到目标长格式数据框,最后通过filter(or == 1)筛选出指定行。
内容的提问来源于stack exchange,提问作者user2272972
相关产品推荐
相关产品推荐

