Solución:
Si la velocidad es un problema, sugiero que revise el excelente data.table
paquete. En el ejemplo al final, es ~ 90 veces más rápido que merge
.
No proporcionaste datos de ejemplo. Si solo desea obtener todas las combinaciones de dos (o más columnas individuales), puede usar CJ
(unión cruzada):
library(data.table)
CJ(x=1:2,y=letters[1:3])
# x y
#1: 1 a
#2: 1 b
#3: 1 c
#4: 2 a
#5: 2 b
#6: 2 c
Si desea hacer una combinación cruzada en dos tablas, no he encontrado una forma de usar CJ (). Pero aún puedes usar data.table
:
x2<-data.table(id1=letters[1:3],vals1=1:3)
y2<-data.table(id2=letters[4:7],vals2=4:7)
res<-setkey(x2[,c(k=1,.SD)],k)[y2[,c(k=1,.SD)],allow.cartesian=TRUE][,k:=NULL]
res
# id1 vals1 id2 vals2
# 1: a 1 d 4
# 2: b 2 d 4
# 3: c 3 d 4
# 4: a 1 e 5
# 5: b 2 e 5
# 6: c 3 e 5
# 7: a 1 f 6
# 8: b 2 f 6
# 9: c 3 f 6
#10: a 1 g 7
#11: b 2 g 7
#12: c 3 g 7
Explicación del res
línea:
- Básicamente, agrega una columna ficticia (k en este ejemplo) a una tabla y la establece como clave (
setkey(tablename,keycolumns)
), agregue la columna ficticia a la otra tabla y luego únalas. - La estructura data.table usa posiciones de columna y no nombres en la combinación, por lo que debe colocar la columna ficticia al principio. los
c(k=1,.SD)
parte es una forma que he encontrado para agregar columnas al principio (el valor predeterminado es agregarlas al final). - Una combinación de data.table estándar tiene un formato de
X[Y]
. La X en este caso essetkey(x2[,c(k=1,.SD)],k)
, y la Y esy2[,c(k=1,.SD)]
. -
allow.cartesian=TRUE
dicedata.table
para ignorar los valores clave duplicados y realizar una unión cartesiana (las versiones anteriores no requerían esto) - los
[,k:=NULL]
al final, simplemente elimina la clave ficticia del resultado.
También puede convertir esto en una función, por lo que es más limpio de usar:
# Version 1; easier to write:
CJ.table.1 <- function(X,Y)
setkey(X[,c(k=1,.SD)],k)[Y[,c(k=1,.SD)],allow.cartesian=TRUE][,k:=NULL]
CJ.table.1(x2,y2)
# id1 vals1 id2 vals2
# 1: a 1 d 4
# 2: b 2 d 4
# 3: c 3 d 4
# 4: a 1 e 5
# 5: b 2 e 5
# 6: c 3 e 5
# 7: a 1 f 6
# 8: b 2 f 6
# 9: c 3 f 6
#10: a 1 g 7
#11: b 2 g 7
#12: c 3 g 7
# Version 2; faster but messier:
CJ.table.2 <- function(X,Y) {
eval(parse(text=paste0("setkey(X[,c(k=1,.SD)],k)[Y[,c(k=1,.SD)],list(",paste0(unique(c(names(X),names(Y))),collapse=","),")][,k:=NULL]")))
}
Aquí hay algunos puntos de referencia de velocidad:
# Create a bigger (but still very small) example:
n<-1e3
x3<-data.table(id1=1L:n,vals1=sample(letters,n,replace=T))
y3<-data.table(id2=1L:n,vals2=sample(LETTERS,n,replace=T))
library(microbenchmark)
microbenchmark(merge=merge.data.frame(x3,y3,all=TRUE),
CJ.table.1=CJ.table.1(x3,y3),
CJ.table.2=CJ.table.2(x3,y3),
times=3, unit="s")
#Unit: seconds
# expr min lq median uq max neval
# merge 4.03710225 4.23233688 4.42757152 5.57854711 6.72952271 3
# CJ.table.1 0.06227603 0.06264222 0.06300842 0.06701880 0.07102917 3
# CJ.table.2 0.04740142 0.04812997 0.04885853 0.05433146 0.05980440 3
Tenga en cuenta que estos data.table
Los métodos son mucho más rápidos que los merge
método sugerido por @ danas.zuokas. Las dos tablas con 1000 filas en este ejemplo dan como resultado una tabla cruzada con 1 millón de filas. Entonces, incluso si sus tablas originales son pequeñas, el resultado puede crecer rápidamente y la velocidad se vuelve importante.
Por último, las versiones recientes de data.table
requiere que agregue el allow.cartesian=TRUE
(como en CJ.table.1) o especifique los nombres de las columnas que deben devolverse (CJ.table.2). El segundo método (CJ.table.2) parece ser más rápido, pero requiere un código más complicado si desea especificar automáticamente todos los nombres de las columnas. Y puede que no funcione con nombres de columna duplicados. (No dude en sugerir una versión más simple de CJ.table.2)
Es solo all=TRUE
?
x<-data.frame(id1=c("a","b","c"),vals1=1:3)
y<-data.frame(id2=c("d","e","f"),vals2=4:6)
merge(x,y,all=TRUE)
De la documentación de merge
:
Si by o ambos by.xy by.y son de longitud 0 (un vector de longitud cero o NULL), el resultado, r, es el producto cartesiano de xey, es decir, dim (r) = c (nrow (x ) * nrow (y), ncol (x) + ncol (y)).
Esto se preguntó hace años, pero puede usar tidyr::crossing()
para hacer una unión cruzada. Definitivamente la solución más simple del grupo.
library(tidyr)
league <- c("MLB", "NHL", "NFL", "NBA")
season <- c("2018", "2017")
tidyr::crossing(league, season)
#> # A tibble: 8 x 2
#> league season
#> <chr> <chr>
#> 1 MLB 2017
#> 2 MLB 2018
#> 3 NBA 2017
#> 4 NBA 2018
#> 5 NFL 2017
#> 6 NFL 2018
#> 7 NHL 2017
#> 8 NHL 2018
Creado el 2018-12-08 por el paquete reprex (v0.2.0).