Mam dwie ramki danych. Przykłady:
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
Każda ramka danych ma datę jako indeks. Obie ramki danych mają taką samą strukturę.
Co chcę zrobić, to porównać te dwie ramki danych i znaleźć wiersze w df2, które nie są w df1. Chcę porównać datę (indeks) i pierwszą kolumnę (banan, jabłko itp.), Aby sprawdzić, czy istnieją w df2 vs df1.
Próbowałem następujących rzeczy:
- Wyświetlanie różnicy w dwóch ramkach danych Pandas obok siebie - podkreślanie różnicy
- Porównanie dwóch ramek danych pand pod kątem różnic
W przypadku pierwszego podejścia pojawia się ten błąd: „Wyjątek: można porównać tylko obiekty DataFrame o identycznych etykietach” . Próbowałem usunąć datę jako indeks, ale pojawia się ten sam błąd.
Przy trzecim podejściu asercja zwraca False, ale nie mogę dowiedzieć się, jak faktycznie zobaczyć różne wiersze.
Wszelkie wskazówki byłyby mile widziane
Odpowiedzi:
To podejście
df1 != df2
działa tylko w przypadku ramek danych z identycznymi wierszami i kolumnami. W rzeczywistości wszystkie osie ramek danych są porównywane z_indexed_same
metodą, a wyjątek jest zgłaszany w przypadku znalezienia różnic, nawet w kolejności kolumn / indeksów.Jeśli dobrze zrozumiałem, nie chcesz znaleźć zmian, ale symetryczną różnicę. W tym celu jednym podejściem może być konkatenacja ramek danych:
>>> df = pd.concat([df1, df2]) >>> df = df.reset_index(drop=True)
Grupuj według
>>> df_gpby = df.groupby(list(df.columns))
uzyskać indeks unikalnych rekordów
>>> idx = [x[0] for x in df_gpby.groups.values() if len(x) == 1]
filtr
>>> df.reindex(idx) Date Fruit Num Color 9 2013-11-25 Orange 8.6 Orange 8 2013-11-25 Apple 22.1 Red
źródło
pd.concat
dodaje tylko brakujące elementy zdf1
? A możedf1
całkowicie zastępujedf2
?pd.concat
- tak jak tutaj użyto - wykonuje sprzężenie zewnętrzne. Innymi słowy, łączy wszystkie indeksy z obu df i jest to w rzeczywistości domyślne zachowanie dlapd.concat()
, oto dokumentacja pandas.pydata.org/pandas-docs/stable/merging.htmlPrzekazanie ramek danych do konkatacji w słowniku daje w wyniku ramkę danych z wieloma indeksami, z której można łatwo usunąć duplikaty, co skutkuje ramką danych z wieloma indeksami z różnicami między ramkami danych:
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)
Wynik:
Date Fruit Num Color DF2 4 2013-11-25 Apple 22.1 Red 5 2013-11-25 Orange 8.6 Orange
źródło
dict
!Aktualizowania i wprowadzania, gdzie łatwiej będzie znaleźć dla innych, ling 's komentować jur jest odpowiedź powyżej.
df_diff = pd.concat([df1,df2]).drop_duplicates(keep=False)
Testowanie z tymi ramkami danych:
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'], })
Skutkuje to:
źródło
Opierając się na odpowiedzi alko, która prawie zadziałała dla mnie, z wyjątkiem etapu filtrowania (gdzie otrzymuję:)
ValueError: cannot reindex from a duplicate axis
, oto ostateczne rozwiązanie, którego użyłem:# 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]
źródło
IndexError: index out of bounds'
, kiedy próbuję uruchomić trzecią linię.# 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']
źródło
Istnieje prostsze rozwiązanie, które jest szybsze i lepsze, a jeśli liczby są różne, mogą nawet podać różnice ilościowe:
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_'])
Tutaj df_diff jest streszczeniem różnic. Możesz go nawet użyć do znalezienia różnic w ilościach. W twoim przykładzie:
Wyjaśnienie: Podobnie jak w przypadku porównywania dwóch list, aby zrobić to efektywnie, najpierw należy je uporządkować, a następnie porównać (konwersja listy na zestawy / haszowanie również byłaby szybka; obie są niesamowitym ulepszeniem prostej pętli podwójnych porównań O (N ^ 2)
Uwaga: poniższy kod tworzy tabele:
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'], })
źródło
Założyciel proste rozwiązanie tutaj:
https://stackoverflow.com/a/47132808/9656339
pd.concat([df1, df2]).loc[df1.index.symmetric_difference(df2.index)]
źródło
# 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
źródło
Mam to rozwiązanie. Czy to ci pomaga?
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))
wynik
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
źródło
Ponieważ
pandas >= 1.1.0
mamyDataFrame.compare
iSeries.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
źródło
Jednym z ważnych szczegółów, na które należy zwrócić uwagę, jest to, że Twoje dane mają zduplikowane wartości indeksu , więc aby wykonać proste porównanie, musimy ustawić wszystko jako unikalne,
df.reset_index()
a zatem możemy dokonać selekcji na podstawie warunków. Po zdefiniowaniu indeksu zakładam, że chciałbyś zachować indeks, więc istnieje rozwiązanie jednowierszowe:[~df2.reset_index().isin(df1.reset_index())].dropna().set_index('Date')
Kiedy celem z pythonowego punktu widzenia jest poprawa czytelności, możemy trochę zepsuć:
# 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)
źródło
Mam nadzieję, że to Ci się przyda. ^ 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 """
źródło
Wypróbowałem tę metodę i zadziałała. Mam nadzieję, że to też może pomóc:
"""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']]
źródło