python - recorrer - los pandas obtienen filas que NO están en otro marco de datos
recorrer filas pandas (11)
Aquí hay otra forma de resolver esto:
df1[~df1.index.isin(df1.merge(df2, how=''inner'', on=[''col1'', ''col2'']).index)]
O:
df1.loc[df1.index.difference(df1.merge(df2, how=''inner'', on=[''col1'', ''col2'']).index)]
Tengo dos marcos de datos de pandas que tienen algunas filas en común.
Supongamos que dataframe2 es un subconjunto de dataframe1.
¿Cómo puedo obtener las filas de dataframe1 que no están en dataframe2?
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]})
Como ya se insinuó, isin requiere que las columnas y los índices sean los mismos para una coincidencia. Si la coincidencia solo debe estar en el contenido de la fila, una forma de obtener la máscara para filtrar las filas presentes es convertir las filas en un Índice (Multi):
In [77]: df1 = pandas.DataFrame(data = {''col1'' : [1, 2, 3, 4, 5, 3], ''col2'' : [10, 11, 12, 13, 14, 10]})
In [78]: df2 = pandas.DataFrame(data = {''col1'' : [1, 3, 4], ''col2'' : [10, 12, 13]})
In [79]: df1.loc[~df1.set_index(list(df1.columns)).index.isin(df2.set_index(list(df2.columns)).index)]
Out[79]:
col1 col2
1 2 11
4 5 14
5 3 10
Si se debe tener en cuenta el índice, set_index tiene un argumento de palabra clave anexar para agregar columnas al índice existente. Si las columnas no se alinean, la lista (df.columns) se puede reemplazar con especificaciones de columna para alinear los datos.
pandas.MultiIndex.from_tuples(df<N>.to_records(index = False).tolist())
alternativamente podría usarse para crear los índices, aunque dudo que esto sea más eficiente.
La solución actualmente seleccionada produce resultados incorrectos.
Para resolver correctamente este problema, podemos realizar una unión izquierda de
df1
a
df2
, asegurándonos primero de obtener 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 en
df2
para que cada fila de
df1
una con exactamente 1 fila de
df2
.
Use el
indicator
parámetro para devolver una columna adicional que indique de qué tabla era 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
Crear 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 están mal?
Algunas soluciones cometen el mismo error: solo verifican que cada valor sea independiente en cada columna, no juntos en la misma fila.
Agregar la última fila, que es única pero tiene los valores de ambas columnas de
df2
expone 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)
Mi forma de hacerlo implica agregar una nueva columna que sea única para un marco de datos y usar esto para elegir si se debe mantener una entrada
df2[col3] = 1
df1 = pd.merge(df_1, df_2, on=[''field_x'', ''field_y''], how = ''outer'')
df1[''Empt''].fillna(0, inplace=True)
Esto hace que cada entrada en df1 tenga un código: 0 si es exclusivo de df1, 1 si está en ambos dataFrames. Luego usa esto para restringir a lo que quieres
answer = nonuni[nonuni[''Empt''] == 0]
Qué tal esto:
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]})
records_df2 = set([tuple(row) for row in df2.values])
in_df2_mask = np.array([tuple(row) in records_df2 for row in df1.values])
result = df1[~in_df2_mask]
Supongamos que tiene dos marcos de datos, df_1 y df_2 con múltiples campos (nombres de columna) y desea encontrar las únicas entradas en df_1 que no están en df_2 en función de algunos campos (por ejemplo, fields_x, fields_y), siga los siguientes pasos.
Paso 1.Agregue una columna key1 y key2 a df_1 y df_2 respectivamente.
Paso 2. Combina los marcos de datos como se muestra a continuación. field_x y field_y son nuestras columnas deseadas.
Paso 3. Seleccione solo aquellas filas de df_1 donde key1 no es igual a key2.
Paso4.Drop key1 y key2.
Este método resolverá su problema y funciona rápido incluso con grandes conjuntos de datos. Lo he probado para marcos de datos con más de 1,000,000 de filas.
df_1[''key1''] = 1
df_2[''key2''] = 1
df_1 = pd.merge(df_1, df_2, on=[''field_x'', ''field_y''], how = ''left'')
df_1 = df_1[~(df_1.key2 == df_1.key1)]
df_1 = df_1.drop([''key1'',''key2''], axis=1)
Suponiendo que los índices son consistentes en los marcos de datos (sin tener en cuenta los valores reales de col):
df1[~df1.index.isin(df2.index)]
También puede concat
df1
,
df2
:
x = pd.concat([df1, df2])
y luego elimine todos los duplicados:
y = x.drop_duplicates(keep=False, inplace=False)
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 son tan comunes:
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 usar
isin
que producirá filas de
NaN
que puede soltar:
In [138]:
df1[~df1.isin(df2)].dropna()
Out[138]:
col1 col2
3 4 13
4 5 14
Sin embargo, si df2 no inicia filas de la misma manera, esto no funcionará:
df2 = pd.DataFrame(data = {''col1'' : [2, 3,4], ''col2'' : [11, 12,13]})
producirá todo el df:
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
puedes hacerlo usando el método isin(dict) :
In [74]: df1[~df1.isin(df2.to_dict(''l'')).all(1)]
Out[74]:
col1 col2
3 4 13
4 5 14
Explicación:
In [75]: df2.to_dict(''l'')
Out[75]: {''col1'': [1, 2, 3], ''col2'': [10, 11, 12]}
In [76]: df1.isin(df2.to_dict(''l''))
Out[76]:
col1 col2
0 True True
1 True True
2 True True
3 False False
4 False False
In [77]: df1.isin(df2.to_dict(''l'')).all(1)
Out[77]:
0 True
1 True
2 True
3 False
4 False
dtype: bool
un poco tarde, pero puede valer la pena verificar el parámetro "indicador" de pd.merge.
Vea esta otra pregunta para ver un ejemplo: Compare PandaS DataFrames y devuelva las filas que faltan en la primera