将 R 中的数据帧连接/合并为向量类型单元格

Posted

技术标签:

【中文标题】将 R 中的数据帧连接/合并为向量类型单元格【英文标题】:Concatenate/merge dataframes in R into vector type cells 【发布时间】:2021-12-18 14:49:38 【问题描述】:

我想将两个数据框合并为一个,每个单元格成为一个向量或一个列表。 两个数据框中的列具有相同的名称。有些列由数值组成,我想在合并的数据框中保留为数值。有些列是由字符组成的。

例如,我想从这两个数据框中:

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 并且它不会像我想要的那样创建列表或向量。

你知道有什么功能可以帮助我做到这一点吗?

【问题讨论】:

【参考方案1】:

使用一些 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)) 将从内到外的两个向量列表翻转成对的列列表到 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))) 将列表转换为 tibble(基本上是 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]>

【讨论】:

我的真实数据中实际上有 3 个数据框,您的第二个提议非常有效。 group_by(rowid)ungroup() 有什么用途吗?我发现没有这些行运行代码没有区别 这是为了确保嵌套时行对齐,但我想nest() 中的默认行为会处理它。它们可能可以被删除,只是更明确一点。没有伤害任何东西,但很好。【参考方案2】:

这会为您提供列表中的矩阵:

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

【讨论】:

我设法使用此功能将您的解决方案转换为我想要的L1_2 &lt;- setNames( lapply( colnames(DF1), function(x) cbind(DF1[[x]], DF2[[x]]) ), colnames(DF1) ) DF_reb &lt;- function(Res) m &lt;- length(Res) n &lt;- nrow(Res$xx) DF &lt;- data.frame(matrix(NA,nrow=n,ncol=m)) colnames(DF) &lt;- c("xx","yy","zz") for (i in 1:n) Lxx &lt;- list(Res$xx[i,]) Lyy &lt;- list(Res$yy[i,]) Lzz &lt;- list(Res$zz[i,]) DF$xx[i] &lt;- Lxx DF$yy[i] &lt;- Lyy DF$zz[i] &lt;- Lzz return(DF) DF1_2 &lt;- DF_reb(L1_2) 让我知道它是否适合您或可以改进 我添加了一个单行来将结果转换为数据帧输出。现在这是@ThomasIsCoding 的确切结果,也许使用较少的内置函数有好处,但这只是我猜的口味问题:) 为任意 DF 列表添加了功能,尽管问题明确指出了两个。 感谢完美。您的回复和@Adam 的回复都回答了我的问题。由于这是我第一次使用这个网站,我不知道是否有办法同时接受两者,如果其他人需要答案,他们会选择他们喜欢或最适合他们问题的答案。 没关系!总是有不止一种解决方案,而且必须接受一种。总之,谢谢你的回复,不胜感激!【参考方案3】:

由于您的数据包含不同的类型,因此没有直接的答案。但是我提出了一些解决方案,可以通过创建嵌套列表来解决问题。如果这是您需要的,请告诉我:

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)

【讨论】:

【参考方案4】:

尝试以下基本 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

【讨论】:

以上是关于将 R 中的数据帧连接/合并为向量类型单元格的主要内容,如果未能解决你的问题,请参考以下文章

在一个单元格中的多个可分离(连接)值上加入 R 数据框

如何将EXCEL表格中的同一列有相同的内容 合并成一个单元格?

vba中怎么用代码将单元格内容转换为文本类型?

如何将具有数据的单元格与同一列中的空白单元格合并?

合并复制如何初始化发布和订阅

如何通过Java 合并和取消合并 Excel 单元格