与dplyr R的笛卡尔积

时间:2017-04-05 10:21:36

标签: r dplyr cartesian-product

我试图找到笛卡尔积的dplyr函数。 我有两个简单的data.frame,没有公共变量:

x <- data.frame(x=c("a","b","c"))
y <- data.frame(y=c(1,2,3))

我想重现

的结果
merge(x,y)

  x y
1 a 1
2 b 1
3 c 1
4 a 2
5 b 2
6 c 2
7 a 3
8 b 3
9 c 3

我已经找到了这个(例如herehere)而没有找到任何有用的东西。

非常感谢

7 个答案:

答案 0 :(得分:18)

使用tidyr包中的crossing

x <- data.frame(x=c("a","b","c"))
y <- data.frame(y=c(1,2,3))

crossing(x, y)

结果:

   x y
 1 a 1
 2 a 2
 3 a 3
 4 b 1
 5 b 2
 6 b 3
 7 c 1
 8 c 2
 9 c 3

答案 1 :(得分:6)

如果我们需要tidyverse输出,我们可以使用expand中的tidyr

library(tidyverse)
y %>% 
   expand(y, x= x$x) %>%
   select(x,y)
# A tibble: 9 × 2
#       x     y
#  <fctr> <dbl>
#1      a     1
#2      b     1
#3      c     1
#4      a     2
#5      b     2
#6      c     2
#7      a     3
#8      b     3
#9      c     3

答案 2 :(得分:6)

对所有人致歉:以下示例似乎 not 不适用于data.frame或data.tables。

当x和y是数据库tbltbl_dbi / tbl_sql)时,您现在还可以执行以下操作:

full_join(x, y, by = character())

于2017年底添加到dplyr,并且在数据库世界中也转换为CROSS JOIN。节省了必须引入伪变量的麻烦。

答案 3 :(得分:5)

当遇到这个问题时,我倾向于做这样的事情:

x <- data.frame(x=c("a","b","c"))
y <- data.frame(y=c(1,2,3))
x %>% mutate(temp=1) %>% 
inner_join(y %>% mutate(temp=1),by="temp") %>%
dplyr::select(-temp) 

如果x和y是多列数据帧,但是我想要将x行和y行的每个组合进行处理,那么这比我可以提出的任何expand.grid()选项更整洁。

答案 4 :(得分:3)

expand.grid(x=c("a","b","c"),y=c(1,2,3))

编辑:考虑以下优雅解决方案来自&#34; Y T&#34;对于更复杂的data.frame:

https://stackoverflow.com/a/21911221/5350791

简而言之:

expand.grid.df <- function(...) Reduce(function(...) merge(..., by=NULL), list(...))
expand.grid.df(df1, df2, df3)

答案 5 :(得分:1)

这是dsz评论的延续。创意来源:http://jarrettmeyer.com/2018/07/10/cross-join-dplyr

tbl_1$fake <- 1
tbl_2$fake <- 1
my_cross_join <- full_join(tbl_1, tbl_2, by = "fake") %>%
                 select(-fake)

我在4到640 obs的四列数据上进行了测试,大约花费了1.08秒。

答案 6 :(得分:0)

使用上面的两个答案,使用 full_join()by = character() 似乎更快:

library(tidyverse)
library(microbenchmark)

df <- data.frame(blah = 1:10)

microbenchmark(diamonds %>% crossing(df))
Unit: milliseconds
                      expr      min       lq     mean   median       uq     max neval
 diamonds %>% crossing(df) 21.70086 22.63943 23.72622 23.01447 24.25333 30.3367   100
microbenchmark(diamonds %>% full_join(df, by = character()))
Unit: milliseconds
                                         expr      min       lq     mean   median       uq      max neval
 diamonds %>% full_join(df, by = character()) 9.814783 10.23155 10.76592 10.44343 11.18464 15.71868   100