R语言堆叠同类变量实现数据集宽表转长表的方法
R 批量按3个变量为一组堆叠宽表转长表方案
问题描述
我有一个大型数据集的部分变量,其中每3个连续变量属于同一测量维度:例如前3个变量c_0064、c_0065、c_0066记录受访者知晓的3个品牌,第二组3个变量v_159_1、v_159_2、v_159_3记录受访者对前述3个品牌的态度,以此类推。仅展示数据集的首尾列,v_159_3之后实际依次为v_160_1、v_160_2、v_160_3、v_161_1……直至v_182_1、v_182_2、v_182_3。
数据集结构示例
structure(list(lfdn = c(4, 6, 7, 8, 9, 11, 12, 19), c_0064 = c("x", "t", "x", "x", "t", "x", "z", "z"), c_0065 = c("z", "z", "z", "f", "f", "f", "t", "t"), c_0066 = c("x", "x", "x", "a", "f", "t", "z", "b"), v_159_1 = c(1, 1, 3, 2, 2, 5, 4, 3), v_159_2 = c(3, 3, 3, 3, 3, 2, 5, 1), v_159_3 = c(5, 5, 1, 4, 4, 1, 2, 2), v_182_1 = c(1, 1, 5, 5, 4, 4, 4, 4), v_182_2 = c(4, 2, 2, 2, 2, 3, 1, 5), v_182_3 = c(5, 4, 5, 1, 2, 5, 2, 2)), row.names = c(NA, -8L), class = c("tbl_df", "tbl", "data.frame")) > df # A tibble: 8 x 10 lfdn c_0064 c_0065 c_0066 v_159_1 v_159_2 v_159_3 v_182_1 v_182_2 v_182_3 <dbl> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> 1 4 x z x 1 3 5 1 4 5 2 6 t z x 1 3 5 1 2 4 3 7 x z x 3 3 1 5 2 5 4 8 x f a 2 3 4 5 2 1 5 9 t f f 2 3 4 4 2 2 6 11 x f t 5 2 1 4 3 5 7 12 z t z 4 5 2 4 1 2 8 19 z t b 3 1 2 4 5 2
预期输出格式
structure(list(lfdn = c(4, 6, 7, 8, 9, 11, 12, 19, 4, 6, 7, 8, 9, 11, 12, 19, 4, 6, 7, 8, 9, 11, 12, 19), c_0064_65_66 = c("x", "t", "x", "x", "t", "x", "z", "z", "z", "z", "z", "f", "f", "f", "t", "t", "x", "x", "x", "a", "f", "t", "z", "b"), v_159_1_2_3 = c(1, 1, 3, 2, 2, 5, 4, 3, 3, 3, 3, 3, 3, 2, 5, 1, 5, 5, 1, 4, 4, 1, 2, 2), v_181_1_2_3 = c(1, 1, 5, 5, 4, 4, 4, 4, 4, 2, 2, 2, 2, 3, 1, 5, 5, 4, 5, 1, 2, 5, 2, 2)), row.names = c(NA, -24L), class = c("tbl_df", "tbl", "data.frame")) > dflong # A tibble: 24 x 4 lfdn c_0064_65_66 v_159_1_2_3 v_181_1_2_3 <dbl> <chr> <dbl> <dbl> 1 4 x 1 1 2 6 t 1 1 3 7 x 3 5 4 8 x 2 5 5 9 t 2 4 6 11 x 5 4 7 12 z 4 4 8 19 z 3 4 9 4 z 3 4 10 6 z 3 2 # ... with 14 more rows
现有问题
尝试使用melt处理数据失败了,目前能想到的方法是使用stack命令逐组处理3个变量,例如stack(df, select=c("c_0064", "c_0065", "c_0066")),最后再把所有堆叠后的变量合并。但除了展示的变量外,数据集还有大量重复组变量,需要更高效的实现方法。
解决方案
使用tidyverse的pivot_longer函数可以实现批量自动处理,不需要逐组写代码,中间的v_160到v_181所有组都会自动识别转换:
library(tidyverse) dflong <- df %>% # 统一品牌列命名规则,和态度列的 组名_位次 格式对齐 rename_with( ~ str_replace(., "c_0064", "c_006_1") %>% str_replace("c_0065", "c_006_2") %>% str_replace("c_0066", "c_006_3"), .cols = starts_with("c_006") ) %>% # 宽转长,按组自动拆分堆叠 pivot_longer( cols = -lfdn, names_to = c(".value", "item_seq"), names_sep = "_(?=\\d$)" # 匹配最后一个下划线,分隔组名和对应品牌的位次 ) %>% # 按受访者ID和品牌位次排序,和预期输出顺序完全一致 arrange(lfdn, item_seq) %>% # 修改列名为你需要的格式 rename( c_0064_65_66 = c_006, v_159_1_2_3 = v_159, v_182_1_2_3 = v_182 ) %>% # 不需要位次列可直接删除 select(-item_seq)
如果需要保留所有中间v组的原始组名,不需要手动写rename规则,直接去掉rename步骤即可,函数会自动生成v_160、v_161等列名,也可以根据需求批量修改列名。
内容的提问来源于stack exchange,提问作者Nadine M.
相关产品推荐
相关产品推荐

