Tengo dos marcos de datos. Ejemplos:
df1:
Date Fruit Num Color
2013-11-24 Banana 22.1 Yellow
2013-11-24 Orange 8.6 Orange
2013-11-24 Apple 7.6 Green
2013-11-24 Celery 10.2 Green
df2:
Date Fruit Num Color
2013-11-24 Banana 22.1 Yellow
2013-11-24 Orange 8.6 Orange
2013-11-24 Apple 7.6 Green
2013-11-24 Celery 10.2 Green
2013-11-25 Apple 22.1 Red
2013-11-25 Orange 8.6 Orange
Cada marco de datos tiene la fecha como índice. Ambos marcos de datos tienen la misma estructura.
Lo que quiero hacer es comparar estos dos marcos de datos y encontrar qué filas están en df2 y no en df1. Quiero comparar la fecha (índice) y la primera columna (Banana, APple, etc.) para ver si existen en df2 vs df1.
He probado lo siguiente:
- Salida de la diferencia en dos marcos de datos de Pandas uno al lado del otro, resaltando la diferencia
- Comparación de dos marcos de datos de pandas para detectar diferencias
Para el primer enfoque, aparece este error: "Excepción: solo se pueden comparar objetos DataFrame con etiquetas idénticas" . Intenté eliminar la fecha como índice pero aparece el mismo error.
En el tercer enfoque , obtengo que la aserción devuelva False pero no puedo averiguar cómo ver realmente las diferentes filas.
Cualquier sugerencia sería bienvenida
Respuestas:
Este enfoque
df1 != df2
funciona solo para marcos de datos con filas y columnas idénticas. De hecho, todos los ejes de los marcos de datos se comparan con el_indexed_same
método y se genera una excepción si se encuentran diferencias, incluso en el orden de columnas / índices.Si lo entendí bien, no querrá encontrar cambios, sino diferencias simétricas. Para eso, un enfoque podría ser concatenar marcos de datos:
>>> df = pd.concat([df1, df2]) >>> df = df.reset_index(drop=True)
agrupar por
>>> df_gpby = df.groupby(list(df.columns))
obtener índice de registros únicos
>>> idx = [x[0] for x in df_gpby.groups.values() if len(x) == 1]
filtrar
>>> df.reindex(idx) Date Fruit Num Color 9 2013-11-25 Orange 8.6 Orange 8 2013-11-25 Apple 22.1 Red
fuente
pd.concat
agrega solo los elementos que faltan deldf1
? ¿O reemplazadf1
completamente condf2
?pd.concat
, como se usa aquí, hace una combinación externa. En otras palabras, se une a todos los índices de ambos df y éste es, de hecho, el comportamiento predeterminado depd.concat()
, aquí está la documentación pandas.pydata.org/pandas-docs/stable/merging.htmlPasar los marcos de datos a concat en un diccionario, da como resultado un marco de datos de múltiples índices del que puede eliminar fácilmente los duplicados, lo que da como resultado un marco de datos de múltiples índices con las diferencias entre los marcos de datos:
import sys if sys.version_info[0] < 3: from StringIO import StringIO else: from io import StringIO import pandas as pd DF1 = StringIO("""Date Fruit Num Color 2013-11-24 Banana 22.1 Yellow 2013-11-24 Orange 8.6 Orange 2013-11-24 Apple 7.6 Green 2013-11-24 Celery 10.2 Green """) DF2 = StringIO("""Date Fruit Num Color 2013-11-24 Banana 22.1 Yellow 2013-11-24 Orange 8.6 Orange 2013-11-24 Apple 7.6 Green 2013-11-24 Celery 10.2 Green 2013-11-25 Apple 22.1 Red 2013-11-25 Orange 8.6 Orange""") df1 = pd.read_table(DF1, sep='\s+') df2 = pd.read_table(DF2, sep='\s+') #%% dfs_dictionary = {'DF1':df1,'DF2':df2} df=pd.concat(dfs_dictionary) df.drop_duplicates(keep=False)
Resultado:
Date Fruit Num Color DF2 4 2013-11-25 Apple 22.1 Red 5 2013-11-25 Orange 8.6 Orange
fuente
dict
!Actualizando y colocando, en algún lugar donde sea más fácil para otros encontrar, el comentario de ling sobre la respuesta de jur anterior.
df_diff = pd.concat([df1,df2]).drop_duplicates(keep=False)
Prueba con estos marcos de datos:
df1=pd.DataFrame({ 'Date':['2013-11-24','2013-11-24','2013-11-24','2013-11-24'], 'Fruit':['Banana','Orange','Apple','Celery'], 'Num':[22.1,8.6,7.6,10.2], 'Color':['Yellow','Orange','Green','Green'], }) df2=pd.DataFrame({ 'Date':['2013-11-24','2013-11-24','2013-11-24','2013-11-24','2013-11-25','2013-11-25'], 'Fruit':['Banana','Orange','Apple','Celery','Apple','Orange'], 'Num':[22.1,8.6,7.6,10.2,22.1,8.6], 'Color':['Yellow','Orange','Green','Green','Red','Orange'], })
Resultados en esto:
fuente
Sobre la base de la respuesta de alko que casi funcionó para mí, excepto por el paso de filtrado (donde obtengo :)
ValueError: cannot reindex from a duplicate axis
, aquí está la solución final que utilicé:# join the dataframes united_data = pd.concat([data1, data2, data3, ...]) # group the data by the whole row to find duplicates united_data_grouped = united_data.groupby(list(united_data.columns)) # detect the row indices of unique rows uniq_data_idx = [x[0] for x in united_data_grouped.indices.values() if len(x) == 1] # extract those unique values uniq_data = united_data.iloc[uniq_data_idx]
fuente
IndexError: index out of bounds'
, cuando intento ejecutar la tercera línea.# THIS WORK FOR ME # Get all diferent values df3 = pd.merge(df1, df2, how='outer', indicator='Exist') df3 = df3.loc[df3['Exist'] != 'both'] # If you like to filter by a common ID df3 = pd.merge(df1, df2, on="Fruit", how='outer', indicator='Exist') df3 = df3.loc[df3['Exist'] != 'both']
fuente
Existe una solución más simple, más rápida y mejor, y si los números son diferentes, incluso pueden darte diferencias de cantidades:
df1_i = df1.set_index(['Date','Fruit','Color']) df2_i = df2.set_index(['Date','Fruit','Color']) df_diff = df1_i.join(df2_i,how='outer',rsuffix='_').fillna(0) df_diff = (df_diff['Num'] - df_diff['Num_'])
Aquí df_diff es una sinopsis de las diferencias. Incluso puede usarlo para encontrar las diferencias en cantidades. En tu ejemplo:
Explicación: De manera similar a comparar dos listas, para hacerlo de manera eficiente, primero debemos ordenarlas y luego compararlas (convertir la lista a conjuntos / hash también sería rápido; ambos son una mejora increíble para el simple ciclo de comparación doble O (N ^ 2)
Nota: el siguiente código produce las tablas:
df1=pd.DataFrame({ 'Date':['2013-11-24','2013-11-24','2013-11-24','2013-11-24'], 'Fruit':['Banana','Orange','Apple','Celery'], 'Num':[22.1,8.6,7.6,10.2], 'Color':['Yellow','Orange','Green','Green'], }) df2=pd.DataFrame({ 'Date':['2013-11-24','2013-11-24','2013-11-24','2013-11-24','2013-11-25','2013-11-25'], 'Fruit':['Banana','Orange','Apple','Celery','Apple','Orange'], 'Num':[22.1,8.6,7.6,10.2,22.1,8.6], 'Color':['Yellow','Orange','Green','Green','Red','Orange'], })
fuente
Fundador de una solución simple aquí:
https://stackoverflow.com/a/47132808/9656339
pd.concat([df1, df2]).loc[df1.index.symmetric_difference(df2.index)]
fuente
# given df1=pd.DataFrame({'Date':['2013-11-24','2013-11-24','2013-11-24','2013-11-24'], 'Fruit':['Banana','Orange','Apple','Celery'], 'Num':[22.1,8.6,7.6,10.2], 'Color':['Yellow','Orange','Green','Green']}) df2=pd.DataFrame({'Date':['2013-11-24','2013-11-24','2013-11-24','2013-11-24','2013-11-25','2013-11-25'], 'Fruit':['Banana','Orange','Apple','Celery','Apple','Orange'], 'Num':[22.1,8.6,7.6,1000,22.1,8.6], 'Color':['Yellow','Orange','Green','Green','Red','Orange']}) # find which rows are in df2 that aren't in df1 by Date and Fruit df_2notin1 = df2[~(df2['Date'].isin(df1['Date']) & df2['Fruit'].isin(df1['Fruit']) )].dropna().reset_index(drop=True) # output print('df_2notin1\n', df_2notin1) # Color Date Fruit Num # 0 Red 2013-11-25 Apple 22.1 # 1 Orange 2013-11-25 Orange 8.6
fuente
Tengo esta solución. ¿Esto te ayuda?
text = """df1: 2013-11-24 Banana 22.1 Yellow 2013-11-24 Orange 8.6 Orange 2013-11-24 Apple 7.6 Green 2013-11-24 Celery 10.2 Green df2: 2013-11-24 Banana 22.1 Yellow 2013-11-24 Orange 8.6 Orange 2013-11-24 Apple 7.6 Green 2013-11-24 Celery 10.2 Green 2013-11-25 Apple 22.1 Red 2013-11-25 Orange 8.6 Orange argetz45 2013-11-24 Banana 22.1 Yellow 2013-11-24 Orange 118.6 Orange 2013-11-24 Apple 74.6 Green 2013-11-24 Celery 10.2 Green 2013-11-25 Nuts 45.8 Brown 2013-11-25 Apple 22.1 Red 2013-11-25 Orange 8.6 Orange 2013-11-26 Pear 102.54 Pale"""
.
from collections import OrderedDict import re r = re.compile('([a-zA-Z\d]+).*\n' '(20\d\d-[01]\d-[0123]\d.+\n?' '(.+\n?)*)' '(?=[ \n]*\Z' '|' '\n+[a-zA-Z\d]+.*\n' '20\d\d-[01]\d-[0123]\d)') r2 = re.compile('((20\d\d-[01]\d-[0123]\d) +([^\d.]+)(?<! )[^\n]+)') d = OrderedDict() bef = [] for m in r.finditer(text): li = [] for x in r2.findall(m.group(2)): if not any(x[1:3]==elbef for elbef in bef): bef.append(x[1:3]) li.append(x[0]) d[m.group(1)] = li for name,lu in d.iteritems(): print '%s\n%s\n' % (name,'\n'.join(lu))
resultado
df1 2013-11-24 Banana 22.1 Yellow 2013-11-24 Orange 8.6 Orange 2013-11-24 Apple 7.6 Green 2013-11-24 Celery 10.2 Green df2 2013-11-25 Apple 22.1 Red 2013-11-25 Orange 8.6 Orange argetz45 2013-11-25 Nuts 45.8 Brown 2013-11-26 Pear 102.54 Pale
fuente
Dado
pandas >= 1.1.0
que tenemosDataFrame.compare
ySeries.compare
.df1 = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6], 'C': [7, np.NaN, 9]}) df2 = pd.DataFrame({'A': [1, 99, 3], 'B': [4, 5, 81], 'C': [7, 8, 9]}) A B C 0 1 4 7.0 1 2 5 NaN 2 3 6 9.0 A B C 0 1 4 7 1 99 5 8 2 3 81 9
df1.compare(df2) A B C self other self other self other 1 2.0 99.0 NaN NaN NaN 8.0 2 NaN NaN 6.0 81.0 NaN NaN
fuente
Un detalle importante a tener en cuenta es que sus datos tienen valores de índice duplicados , por lo que para realizar cualquier comparación sencilla, debemos convertir todo en único con
df.reset_index()
y, por lo tanto, podemos realizar selecciones en función de las condiciones. Una vez que en su caso se define el índice, supongo que le gustaría mantener el índice para que haya una solución de una línea:[~df2.reset_index().isin(df1.reset_index())].dropna().set_index('Date')
Una vez que el objetivo desde una perspectiva pitónica es mejorar la legibilidad, podemos romper un poco:
# keep the index name, if it does not have a name it uses the default name index_name = df.index.name if df.index.name else 'index' # setting the index to become unique df1 = df1.reset_index() df2 = df2.reset_index() # getting the differences to a Dataframe df_diff = df2[~df2.isin(df1)].dropna().set_index(index_name)
fuente
Espero que esto te sea de utilidad. ^ o ^
df1 = pd.DataFrame({'date': ['0207', '0207'], 'col1': [1, 2]}) df2 = pd.DataFrame({'date': ['0207', '0207', '0208', '0208'], 'col1': [1, 2, 3, 4]}) print(f"df1(Before):\n{df1}\ndf2:\n{df2}") """ df1(Before): date col1 0 0207 1 1 0207 2 df2: date col1 0 0207 1 1 0207 2 2 0208 3 3 0208 4 """ old_set = set(df1.index.values) new_set = set(df2.index.values) new_data_index = new_set - old_set new_data_list = [] for idx in new_data_index: new_data_list.append(df2.loc[idx]) if len(new_data_list) > 0: df1 = df1.append(new_data_list) print(f"df1(After):\n{df1}") """ df1(After): date col1 0 0207 1 1 0207 2 2 0208 3 3 0208 4 """
fuente
Probé este método y funcionó. Espero que también pueda ayudar:
"""Identify differences between two pandas DataFrames""" df1.sort_index(inplace=True) df2.sort_index(inplace=True) df_all = pd.concat([df1, df12], axis='columns', keys=['First', 'Second']) df_final = df_all.swaplevel(axis='columns')[df1.columns[1:]] df_final[df_final['change this to one of the columns'] != df_final['change this to one of the columns']]
fuente