r - 在 R 中与 dplyr 连接时嵌套重复变量

标签 r join merge dplyr tidyr

我正在加入具有重复列的数据框(tibbles),而我不想加入这些列。下面的示例是我通常会做的(通过 i 加入,但不是 ab):

library(dplyr)

df1 <- tibble(i = letters[1:3], a = 1:3,   b = 4:6)
df2 <- tibble(i = letters[1:3], a = 11:13, b = 14:16)

d <- full_join(df1, df2, by ="i")
d
#> # A tibble: 3 × 5
#>       i   a.x   b.x   a.y   b.y
#>   <chr> <int> <int> <int> <int>
#> 1     a     1     4    11    14
#> 2     b     2     5    12    15
#> 3     c     3     6    13    16

我希望这些重复的变量作为嵌套列表返回,例如下面创建的输出:

tibble(
  i = letters[1:3],
  a = list(c(1, 11), c(2, 12), c(3, 13)),
  b = list(c(4, 14), c(5, 15), c(6, 16))
)
#> # A tibble: 3 × 3
#>       i         a         b
#>   <chr>    <list>    <list>
#> 1     a <dbl [2]> <dbl [2]>
#> 2     b <dbl [2]> <dbl [2]>
#> 3     c <dbl [2]> <dbl [2]>

有没有简单的方法来做这样的事情?

除此之外,我一直在尝试(但未成功)各种 stringr 和 tidyr 方法。这是一个引发错误的示例:

library(stringr)
library(tidyr)

# Find any variables with .x or .y
dup_var <- d %>% select(matches("\\.[xy]")) %>% names()

# Condense to the stems (original names) of these variables
dup_var_stems <- dup_var %>% str_replace("(\\.[x|y])+", "") %>% unique()

# For each stem, try to nest relevant data into a single variable
for (stem in dup_var_stems) {
  d <- d %>% nest_(key_col = stem, nest_cols = names(d)[str_detect(names(d), paste0(stem, "[$|\\.]"))])
}

更新

在@Sotos 和@conor 的回答之后,我会提到该解决方案需要泛化到许多数据帧上的多个连接列和重复列。下面是一个示例,其中按两列(ij)对五个数据帧进行连接。这将创建列 ab 的五个重复版本,还有大量独特的列 c:g。一个问题是复制如此多的数据帧会导致复制版本没有后缀、.x.x.x 等。 .x|.y 的简单正则表达式匹配将错过该列的无后缀版本。

library(dplyr)
library(purrr)


id_cols <- tibble(i = c("x", "x", "y", "y"),
                  j = c(1, 2, 1, 2))

df1 <- id_cols %>% cbind(tibble(a = 1:4, b = 5:8, c = 21:24))
df2 <- id_cols %>% cbind(tibble(a = 2:5, b = 6:9, d = 31:34))
df3 <- id_cols %>% cbind(tibble(a = 2:5, b = 6:9, e = 31:34))
df4 <- id_cols %>% cbind(tibble(a = 2:5, b = 6:9, f = 31:34))
df5 <- id_cols %>% cbind(tibble(a = 2:5, b = 6:9, g = 31:34))
datalist <- list(df1, df2, df3, df4, df5)

d <- reduce(datalist, full_join, by = c("i", "j"))
d
#>   i j a.x b.x  c a.y b.y  d a.x.x b.x.x  e a.y.y b.y.y  f a b  g
#> 1 x 1   1   5 21   2   6 31     2     6 31     2     6 31 2 6 31
#> 2 x 2   2   6 22   3   7 32     3     7 32     3     7 32 3 7 32
#> 3 y 1   3   7 23   4   8 33     4     8 33     4     8 33 4 8 33
#> 4 y 2   4   8 24   5   9 34     5     9 34     5     9 34 5 9 34

最佳答案

这是一次尝试,

library(dplyr)
library(tidyr)

melt(d, id.vars = 'i') %>% 
   group_by(a = sub('\\..*', '', variable), i) %>% 
   summarise(new = list(value)) %>% 
   spread(a, new)

# A tibble: 3 × 3
#      i         a         b
#* <chr>    <list>    <list>
#1     a <int [2]> <int [2]>
#2     b <int [2]> <int [2]>
#3     c <int [2]> <int [2]>

#With structure
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   3 obs. of  3 variables:
 $ i: chr  "a" "b" "c"
 $ a:List of 3
  ..$ : int  1 11
  ..$ : int  2 12
  ..$ : int  3 13
 $ b:List of 3
  ..$ : int  4 14
  ..$ : int  5 15
  ..$ : int  6 16

#Or via reshape2 package

library(dplyr)
library(reshape2)

d1 <- melt(d, id.vars = 'i') %>% 
         group_by(a = sub('\\..*', '', variable), i) %>% 
         summarise(new = list(value))

d2 <- dcast(d1, i ~ a, value.var = 'new')
#d2
#  i     a     b
#1 a 1, 11 4, 14
#2 b 2, 12 5, 15
#3 c 3, 13 6, 16

#with structure:
str(d2)
'data.frame':   3 obs. of  3 variables:
 $ i: chr  "a" "b" "c"
 $ a:List of 3
  ..$ : int  1 11
  ..$ : int  2 12
  ..$ : int  3 13
 $ b:List of 3
  ..$ : int  4 14
  ..$ : int  5 15
  ..$ : int  6 16

编辑

跟随你的想法,

library(dplyr)
library(reshape2)
library(purrr)
library(tidyr)

df <- melt(d, id.vars = c(names(d)[!grepl('a|b', names(d))]))

dots <- names(df)[!grepl('value', names(df))] %>% map(as.symbol)

df %>% mutate(variable = sub('\\..*', '', variable)) %>%
     group_by_(.dots = dots) %>%
     summarise(new = list(value)) %>%
     spread(variable, new) %>%
     ungroup()
# A tibble: 4 × 9
#      i     j     c     d     e     f     g         a         b
#* <chr> <dbl> <int> <int> <int> <int> <int>    <list>    <list>
#1     x     1    21    31    31    31    31 <int [5]> <int [5]>
#2     x     2    22    32    32    32    32 <int [5]> <int [5]>
#3     y     1    23    33    33    33    33 <int [5]> <int [5]>
#4     y     2    24    34    34    34    34 <int [5]> <int [5]>

关于r - 在 R 中与 dplyr 连接时嵌套重复变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39787133/

相关文章:

r - 将位置索引添加到列表

sql - 我怎样才能在 PostgreSQL 中得到一个随机的笛卡尔积?

javascript - 如何在数组中的全名后添加逗号?

r - 如何在 R 中一次删除多列的单个列中的重复值

r - 如何在 R 中将所有列重命名为中间分隔符?

postgresql - 加入别名列 SQL

javascript - 将两个或多个 JSON 对象数组合并到一个数组中,保持唯一性

merge - XCode Storyboard合并

2个数据库之间的MySQL同步和主键冲突

R xts 和 data.table 和 IDate