varias superponer studio lineas hacer graficos graficas como r cross-join

studio - superponer graficas en r



¿Cómo hacer una unión cruzada en R? (8)

Esto se solicitó 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 en 2018-12-08 por el paquete reprex (v0.2.0).

¿Cómo puedo lograr una unión cruzada en R? Sé que "fusionar" puede hacer unión interna, unión externa. Pero no sé cómo lograr una unión cruzada en R.

Gracias


Me encantaría saber si existe una forma conveniente de unir dos tablas de datos. Hago esto tan a menudo que terminé desarrollando mi propia función que otros pueden encontrar útiles.

library(data.table) cartesian_join <- function(i, j){ # Cartesian join of two data.tables # If i has M rows and j has N rows, the result will have M*N rows # Example: cartesian_join(as.data.table(iris), as.data.table(mtcars)) # Check inputs if(!is.data.table(i)) stop("''i'' must be a data.table") if(!is.data.table(j)) stop("''j'' must be a data.table") if(nrow(i) == 0) stop("''i'' has 0 rows. Not sure how to handle cartesian join") if(nrow(j) == 0) stop("''j'' has 0 rows. Not sure how to handle cartesian join") # Do the join (use a join column name that''s unlikely to clash with a pre-existing column name) i[, MrJoinyJoin := 1L] j[, MrJoinyJoin := 1L] result <- j[i, on = "MrJoinyJoin", allow.cartesian = TRUE] result[, MrJoinyJoin := NULL] i[, MrJoinyJoin := NULL] j[, MrJoinyJoin := NULL] return(result[]) } foo <- data.frame(Foo = c(1,2,3)) foo Foo 1 1 2 2 3 3 bar <- data.frame(Bar = c("a", "b", "c")) bar Bar 1 a 2 b 3 c cartesian_join(as.data.table(foo), as.data.table(bar)) Bar Foo 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


Si la velocidad es un problema, sugiero revisar el excelente paquete data.table . En el ejemplo, al final es ~ 90x más rápido que la merge .

No proporcionaste datos de ejemplo. Si solo desea obtener todas las combinaciones de dos (o más columnas individuales), puede usar CJ (combinació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 realizar una combinación cruzada en dos tablas, no he encontrado una forma de usar CJ (). Pero todavía 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 de la línea de res :

  • Básicamente, agrega una columna ficticia (k en este ejemplo) a una tabla y la configura como la clave ( setkey(tablename,keycolumns) ), agrega la columna ficticia a la otra tabla y luego las une.
  • La estructura data.table utiliza posiciones de columna y no nombres en la unión, por lo que debe colocar la columna ficticia al principio. La parte c(k=1,.SD) es una forma que encontré para agregar columnas al principio (el valor predeterminado es agregarlas al final).
  • Una unión estándar data.table tiene un formato de X[Y] . La X en este caso es setkey(x2[,c(k=1,.SD)],k) , y la Y es y2[,c(k=1,.SD)] .
  • allow.cartesian=TRUE le dice a data.table que ignore los valores de clave duplicados y realice una unión cartesiana (las versiones anteriores no requerían esto)
  • El [,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 métodos data.table son mucho más rápidos que el método de merge sugerido por @ danas.zuokas. Las dos tablas con 1,000 filas en este ejemplo dan como resultado una tabla unida con 1 millón de filas. Entonces, incluso si las tablas originales son pequeñas, el resultado puede aumentar rápidamente y la velocidad es importante.

Por último, las versiones recientes de data.table requieren 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 columna. Y puede que no funcione con nombres de columna duplicados. (No dude en sugerir una versión más simple de CJ.table.2)


Si quieres hacerlo a través de data.table, esta es una forma:

cjdt <- function(a,b){ cj = CJ(1:nrow(a),1:nrow(b)) cbind(a[cj[[1]],],b[cj[[2]],]) } A = data.table(ida = 1:10) B = data.table(idb = 1:10) cjdt(A,B)

Habiendo dicho lo anterior, si está haciendo muchas combinaciones pequeñas y no necesita un objeto de data.table y la sobrecarga de producirlo, puede lograrse un aumento de velocidad significativo escribiendo un bloque de código c++ utilizando Rcpp y similares:

// [[Rcpp::export]] NumericMatrix crossJoin(NumericVector a, NumericVector b){ int szA = a.size(), szB = b.size(); int i,j,r; NumericMatrix ret(szA*szB,2); for(i = 0, r = 0; i < szA; i++){ for(j = 0; j < szB; j++, r++){ ret(r,0) = a(i); ret(r,1) = b(j); } } return ret; }

Para comparar, en primer lugar para una gran unión:

C ++

n = 1 a = runif(10000) b = runif(10000) system.time({for(i in 1:n){ crossJoin(a,b) }})

sistema de usuario transcurrido 1.033 0.424 1.462

tabla de datos

system.time({for(i in 1:n){ CJ(a,b) }})

sistema de usuario transcurrido 0.602 0.569 2.452

Ahora para un montón de pequeñas juntas:

C ++

n = 1e5 a = runif(10) b = runif(10) system.time({for(i in 1:n){ crossJoin(a,b) }})

sistema de usuario transcurrido 0.660 0.077 0.739

tabla de datos

system.time({for(i in 1:n){ CJ(a,b) }})

sistema de usuario transcurrido 26.164 0.056 26.271


Usando la función de fusión y sus parámetros opcionales:

La combinación interna: combinación (df1, df2) funcionará para estos ejemplos porque R une los marcos por nombres de variables comunes, pero lo más probable es que desee especificar la combinación (df1, df2, por = "CustomerId") para asegurarse de que coincidían solo en los campos que deseabas. También puede usar los parámetros by.x y by.y si las variables coincidentes tienen nombres diferentes en los diferentes marcos de datos.

Outer join: merge(x = df1, y = df2, by = "CustomerId", all = TRUE) Left outer: merge(x = df1, y = df2, by = "CustomerId", all.x = TRUE) Right outer: merge(x = df1, y = df2, by = "CustomerId", all.y = TRUE) Cross join: merge(x = df1, y = df2, by = NULL)


Usig sqldf :

x <- data.frame(id1 = c("a", "b", "c"), vals1 = 1:3) y <- data.frame(id2 = c("d", "e", "f"), vals2 = 4:6) library(sqldf) sqldf("SELECT * FROM x CROSS JOIN y")

Salida:

id1 vals1 id2 vals2 1 a 1 d 4 2 a 1 e 5 3 a 1 f 6 4 b 2 d 4 5 b 2 e 5 6 b 2 f 6 7 c 3 d 4 8 c 3 e 5 9 c 3 f 6

Solo para el registro, con el paquete base, podemos usar by= NULL lugar de all=TRUE :

merge(x, y, by= NULL)


¿Es sólo 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 la merge :

Si by o both by.x y by.y son de longitud 0 (un vector de longitud cero o NULL), el resultado, r, es el producto cartesiano de x e y, es decir, dim (r) = c (nrow (x ) * nrow (y), ncol (x) + ncol (y)).


No conozco una forma integrada de hacerlo con data.frame ''s, pero no es difícil de hacer.

@danas demostró que hay una forma fácil incorporada, pero dejaré mi respuesta aquí en caso de que sea útil para otros fines.

cross.join <- function(a, b) { idx <- expand.grid(seq(length=nrow(a)), seq(length=nrow(b))) cbind(a[idx[,1],], b[idx[,2],]) }

y demostrando que funciona con algunos conjuntos de datos incorporados:

> tmp <- cross.join(mtcars, iris) > dim(mtcars) [1] 32 11 > dim(iris) [1] 150 5 > dim(tmp) [1] 4800 16 > str(tmp) ''data.frame'': 4800 obs. of 16 variables: $ mpg : num 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ... $ cyl : num 6 6 4 6 8 6 8 4 4 6 ... $ disp : num 160 160 108 258 360 ... $ hp : num 110 110 93 110 175 105 245 62 95 123 ... $ drat : num 3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ... $ wt : num 2.62 2.88 2.32 3.21 3.44 ... $ qsec : num 16.5 17 18.6 19.4 17 ... $ vs : num 0 0 1 1 0 1 0 1 1 1 ... $ am : num 1 1 1 0 0 0 0 0 0 0 ... $ gear : num 4 4 4 3 3 3 3 4 4 4 ... $ carb : num 4 4 1 1 2 1 4 2 2 4 ... $ Sepal.Length: num 5.1 5.1 5.1 5.1 5.1 5.1 5.1 5.1 5.1 5.1 ... $ Sepal.Width : num 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 ... $ Petal.Length: num 1.4 1.4 1.4 1.4 1.4 1.4 1.4 1.4 1.4 1.4 ... $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 ... $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...