如何基于变量共同前缀将R语言宽表转为长表?
解决R语言宽表转长表(带前缀分组)的问题
原始宽格式数据
# 示例数据,还有更多类似x_、y_开头的变量 df <- data.frame(id = c(1,2,3), x_num = c(9,8,7), y_num = c(6,5,4), x_text_long = c("a","b","c"), y_text_long = c("d","e","f"), z = c(T,F,F))
期望的长格式数据
# 目标长表 target <- data.frame(id = c(1,1,2,2,3,3), type = c("x","y","x","y","x","y"), num = c(9,6,8,5,7,4), text_long = c("a","d","b","e","c","f"), z = c(T,T,F,F,F,F))
需求说明
将宽表转换为长表,核心要求:
- 对以
x_和y_为前缀的变量分组,生成type列标记前缀(x或y) - 前缀后的部分作为新的列名(比如
x_num对应type=x,值归入num列) - 保留
id、z等不参与分组的变量的对应值(每个type分组下重复这些值)
尝试过的无效方法
方法1:单次处理一组变量,效率低
# 只能逐个处理(x,y)变量对,效率不高 df[c("x_num","y_num")] %>% pivot_longer( cols = `x_num`:`y_num`, names_to = "type", values_to = "values" ) %>% mutate(type=substring(type,1,1))
方法2:reshape函数输出不符合预期
# 输出结果不符合需求 reshape(df, direction = "long", varying = list(names(df)[2:5]), v.names = "values", idvar = c("id"), timevar = "type")
可行解决方案
方案1:基于tidyverse的pivot_longer(推荐)
使用tidyr包的pivot_longer函数,通过拆分变量名一次性完成转换,同时保留非分组变量:
library(tidyr) library(dplyr) result <- df %>% pivot_longer( cols = starts_with(c("x_", "y_")), # 选择所有x_、y_开头的变量 names_to = c("type", ".value"), # 拆分变量名:前缀存入type,剩余部分作为新列名 names_sep = "_" # 按下划线拆分变量名 ) # 查看结果 result
运行后得到的结果与目标target完全一致:
# A tibble: 6 × 4 id z type num text_long <dbl> <lgl> <chr> <dbl> <chr> 1 1 TRUE x 9 a 2 1 TRUE y 6 d 3 2 FALSE x 8 b 4 2 FALSE y 5 e 5 3 FALSE x 7 c 6 3 FALSE y 4 f
核心参数说明
cols = starts_with(c("x_", "y_")):精准选择需要转换的变量,避免手动输入列名names_to = c("type", ".value"):type存储拆分出的前缀(x/y),.value表示用拆分后的剩余部分作为新列名,自动匹配对应值names_sep = "_":指定变量名的拆分分隔符为下划线
方案2:基于base R的reshape函数
如果不想依赖tidyverse,可通过正确配置reshape参数实现:
result_base <- reshape(df, direction = "long", varying = list(c("x_num", "y_num"), c("x_text_long", "y_text_long")), v.names = c("num", "text_long"), idvar = c("id", "z"), timevar = "type", times = c("x", "y")) # 调整列顺序与目标一致 result_base <- result_base[, c("id", "type", "num", "text_long", "z")] rownames(result_base) <- NULL # 重置行名 result_base
运行后输出:
id type num text_long z 1 1 x 9 a TRUE 2 2 x 8 b FALSE 3 3 x 7 c FALSE 4 1 y 6 d TRUE 5 2 y 5 e FALSE 6 3 y 4 f FALSE
内容的提问来源于stack exchange,提问作者luchonacho
相关产品推荐
相关产品推荐

