Concatenate/merge 将 R 中的数据帧转换为向量类型的单元格
Concatenate/merge dataframes in R into vector type cells
我想将两个数据框合并为一个,每个单元格成为一个向量或列表。
列在两个数据框中具有相同的名称。有些列由我想在合并数据框中保留为数值的数值组成。有些列是由字符组成的。
例如我想从这两个数据帧中得到:
DF1 <- data.frame(
xx = c(1:5),
yy = c(2:6),
zz = c("a","b","c","d","e"))
DF2 <- data.frame(
xx = c(3:7),
yy = c(5:9),
zz = c("a","i","h","g","f"))
看起来像这样:
DF1
xx
yy
zz
1
2
a
2
3
b
3
4
c
4
5
d
5
6
e
DF2
xx
yy
zz
3
5
a
4
6
i
5
7
h
6
8
g
7
9
f
要获得如下所示的数据框:
xx
yy
zz
c(1,3)
c(2,5)
c(a,a)
c(2,4)
c(3,6)
c(b,i)
c(3,5)
c(4,7)
c(c,h)
c(4,6)
c(5,8)
c(d,g)
c(5,7)
c(6,9)
c(e,f)
我尝试过使用 paste() 或 str_c(),但它总是将我的数值转换为 char,并且它不会像我想要的那样创建列表或向量。
你知道有什么函数可以帮助我做到这一点吗?
由于您的数据由不同类型组成,因此没有直接的答案。但是我提出了一些解决方案,可以通过创建嵌套列表来解决问题。让我知道,如果这是您需要的:
library(BBmisc)
library(dplyr)
colvec <- c("xx2","yy2","zz2")
colnames(DF2) <- colvec
DF <- bind_cols(DF1,DF2)
cols.num <- c("xx","xx2","yy","yy2")
DF[cols.num] <- sapply(DF[cols.num],as.character)
DF <- DF[,c(1,4,2,5,3,6)]
xx <- convertRowsToList(DF[,1:2])
yy <- convertRowsToList(DF[,3:4])
zz <- convertRowsToList(DF[,5:6])
final_list <- list(xx,yy,zz)
这会为您提供列表中的矩阵:
res <- setNames(
lapply( colnames(DF1), function(x) cbind(DF1[[x]], DF2[[x]]) ),
colnames(DF1) )
要将结果转换为数据框,您可以使用:
data.frame( sapply(
names(res), function(x){ sapply(
1:nrow(res$xx), function(y){ list(res[[x]][y,1:ncol(res$xx)]) }
) }
) )
xx yy zz
1 1, 3 2, 5 a, a
2 2, 4 3, 6 b, i
3 3, 5 4, 7 c, h
4 4, 6 5, 8 d, g
5 5, 7 6, 9 e, f
放在一个函数中:
编辑:添加了应用任意数量 DF 的功能
(针对问题的要求,但似乎是必要的)
morph <- function(...){
abc <- list(...)
res <- sapply( colnames(abc[[1]]), function(col) list(
sapply( abc, function(dfr) dfr[[col]] ) ) )
data.frame( sapply(
names(res), function(x){ sapply(
1:nrow(res[[1]]), function(y){ list(res[[x]][y,1:ncol(res[[1]])]) }
) }
) )
}
morph(DF1, DF2, DF2)
xx yy zz
1 1, 3, 3 2, 5, 5 a, a, a
2 2, 4, 4 3, 6, 6 b, i, i
3 3, 5, 5 4, 7, 7 c, h, h
4 4, 6, 6 5, 8, 8 d, g, g
5 5, 7, 7 6, 9, 9 e, f, f
使用一些 tidyverse,您可以反转列表,然后将它们重新组合在一起。
library(purrr)
library(dplyr)
as_tibble(map2(DF1, DF2, ~ map(transpose(list(.x, .y)), unlist)))
这将为您提供矢量数据框。
# A tibble: 5 x 3
xx yy zz
<list> <list> <list>
1 <int [2]> <int [2]> <chr [2]>
2 <int [2]> <int [2]> <chr [2]>
3 <int [2]> <int [2]> <chr [2]>
4 <int [2]> <int [2]> <chr [2]>
5 <int [2]> <int [2]> <chr [2]>
正在分解...
transpose(list(.x, .y))
会将成对的列列表 inside-out 从两个向量的列表翻转为 5 个元素的列表(每行一个,每个元素中有两个列表元素)。
map(transpose(list(.x, .y)), unlist))
将遍历 5 个列表中的每一个,并将它们从 2 的列表取消列出到 2 的向量。
map2(DF1, DF2, ~ map(transpose(list(.x, .y)), unlist))
将迭代 DF1 和 DF2 中的每个列对(例如,xx、yy、zz)执行步骤 1 和 2。
as_tibble(map2(DF1, DF2, ~ map(transpose(list(.x, .y)), unlist)))
将列表转换为小标题(基本上是 data.frame)。
您可以做的另一件事是堆叠数据,然后 nest()
。您再次需要几个步骤来完成它。这会更好地扩展,因为您可以使用 2 个以上的数据帧来执行此操作。
library(dplyr)
library(tibble)
library(tidyr)
bind_rows(rowid_to_column(DF1),
rowid_to_column(DF2)) %>%
group_by(rowid) %>%
nest(nest_data = -rowid) %>%
unnest_wider(nest_data) %>%
ungroup() %>%
select(-rowid)
这也为您提供了矢量数据框。
# A tibble: 5 x 3
xx yy zz
<list> <list> <list>
1 <int [2]> <int [2]> <chr [2]>
2 <int [2]> <int [2]> <chr [2]>
3 <int [2]> <int [2]> <chr [2]>
4 <int [2]> <int [2]> <chr [2]>
5 <int [2]> <int [2]> <chr [2]>
尝试以下基本 R 选项
> data.frame(Map(function(x, y) asplit(cbind(x, y), 1), DF1, DF2))
xx yy zz
1 1, 3 2, 5 a, a
2 2, 4 3, 6 b, i
3 3, 5 4, 7 c, h
4 4, 6 5, 8 d, g
5 5, 7 6, 9 e, f
我想将两个数据框合并为一个,每个单元格成为一个向量或列表。 列在两个数据框中具有相同的名称。有些列由我想在合并数据框中保留为数值的数值组成。有些列是由字符组成的。
例如我想从这两个数据帧中得到:
DF1 <- data.frame(
xx = c(1:5),
yy = c(2:6),
zz = c("a","b","c","d","e"))
DF2 <- data.frame(
xx = c(3:7),
yy = c(5:9),
zz = c("a","i","h","g","f"))
看起来像这样:
DF1
xx | yy | zz |
---|---|---|
1 | 2 | a |
2 | 3 | b |
3 | 4 | c |
4 | 5 | d |
5 | 6 | e |
DF2
xx | yy | zz |
---|---|---|
3 | 5 | a |
4 | 6 | i |
5 | 7 | h |
6 | 8 | g |
7 | 9 | f |
要获得如下所示的数据框:
xx | yy | zz |
---|---|---|
c(1,3) | c(2,5) | c(a,a) |
c(2,4) | c(3,6) | c(b,i) |
c(3,5) | c(4,7) | c(c,h) |
c(4,6) | c(5,8) | c(d,g) |
c(5,7) | c(6,9) | c(e,f) |
我尝试过使用 paste() 或 str_c(),但它总是将我的数值转换为 char,并且它不会像我想要的那样创建列表或向量。
你知道有什么函数可以帮助我做到这一点吗?
由于您的数据由不同类型组成,因此没有直接的答案。但是我提出了一些解决方案,可以通过创建嵌套列表来解决问题。让我知道,如果这是您需要的:
library(BBmisc)
library(dplyr)
colvec <- c("xx2","yy2","zz2")
colnames(DF2) <- colvec
DF <- bind_cols(DF1,DF2)
cols.num <- c("xx","xx2","yy","yy2")
DF[cols.num] <- sapply(DF[cols.num],as.character)
DF <- DF[,c(1,4,2,5,3,6)]
xx <- convertRowsToList(DF[,1:2])
yy <- convertRowsToList(DF[,3:4])
zz <- convertRowsToList(DF[,5:6])
final_list <- list(xx,yy,zz)
这会为您提供列表中的矩阵:
res <- setNames(
lapply( colnames(DF1), function(x) cbind(DF1[[x]], DF2[[x]]) ),
colnames(DF1) )
要将结果转换为数据框,您可以使用:
data.frame( sapply(
names(res), function(x){ sapply(
1:nrow(res$xx), function(y){ list(res[[x]][y,1:ncol(res$xx)]) }
) }
) )
xx yy zz
1 1, 3 2, 5 a, a
2 2, 4 3, 6 b, i
3 3, 5 4, 7 c, h
4 4, 6 5, 8 d, g
5 5, 7 6, 9 e, f
放在一个函数中:
编辑:添加了应用任意数量 DF 的功能 (针对问题的要求,但似乎是必要的)
morph <- function(...){
abc <- list(...)
res <- sapply( colnames(abc[[1]]), function(col) list(
sapply( abc, function(dfr) dfr[[col]] ) ) )
data.frame( sapply(
names(res), function(x){ sapply(
1:nrow(res[[1]]), function(y){ list(res[[x]][y,1:ncol(res[[1]])]) }
) }
) )
}
morph(DF1, DF2, DF2)
xx yy zz
1 1, 3, 3 2, 5, 5 a, a, a
2 2, 4, 4 3, 6, 6 b, i, i
3 3, 5, 5 4, 7, 7 c, h, h
4 4, 6, 6 5, 8, 8 d, g, g
5 5, 7, 7 6, 9, 9 e, f, f
使用一些 tidyverse,您可以反转列表,然后将它们重新组合在一起。
library(purrr)
library(dplyr)
as_tibble(map2(DF1, DF2, ~ map(transpose(list(.x, .y)), unlist)))
这将为您提供矢量数据框。
# A tibble: 5 x 3
xx yy zz
<list> <list> <list>
1 <int [2]> <int [2]> <chr [2]>
2 <int [2]> <int [2]> <chr [2]>
3 <int [2]> <int [2]> <chr [2]>
4 <int [2]> <int [2]> <chr [2]>
5 <int [2]> <int [2]> <chr [2]>
正在分解...
transpose(list(.x, .y))
会将成对的列列表 inside-out 从两个向量的列表翻转为 5 个元素的列表(每行一个,每个元素中有两个列表元素)。map(transpose(list(.x, .y)), unlist))
将遍历 5 个列表中的每一个,并将它们从 2 的列表取消列出到 2 的向量。map2(DF1, DF2, ~ map(transpose(list(.x, .y)), unlist))
将迭代 DF1 和 DF2 中的每个列对(例如,xx、yy、zz)执行步骤 1 和 2。as_tibble(map2(DF1, DF2, ~ map(transpose(list(.x, .y)), unlist)))
将列表转换为小标题(基本上是 data.frame)。
您可以做的另一件事是堆叠数据,然后 nest()
。您再次需要几个步骤来完成它。这会更好地扩展,因为您可以使用 2 个以上的数据帧来执行此操作。
library(dplyr)
library(tibble)
library(tidyr)
bind_rows(rowid_to_column(DF1),
rowid_to_column(DF2)) %>%
group_by(rowid) %>%
nest(nest_data = -rowid) %>%
unnest_wider(nest_data) %>%
ungroup() %>%
select(-rowid)
这也为您提供了矢量数据框。
# A tibble: 5 x 3
xx yy zz
<list> <list> <list>
1 <int [2]> <int [2]> <chr [2]>
2 <int [2]> <int [2]> <chr [2]>
3 <int [2]> <int [2]> <chr [2]>
4 <int [2]> <int [2]> <chr [2]>
5 <int [2]> <int [2]> <chr [2]>
尝试以下基本 R 选项
> data.frame(Map(function(x, y) asplit(cbind(x, y), 1), DF1, DF2))
xx yy zz
1 1, 3 2, 5 a, a
2 2, 4 3, 6 b, i
3 3, 5 4, 7 c, h
4 4, 6 5, 8 d, g
5 5, 7 6, 9 e, f