如何用R语言函数(如pivot_longer)将调查宽表转为多类型列整洁长表?
解决家庭调查宽表转长表的问题(支持多数据类型)
你提到的pivot_longer完全可以生成包含不同类型列的tidy dataframe,无需逐个处理问题再合并,只要利用列名的规律批量操作即可。针对你的示例数据,这里提供两种高效实现方法:
方法一:分步处理后合并(直观易读)
这种方法将年龄和语言数据分开转换,再合并结果,能清晰保留各列的数据类型:
library(tidyverse) # 示例数据 df <- tribble( ~ID, ~Age_1, ~Age_2, ~Age_3, ~Lang_1_1, ~Lang_1_2, ~Lang_2_1, ~Lang_2_2, ~Lang_3_1, ~Lang_3_2, 1, 20, 25, 30, "English", NA, "English", NA, "English", "French", 2, 21, 25, 47, "English", "French", "English", NA, "English", "French", 3, 17, 42, 43, NA, "French", NA, "French", NA, "French" ) # 1. 转换年龄列到长格式 age_long <- df %>% select(ID, starts_with("Age")) %>% pivot_longer( cols = starts_with("Age"), names_to = "family_member", values_to = "Age", names_prefix = "Age_" # 去掉列名中的"Age_"前缀,提取家庭成员编号 ) %>% mutate(family_member = as.integer(family_member)) # 转成整数类型 # 2. 转换语言列到长格式,再转宽为多语言列 lang_long <- df %>% select(ID, starts_with("Lang")) %>% pivot_longer( cols = starts_with("Lang"), names_to = c("family_member", "lang_index"), values_to = "Language", names_pattern = "Lang_(\\d)_(\\d)" # 用正则拆分列名,提取成员编号和语言序号 ) %>% mutate(family_member = as.integer(family_member)) %>% pivot_wider( id_cols = c(ID, family_member), names_from = lang_index, values_from = Language, names_prefix = "Lang_" # 添加前缀生成Lang_1、Lang_2列 ) # 3. 合并年龄和语言数据 df_final <- age_long %>% inner_join(lang_long, by = c("ID", "family_member"))
方法二:一次性转换(更简洁)
通过separate拆分列名,再用pivot_wider整理,一步到位:
df_final <- df %>% pivot_longer(cols = -ID, names_to = "name", values_to = "value") %>% # 拆分列名为变量类型、成员编号、语言序号(Age列自动补全NA) separate(name, into = c("variable", "family_member", "lang_index"), sep = "_", fill = "right") %>% pivot_wider( id_cols = c(ID, family_member), names_from = c(variable, lang_index), values_from = value, # 生成规范列名:Age、Lang_1、Lang_2 names_glue = "{variable}{ifelse(is.na(lang_index), '', paste0('_', lang_index))}" ) %>% # 修正数据类型 mutate( family_member = as.integer(family_member), Age = as.numeric(Age) )
结果说明
最终生成的df_final每行对应一位家庭成员,包含以下列:
ID:访谈编号family_member:家庭成员编号(1/2/3)Age:数值型的年龄数据Lang_1、Lang_2:字符型的语言能力数据
两种方法都能高效处理大量列,只要你的列名遵循Age_成员编号、Lang_成员编号_语言序号的规律,无需手动逐个处理。
内容的提问来源于stack exchange,提问作者kheops
相关产品推荐
相关产品推荐

