如何让tidyr的gather函数在R中评估对象i以生成正确列名?
解决gather函数无法解析变量作为列名的问题
这个问题我之前处理宽转长数据时也踩过坑!核心原因是gather()的值列参数默认会把你传入的变量名直接当成字符串列名,而不会去解析变量里存储的内容。下面给你几个实用的解决办法:
方法1:推荐用新版tidyr的pivot_longer()(更灵活)
自从tidyr 1.0.0版本之后,官方更推荐使用pivot_longer()替代gather(),它对字符变量作为列名的支持更友好:
library(tidyr) library(dplyr) # 模拟可重复的测试数据 set.seed(123) z0 <- data.frame(id = 1:10, A.pre = rnorm(10), B.pre = rnorm(10), A.Post = rnorm(10), B.Post = rnorm(10)) choix <- data.frame(var = colnames(z0), pairs = c(NA, "A", "B", "A", "B"), stringsAsFactors = F) i <- "A" # 宽转长,直接用i的内容作为值列名 z0 %>% select(id, all_of(choix[choix$pairs %in% i, 1])) %>% pivot_longer(cols = -id, names_to = "time", values_to = i)
运行后你会看到结果的列名是id、time、A,完全符合你的需求。这里values_to = i直接接受字符向量,会自动把i存储的"A"作为新列名。
方法2:如果坚持用旧版gather(),用符号解析
如果你还在使用旧版tidyr,需要用rlang包的符号解析功能,把字符变量转换成gather能识别的列名表达式:
z0 %>% select(c("id", choix[choix$pairs %in% i, 1])) %>% gather(time, !!sym(i), choix[choix$pairs %in% i, 1])
这里的!!sym(i)是关键:sym()把字符"A"转换成R能识别的符号,!!(双感叹号)告诉gather要解析这个符号,而不是把它当成字符串"i"。
为什么原来的代码不行?
你之前写的gather(time, i, ...)里,第二个参数i被gather当成了字面量,也就是直接把"i"作为列名,而不会去读取变量i里存储的"A"。这是因为gather()的参数设计是优先接受表达式,而非字符向量。
内容的提问来源于stack exchange,提问作者Nicolas Molano
相关产品推荐
相关产品推荐

