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
之前使用 map
和 setNames
,但没有成功。
我不想使用 tidyr 的 gather
和 separate
,因为我的 1.5GB 数据集在纯长格式下增长到 13GB(我有很多类似 id 的列需要保留)。
我可能可以使用 names
、gsub
和一些基本的正则表达式在下一行中添加名称,但我很好奇是否可以在不破坏 %>%
流程的情况下做到这一点.
更新 #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
因为我意识到我跳过了一些结果。
在此先感谢您的问候。
这是使用 split
和 do.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 附加到每个变量的末尾。
我们以鸢尾花数据为例,稍微修改一下:
(注意:下面两行使用 "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
之前使用 map
和 setNames
,但没有成功。
我不想使用 tidyr 的 gather
和 separate
,因为我的 1.5GB 数据集在纯长格式下增长到 13GB(我有很多类似 id 的列需要保留)。
我可能可以使用 names
、gsub
和一些基本的正则表达式在下一行中添加名称,但我很好奇是否可以在不破坏 %>%
流程的情况下做到这一点.
更新 #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
因为我意识到我跳过了一些结果。
在此先感谢您的问候。
这是使用 split
和 do.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 附加到每个变量的末尾。