R语言使用gather函数将4列转为2组键值对避免重复行的实现方法
问题原因
你连续两次使用gather的写法会生成笛卡尔积:第一次将measure_A相关列转为长表后,每个ID对应2条记录;第二次对measure_B列做宽转长时,会给每条已有的A类记录匹配所有B类分组,因此每个ID最终会得到2*2=4条记录,自然出现重复行。
最优实现方案(推荐)
现在tidyr官方已推荐用pivot_longer替代老旧的gather函数,该方案无需额外过滤,逻辑更直观,性能也更好:
library(tidyr) library(dplyr) result <- df %>% pivot_longer( cols = starts_with("measure"), # 匹配所有要转换的指标列 names_to = c(".value", "group"), # 将列名按分隔符拆为两部分,.value表示前缀作为新列名 names_sep = "\\." # 按列名里的.拆分 ) %>% select(-group) # 如果不需要序号列可以直接删掉
逻辑说明
pivot_longer会自动把列名前缀measure_A、measure_B作为新的列名,后缀的1、2作为分组标识,同一序号下的A、B数值会自动对应匹配,不会产生多余的笛卡尔积,直接得到你需要的无重复结果。
gather+filter方案逻辑解释
你找到的filter方案本质是剔除笛卡尔积里的无效匹配行,实现逻辑如下:
df %>% gather(key = measure_A, value = "score_A", measure_A.1, measure_A.2) %>% gather(key = measure_B, value = "score_B", measure_B.1, measure_B.2) %>% # 提取两个measure列的后缀序号,仅保留序号相同的有效匹配行 filter(sub(".*\\.", "", measure_A) == sub(".*\\.", "", measure_B)) %>% distinct() # 可选,用于删除完全重复的冗余行
逻辑说明
两次gather得到的结果里,只有measure_A和measure_B后缀数字相同的行是你需要的正确匹配(比如measure_A.1对应measure_B.1),其余交叉匹配的行(比如measure_A.1配measure_B.2)都是多余的,filter就是把这些无效行直接过滤掉,最终得到目标结果。
内容的提问来源于stack exchange,提问作者Mirko Saunders
相关产品推荐
相关产品推荐

