los pandas obtienen filas que NO están en otro marco de datos

Resuelto think nice things asked hace 9 años • 17 respuestas

Tengo dos marcos de datos de pandas que tienen algunas filas en común.

Supongamos que el marco de datos2 es un subconjunto del marco de datos1.

¿Cómo puedo obtener las filas del marco de datos1 que no están en el marco de datos2?

df1 = pandas.DataFrame(data = {'col1' : [1, 2, 3, 4, 5], 'col2' : [10, 11, 12, 13, 14]}) 
df2 = pandas.DataFrame(data = {'col1' : [1, 2, 3], 'col2' : [10, 11, 12]})

df1

   col1  col2
0     1    10
1     2    11
2     3    12
3     4    13
4     5    14

df2

   col1  col2
0     1    10
1     2    11
2     3    12

Resultado Esperado:

   col1  col2
3     4    13
4     5    14
think nice things avatar Mar 06 '15 22:03 think nice things
Aceptado

La solución actualmente seleccionada produce resultados incorrectos. Para resolver correctamente este problema, podemos realizar una unión izquierda desde df1hasta df2, asegurándonos de obtener primero solo las filas únicas para df2.

Primero, necesitamos modificar el DataFrame original para agregar la fila con datos [3, 10].

df1 = pd.DataFrame(data = {'col1' : [1, 2, 3, 4, 5, 3], 
                           'col2' : [10, 11, 12, 13, 14, 10]}) 
df2 = pd.DataFrame(data = {'col1' : [1, 2, 3],
                           'col2' : [10, 11, 12]})

df1

   col1  col2
0     1    10
1     2    11
2     3    12
3     4    13
4     5    14
5     3    10

df2

   col1  col2
0     1    10
1     2    11
2     3    12

Realice una unión izquierda, eliminando duplicados df2para que cada fila de df1uniones con exactamente 1 fila de df2. Utilice el parámetro indicatorpara devolver una columna adicional que indique de qué tabla proviene la fila.

df_all = df1.merge(df2.drop_duplicates(), on=['col1','col2'], 
                   how='left', indicator=True)
df_all

   col1  col2     _merge
0     1    10       both
1     2    11       both
2     3    12       both
3     4    13  left_only
4     5    14  left_only
5     3    10  left_only

Crea una condición booleana:

df_all['_merge'] == 'left_only'

0    False
1    False
2    False
3     True
4     True
5     True
Name: _merge, dtype: bool

Por qué otras soluciones son incorrectas

Algunas soluciones cometen el mismo error: solo verifican que cada valor esté independientemente en cada columna, no juntos en la misma fila. Agregar la última fila, que es única pero tiene los valores de ambas columnas, df2expone el error:

common = df1.merge(df2,on=['col1','col2'])
(~df1.col1.isin(common.col1))&(~df1.col2.isin(common.col2))
0    False
1    False
2    False
3     True
4     True
5    False
dtype: bool

Esta solución obtiene el mismo resultado incorrecto:

df1.isin(df2.to_dict('l')).all(1)
Ted Petrou avatar Nov 04 '2017 03:11 Ted Petrou

Un método sería almacenar el resultado de una combinación interna de ambos dfs, luego podemos simplemente seleccionar las filas cuando los valores de una columna no estén en este común:

In [119]:

common = df1.merge(df2,on=['col1','col2'])
print(common)
df1[(~df1.col1.isin(common.col1))&(~df1.col2.isin(common.col2))]
   col1  col2
0     1    10
1     2    11
2     3    12
Out[119]:
   col1  col2
3     4    13
4     5    14

EDITAR

Otro método que ha encontrado es utilizar isinel cual producirá NaNfilas que puede eliminar:

In [138]:

df1[~df1.isin(df2)].dropna()
Out[138]:
   col1  col2
3     4    13
4     5    14

Sin embargo, si df2 no ​​inicia las filas de la misma manera, esto no funcionará:

df2 = pd.DataFrame(data = {'col1' : [2, 3,4], 'col2' : [11, 12,13]})

producirá el df completo:

In [140]:

df1[~df1.isin(df2)].dropna()
Out[140]:
   col1  col2
0     1    10
1     2    11
2     3    12
3     4    13
4     5    14
EdChum avatar Mar 06 '2015 15:03 EdChum