【问题标题】:Collapse variables into one variable with values preserving the variable names将变量合并为一个变量,其值保留变量名称
【发布时间】:2016-08-05 22:33:57
【问题描述】:

合并两个数据框后,我得到:

d.f <- data.frame(sex = c("M", "F", NA, NA),
       age = c(NA, NA, "old", "young"),
       n = c(2, 1, 3, 4))

...但想将前两个变量合二为一,结果如下:

sex.age      n
 sex.M       2
 sex.F       1
 age.old     3
 age.young   4

这似乎是一个简单(并且可能很常见)的问题,但我真的很难找到答案。我认为按照 tidyr 和 reshape 的方式已经准备好了一些东西,但我没有找到它——可能是因为最终的结构非常不整洁。

数据结构将保持不变,这意味着 NA 始终位于不同的行中。像

这样的解决方案
na.omit(unlist(d.f[1:2]))

apply(d.f[, 1:2], 1, function(x) x[!is.na(x)])

工作,但没有简单的方法来获取变量名前缀。

【问题讨论】:

  • 我认为数据结构根本不是“常见的”,而是一种病态的情况。
  • 这是 list(data.frame(sex = c("M", "F"), n = c(2,1)), data.frame(age = c("old", "young"), n = c(3,4))) %&gt;% dplyr::bind_rows() 的结果,因此并非完全不合理。有趣的是,data.table::rbindlist() 通过折叠 NA 并保留第一个变量名来处理这种情况。不知道怎么总结,想听听其他意见。

标签: r reshape


【解决方案1】:

您可以使用 reshape2 包中的melt

library(reshape2)
df <- melt(d.f, id.vars = "n")
df[!is.na(df$value), ]
#   n variable value
# 1 2      sex     M
# 2 1      sex     F
# 7 3      age   old
# 8 4      age young

【讨论】:

  • 谢谢,这很有用,但@akrun 的回答给了我需要的列名。
【解决方案2】:

这是一个使用dplyr/tidyr 的选项。我们使用gatherunite 的“Var”和“Val”列将“wide”转换为“long”格式,以创建“sex.age”并重新排列列顺序。

library(dplyr)
library(tidyr)
gather(d.f, Var, Val, -n, na.rm = TRUE) %>% 
                 unite(sex.age, Var, Val, sep=".") %>%
                 select(2:1)
#    sex.age n
#1     sex.M 2
#2     sex.F 1
#7   age.old 3
#8 age.young 4

【讨论】: