关于r:取代dplyr的plyr :: cbind.fill吗?

Replacement of plyr::cbind.fill in dplyr?

如果这个问题很简单,我深表歉意,但是我一直在搜寻互联网,而且似乎找不到简单的解决方案。

我目前有一个R对象的列表(命名向量或1个变量的数据框,我可以使用其中任何一个),我想将它们加入1个大数据框,每个唯一的名称/行名各有1行,每列1对于原始列表中的每个元素。

我的开始列表如下:

1
2
3
4
l1 <- list(df1 = data.frame(c(1,2,3), row.names = c("A","B","C")),
       df2 = data.frame(c(2,6), row.names = c("B","D")),
       df3 = data.frame(c(3,6,9), row.names = c("C","D","A")),
       df4 = data.frame(c(4,12), row.names = c("A","E")))

我希望输出看起来像:

1
2
3
4
5
6
7
8
9
10
data.frame("df1" = c(1,2,3,NA,NA),
+           "df2" = c(NA,2,NA,6,NA),
+           "df3" = c(9,NA,3,6,NA),
+           "df4" = c(4,NA,NA,NA,12), row.names = c("A","B","C","D","E"))
  df1 df2 df3 df4
A   1  NA   9   4
B   2   2  NA  NA
C   3  NA   3  NA
D  NA   6   6  NA
E  NA  NA  NA  12

我不介意填充值是NA还是0(最终我希望是0,但这很容易解决)。

我几乎肯定plyr::cbind.fill确实可以做到这一点,但是我在脚本的其余部分中一直使用dplyr,所以我不认为同时使用dplyr是个好主意。 dplyr::bind_cols似乎不适用于不同长度的向量。我知道这里曾问过一个非常类似的问题:R:dplyr中的plyr :: rbind.fill是否有很好的替代品?
但是正如我提到的那样,该解决方案实际上似乎不起作用。 dplyr::full_join都不会,即使包裹在do.call中也是如此。是否有一个简单的解决方案,或者是编写自定义函数的唯一解决方案?


这里是一些purrrdplyr函数的一种方式。创建列名称以表示每个数据框-因为每个数据框只有一个列,所以对于setNames来说这很容易,但是对于更多的列,您可以使用dplyr::rename。根据原始行名对整个列表进行完全联接,并用0填充NA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
library(dplyr)
library(purrr)

l1 %>%
  imap(~setNames(.x, .y)) %>%
  map(tibble::rownames_to_column) %>%
  reduce(full_join, by ="rowname") %>%
  mutate_all(tidyr::replace_na, 0)
#>   rowname df1 df2 df3 df4
#> 1       A   1   0   9   4
#> 2       B   2   2   0   0
#> 3       C   3   0   3   0
#> 4       D   0   6   6   0
#> 5       E   0   0   0  12


我们可以将行名转换为使用rownames_to_column的列,然后将rename转换为第二列,将list元素与bind_rows绑定,并使用pivot_wider

重塑为\\'wide \\'

1
2
3
4
5
6
7
8
library(dplyr)
library(tidyr)
library(purrr)
library(tibble)
map_dfr(l1, ~ rownames_to_column(.x, 'rn') %>%
              rename_at(2, ~'v1'), .id = 'grp') %>%        
   pivot_wider(names_from = grp, values_from = v1) %>%
   column_to_rownames('rn')


另一个purrrdplyr选项可能是:

1
2
3
4
5
6
7
8
9
10
11
12
13
l1 %>%
 map2_dfr(.x = ., .y = names(.), ~ setNames(.x, .y) %>%
           rownames_to_column()) %>%
 group_by(rowname) %>%
 summarise_all(~ ifelse(all(is.na(.)), NA, first(na.omit(.))))

  rowname   df1   df2   df3   df4
  <chr>   <dbl> <dbl> <dbl> <dbl>
1 A           1    NA     9     4
2 B           2     2    NA    NA
3 C           3    NA     3    NA
4 D          NA     6     6    NA
5 E          NA    NA    NA    12