R:使用 reduce 和设置后缀从长到宽的转换

R: long to wide transformation using reduce and setting suffixes

我们以鸢尾花数据为例,稍微修改一下:

(注意:下面两行使用 "UPDATE #1" 部分中的 4 行)

data(iris)
iris$id <- rep(1:50, times = 3)

我需要将数据从这种准长格式转换为宽格式,以便每一行的 id 都相同。换句话说:原始鸢尾花数据可以看作是 3 个表格(每个物种一个)一张一张地粘贴。我需要将这 3 张桌子一张一张地粘贴到另一张桌子上。

这很简单,我是这样做的:

require(purrr)
require(dplyr)
iris %>% split(.$Species) %>% reduce( full_join, by = "id")

以上示例生成的名称如 "Petal.Length.x"、...、"Petal.Length.y"、...、"Petal.Length"。我希望它们是:"Petal.Length.setosa"、...、"Petal.Length.versicolor"、...、"Petal.Length.virginica"。所以唯一剩下的就是将物种名称附加到原始变量名称。

我尝试在 reduce 之前使用 mapsetNames,但没有成功。

我不想使用 tidyr 的 gatherseparate,因为我的 1.5GB 数据集在纯长格式下增长到 13GB(我有很多类似 id 的列需要保留)。

我可能可以使用 namesgsub 和一些基本的正则表达式在下一行中添加名称,但我很好奇是否可以在不破坏 %>% 流程的情况下做到这一点.


更新 #1

谢谢lmo的回复!一个非常好的和干净的解决方案!当我第一次看到它时,我觉得我想多了这个问题......但实际上我在 Whosebug 上把它简单化了。让我们添加一些混乱:

iris$id <- rep(sample(1:50, 50), times = 3) ## random order
iris$drop_me <- sample(c(1,0), 150, TRUE, c(0.8, 0.2)) ## rows wirh 0 in this column will be missing
iris <- iris[iris$drop_me == 1, ]
iris$drop_me <- NULL

所以我有上面的数据,现在我尝试使用 reduce...我也从 left_join 更新到 full_join 因为我意识到我跳过了一些结果。

在此先感谢您的问候。

这是使用 splitdo.call 的基础 R 方法:

# get list of data frame, drop the split factor (Species)
myList <- split(iris[, -which(names(iris) == "Species")], iris$Species)
# perform wide transformation
do.call(data.frame, myList)

这会将物种名称放在前面。使用 gsub.

将它们移到后面并不难

这是部分结果:

  setosa.Sepal.Length setosa.Sepal.Width setosa.Petal.Length setosa.Petal.Width
1                  5.1                3.5                 1.4                0.2
2                  4.9                3.0                 1.4                0.2
3                  4.7                3.2                 1.3                0.2
4                  4.6                3.1                 1.5                0.2
5                  5.0                3.6                 1.4                0.2
6                  5.4                3.9                 1.7                0.4

其他品种为附加柱。

更新 #1 的答案

虽然第一行是一样的,但这里有点复杂:

# get list of data frame, drop the split factor (Species)
myList <- split(iris[, -which(names(iris) == "Species")], iris$Species)
# add names to data.frames
myList <- lapply(names(myList),
                 function(i) {
                       setNames(myList[[i]],
                         c(paste0(head(names(myList[[i]]), -1), ".", i), "id"))
                 })

# merge the data.frames together
Reduce(function(x, y) {merge(x, y, by="id", all=TRUE)}, myList)

这会产生您想要的命名,并将 Species 附加到每个变量的末尾。