Seleccione filas de un marco de datos que no estén presentes en un segundo marco de datos
Tengo dos marcos de datos:
a1 <- data.frame(a = 1:5, b=letters[1:5])
a2 <- data.frame(a = 1:3, b=letters[1:3])
Quiero encontrar las filas que tiene a1 y que no tiene a2.
¿Existe una función integrada para este tipo de operación?
(PD: escribí una solución para ello, simplemente tengo curiosidad por saber si alguien ya creó un código más elaborado)
Aquí está mi solución:
a1 <- data.frame(a = 1:5, b=letters[1:5])
a2 <- data.frame(a = 1:3, b=letters[1:3])
rows.in.a1.that.are.not.in.a2 <- function(a1,a2)
{
a1.vec <- apply(a1, 1, paste, collapse = "")
a2.vec <- apply(a2, 1, paste, collapse = "")
a1.without.a2.rows <- a1[!a1.vec %in% a2.vec,]
return(a1.without.a2.rows)
}
rows.in.a1.that.are.not.in.a2(a1,a2)
sqldf
proporciona una buena solución
a1 <- data.frame(a = 1:5, b=letters[1:5])
a2 <- data.frame(a = 1:3, b=letters[1:3])
require(sqldf)
a1NotIna2 <- sqldf('SELECT * FROM a1 EXCEPT SELECT * FROM a2')
Y las filas que están en ambos marcos de datos:
a1Ina2 <- sqldf('SELECT * FROM a1 INTERSECT SELECT * FROM a2')
La nueva versión de dplyr
tiene una función, anti_join
exactamente para este tipo de comparaciones.
require(dplyr)
anti_join(a1,a2)
Y semi_join
para filtrar filas a1
que también están ena2
semi_join(a1,a2)
En dplyr :
setdiff(a1,a2)
Básicamente, setdiff(bigFrame, smallFrame)
obtiene los registros adicionales en la primera tabla.
En SQLverse esto se llama
Para obtener buenas descripciones de todas las opciones de unión y temas establecidos, este es uno de los mejores resúmenes que he visto hasta la fecha: http://www.vertabelo.com/blog/technical-articles/sql-joins
Pero volvamos a esta pregunta: aquí están los resultados del setdiff()
código cuando se utilizan los datos del OP:
> a1
a b
1 1 a
2 2 b
3 3 c
4 4 d
5 5 e
> a2
a b
1 1 a
2 2 b
3 3 c
> setdiff(a1,a2)
a b
1 4 d
2 5 e
O incluso anti_join(a1,a2)
obtendrá los mismos resultados.
Para más información: https://www.rstudio.com/wp-content/uploads/2015/02/data-wrangling-cheatsheet.pdf
Esto no responde directamente a su pregunta, pero le brindará los elementos que tienen en común. Esto se puede hacer con el paquete de Paul Murrell compare
:
library(compare)
a1 <- data.frame(a = 1:5, b = letters[1:5])
a2 <- data.frame(a = 1:3, b = letters[1:3])
comparison <- compare(a1,a2,allowAll=TRUE)
comparison$tM
# a b
#1 1 a
#2 2 b
#3 3 c
La función compare
le brinda mucha flexibilidad en términos de qué tipo de comparaciones se permiten (por ejemplo, cambiar el orden de los elementos de cada vector, cambiar el orden y los nombres de las variables, acortar las variables, cambiar el caso de las cadenas). A partir de esto, deberías poder descubrir qué faltaba en uno u otro. Por ejemplo (esto no es muy elegante):
difference <-
data.frame(lapply(1:ncol(a1),function(i)setdiff(a1[,i],comparison$tM[,i])))
colnames(difference) <- colnames(a1)
difference
# a b
#1 4 d
#2 5 e
Ciertamente no es eficiente para este propósito particular, pero lo que hago a menudo en estas situaciones es insertar variables indicadoras en cada data.frame y luego fusionar:
a1$included_a1 <- TRUE
a2$included_a2 <- TRUE
res <- merge(a1, a2, all=TRUE)
Los valores faltantes en include_a1 indicarán qué filas faltan en a1. lo mismo para a2.
Un problema con su solución es que el orden de las columnas debe coincidir. Otro problema es que es fácil imaginar situaciones en las que las filas están codificadas como iguales cuando en realidad son diferentes. La ventaja de utilizar merge es que obtienes de forma gratuita todas las comprobaciones de errores necesarias para encontrar una buena solución.
Escribí un paquete ( https://github.com/alexsanjoseph/compareDF ) ya que tuve el mismo problema.
> df1 <- data.frame(a = 1:5, b=letters[1:5], row = 1:5)
> df2 <- data.frame(a = 1:3, b=letters[1:3], row = 1:3)
> df_compare = compare_df(df1, df2, "row")
> df_compare$comparison_df
row chng_type a b
1 4 + 4 d
2 5 + 5 e
Un ejemplo más complicado:
library(compareDF)
df1 = data.frame(id1 = c("Mazda RX4", "Mazda RX4 Wag", "Datsun 710",
"Hornet 4 Drive", "Duster 360", "Merc 240D"),
id2 = c("Maz", "Maz", "Dat", "Hor", "Dus", "Mer"),
hp = c(110, 110, 181, 110, 245, 62),
cyl = c(6, 6, 4, 6, 8, 4),
qsec = c(16.46, 17.02, 33.00, 19.44, 15.84, 20.00))
df2 = data.frame(id1 = c("Mazda RX4", "Mazda RX4 Wag", "Datsun 710",
"Hornet 4 Drive", " Hornet Sportabout", "Valiant"),
id2 = c("Maz", "Maz", "Dat", "Hor", "Dus", "Val"),
hp = c(110, 110, 93, 110, 175, 105),
cyl = c(6, 6, 4, 6, 8, 6),
qsec = c(16.46, 17.02, 18.61, 19.44, 17.02, 20.22))
> df_compare$comparison_df
grp chng_type id1 id2 hp cyl qsec
1 1 - Hornet Sportabout Dus 175 8 17.02
2 2 + Datsun 710 Dat 181 4 33.00
3 2 - Datsun 710 Dat 93 4 18.61
4 3 + Duster 360 Dus 245 8 15.84
5 7 + Merc 240D Mer 62 4 20.00
6 8 - Valiant Val 105 6 20.22
El paquete también tiene un comando html_output para una verificación rápida.
df_compare$html_output