宽表转长表时reshape函数列值匹配错误问题求助
问题
尝试将宽格式数据转换为长格式,使每个条目对应预评估(pre-assessment)和后评估(post-assessment)两行数据。9个条目转换时结果正常,但添加至10个(实际共25个)后,reshape函数无法正确匹配值与列标题,出现列值错位(例如bk_item_2_key列包含原本属于bk_item_5_key的值,正确值却出现在bk_item_3_key列)。
宽格式数据及尝试的代码如下:
wide <- data.frame(bk_item_1_key_pre=0.62804878, bk_item_2_key_pre=0.853658536585366, bk_item_3_key_pre=0.603658536585366, bk_item_4_key_pre=0.420731707317073, bk_item_5_key_pre=0.713414634146341, bk_item_6_key_pre=0.567073170731707, bk_item_7_key_pre=0.5, bk_item_8_key_pre=0.426829268292683, bk_item_9_key_pre=0.652439024390244, bk_item_10_key_pre=0.73780487804878, bk_item_1_key_post=0.794117647058824, bk_item_2_key_post=0.864705882352941, bk_item_3_key_post=0.594117647058824, bk_item_4_key_post=0.452941176470588, bk_item_5_key_post=0.752941176470588, bk_item_6_key_post=0.658823529411765, bk_item_7_key_post=0.5, bk_item_8_key_post=0.4, bk_item_9_key_post=0.611764705882353, bk_item_10_key_post=0.752941176470588) long <- reshape(wide, varying=c("bk_item_1_key_pre", "bk_item_2_key_pre", "bk_item_3_key_pre", "bk_item_4_key_pre", "bk_item_5_key_pre", "bk_item_6_key_pre", "bk_item_7_key_pre", "bk_item_8_key_pre", "bk_item_9_key_pre", "bk_item_10_key_pre", "bk_item_1_key_post", "bk_item_2_key_post", "bk_item_3_key_post", "bk_item_4_key_post", "bk_item_5_key_post", "bk_item_6_key_post", "bk_item_7_key_post", "bk_item_8_key_post", "bk_item_9_key_post", "bk_item_10_key_post"), v.names=c("bk_item_1_key", "bk_item_2_key", "bk_item_3_key", "bk_item_4_key", "bk_item_5_key", "bk_item_6_key", "bk_item_7_key", "bk_item_8_key", "bk_item_9_key", "bk_item_10_key"), times=c("pre", "post"), new.row.names=1:1000, direction="long")
修复思路与解决方案
问题根源
reshape函数的varying参数如果传入向量,会按v.names的长度依次分组。你将所有pre列放在前10位,post列放在后10位,函数会把第1&2列、3&4列...19&20列分为一组,这完全不符合按item匹配pre/post的需求,导致值错位。
方案1:修正base R的reshape参数
将varying改为列表格式,每个列表元素对应同一个item的pre和post列,让函数明确匹配关系:
long_fixed <- reshape(wide, varying = list( c("bk_item_1_key_pre", "bk_item_1_key_post"), c("bk_item_2_key_pre", "bk_item_2_key_post"), c("bk_item_3_key_pre", "bk_item_3_key_post"), c("bk_item_4_key_pre", "bk_item_4_key_post"), c("bk_item_5_key_pre", "bk_item_5_key_post"), c("bk_item_6_key_pre", "bk_item_6_key_post"), c("bk_item_7_key_pre", "bk_item_7_key_post"), c("bk_item_8_key_pre", "bk_item_8_key_post"), c("bk_item_9_key_pre", "bk_item_9_key_post"), c("bk_item_10_key_pre", "bk_item_10_key_post") ), v.names = c("bk_item_1_key", "bk_item_2_key", "bk_item_3_key", "bk_item_4_key", "bk_item_5_key", "bk_item_6_key", "bk_item_7_key", "bk_item_8_key", "bk_item_9_key", "bk_item_10_key"), times = c("pre", "post"), new.row.names = 1:1000, direction = "long")
方案2:利用列名规则自动匹配(更简洁)
你的列名有统一后缀_pre/_post,可以用sep参数让reshape自动识别分组,无需手动列所有列名:
long_fixed <- reshape(wide, varying = grep("_pre|_post", colnames(wide), value = TRUE), v.names = sub("_pre|_post", "", grep("_pre", colnames(wide), value = TRUE)), times = c("pre", "post"), sep = "_", direction = "long")
这里sep="_"会按下划线拆分列名,自动提取pre/post作为time标识,匹配对应item列。
方案3:使用tidyverse的pivot_longer(更直观不易错)
如果允许使用tidyverse包,pivot_longer的语法更清晰,适合这类宽转长场景:
library(tidyverse) long_tidy <- wide %>% pivot_longer( cols = everything(), names_to = c("item", ".value"), names_pattern = "(bk_item_\\d+_key)_(pre|post)" )
names_pattern用正则表达式拆分列名:将bk_item_X_key作为item列,pre/post对应值列的后缀,.value表示保留原列的数值部分。
内容的提问来源于stack exchange,提问作者Anita
相关产品推荐
相关产品推荐

