Najłatwiejszy sposób, aby to zrobić, będzie zależeć od struktury ramek danych (tj. Czy można używać indeksów itp.). To jest dobry przykład, dlaczego w pytaniach o pandy zawsze powinieneś umieszczać powtarzalny przykład .
Możesz także określić, które kolumny mają być brane pod uwagę podczas wyszukiwania duplikatów:pd.concat([df1,df2]).drop_duplicates(subset = ['col1','col2'], keep=False)
Szpaqn
1
@Szpaqn zauważ, że ta metoda nie będzie obsługiwać specjalnego przypadku. :-)
BENY
Zwróć uwagę, że może to spowodować, że w wyniku pozostaną nieoczekiwane wiersze, jeśli jeden z typów danych to float(ponieważ 12.00000000001 != 12). Lepszą praktyką jest znalezienie przecięcia zestawu identyfikatorów w dwóch ramkach danych i na tej podstawie obliczenie różnicy.
Jiāgěng
1
@DtechNet musisz sprawić, by dwie ramki danych miały tę samą nazwę
BENY
2
Metoda 2 ( indicator=True) jest bardzo wszechstronnym i użytecznym narzędziem. Chciałbym zobaczyć ją na początku tej odpowiedzi, ale z łączeniem „zewnętrznym”, a nie „lewym”, obejmującym wszystkie 3 sytuacje.
mirekphd
34
W przypadku wierszy spróbuj tego, gdzie Namejest kolumna wspólnego indeksu (może to być lista wielu wspólnych kolumn lub określić left_oni right_on):
m = df1.merge(df2, on='Name', how='outer', suffixes=['', '_'], indicator=True)
To indicator=Trueustawienie jest przydatne, ponieważ dodaje kolumnę o nazwie _merge, zawierającą wszystkie zmiany między df1i df2, podzielone na 3 możliwe rodzaje: „left_only”, „right_only” lub „both”.
Chcesz komentować? mergewith indicator=Trueto klasyczne rozwiązanie do porównywania ramek danych według danych pól.
jpp
9
Zaakceptowana odpowiedź Metoda 1 nie będzie działać dla ramek danych z NaNami wewnątrz, as pd.np.nan != pd.np.nan. Nie jestem pewien, czy to najlepszy sposób, ale można tego uniknąć
Okay, znalazłem odpowiedź najwyższego głosowania już zawiera to, co odkryłem. Tak, możemy użyć tego kodu tylko pod warunkiem, że nie ma duplikatów w każdym z dwóch plików df.
Mam trudną metodę. Najpierw ustawiliśmy „Name” jako indeks dwóch ramek danych podanych w pytaniu. Ponieważ mamy tę samą „Nazwę” w dwóch plikach df, możemy po prostu usunąć indeks „mniejszego” pliku df z „większego” pliku df. Oto kod.
proste i skuteczne. Dodano błędy = „ignoruj”, aby rozwiązać problem w przypadku, gdy wartości docelowe nie znajdują się w źródle (tj. Na przecięciu), a zresetowanie indeksu na końcu daje plik df podobny do oryginału.
Autor pytania poprosił o zwrócenie wszystkich wartości w df1, których nie ma w df2. Dlatego df1[~df1.apply(tuple,1).isin(df2.apply(tuple,1))]nawet w tym przypadku jest to poprawna odpowiedź. Jeśli chciałeś uzyskać wartości, które są w df1 lub df2, ale nie w obu, to sugerowane podejście jest poprawne (z zastrzeżeniem usuwania duplikatów z oryginalnych ramek danych).
ira
0
Niewielka odmiana rozwiązania nice @ liangli, które nie wymaga zmiany indeksu istniejących ramek danych:
Znajdowanie różnicy według indeksu. Zakładając, że df1 jest podzbiorem df2, a indeksy są przenoszone do przodu podczas podzbioru
df1.loc[set(df1.index).symmetric_difference(set(df2.index))].dropna()
# Example
df1 = pd.DataFrame({"gender":np.random.choice(['m','f'],size=5), "subject":np.random.choice(["bio","phy","chem"],size=5)}, index = [1,2,3,4,5])
df2 = df1.loc[[1,3,5]]
df1
gender subject
1 f bio
2 m chem
3 f phy
4 m bio
5 f bio
df2
gender subject
1 f bio
3 f phy
5 f bio
df3 = df1.loc[set(df1.index).symmetric_difference(set(df2.index))].dropna()
df3
gender subject
2 m chem
4 m bio
Oprócz zaakceptowanej odpowiedzi chciałbym zaproponować jeszcze jedno szersze rozwiązanie, w którym można znaleźć różnicę w zestawie 2D dwóch ramek danych z dowolnym index/ columns(mogą nie pokrywać się dla obu nazw danych). Metoda pozwala również na ustawienie tolerancji dla floatelementów do porównania ramek danych (wykorzystuje np.isclose)
import numpy as np
import pandas as pd
defget_dataframe_setdiff2d(df_new: pd.DataFrame,
df_old: pd.DataFrame,
rtol=1e-03, atol=1e-05) -> pd.DataFrame:"""Returns set difference of two pandas DataFrames"""
union_index = np.union1d(df_new.index, df_old.index)
union_columns = np.union1d(df_new.columns, df_old.columns)
new = df_new.reindex(index=union_index, columns=union_columns)
old = df_old.reindex(index=union_index, columns=union_columns)
mask_diff = ~np.isclose(new, old, rtol, atol)
df_bool = pd.DataFrame(mask_diff, union_index, union_columns)
df_diff = pd.concat([new[df_bool].stack(),
old[df_bool].stack()], axis=1)
df_diff.columns = ["New", "Old"]
return df_diff
Odpowiedzi:
Używając
drop_duplicates
pd.concat([df1,df2]).drop_duplicates(keep=False)
Update :
df1=pd.DataFrame({'A':[1,2,3,3],'B':[2,3,4,4]}) df2=pd.DataFrame({'A':[1],'B':[2]})
Wyświetli się jak poniżej, co jest błędne
pd.concat([df1, df2]).drop_duplicates(keep=False) Out[655]: A B 1 2 3
Out[656]: A B 1 2 3 2 3 4 3 3 4
Metoda 1: używanie
isin
ztuple
df1[~df1.apply(tuple,1).isin(df2.apply(tuple,1))] Out[657]: A B 1 2 3 2 3 4 3 3 4
Metoda 2:
merge
zindicator
df1.merge(df2,indicator = True, how='left').loc[lambda x : x['_merge']!='both'] Out[421]: A B _merge 1 2 3 left_only 2 3 4 left_only 3 3 4 left_only
źródło
pd.concat([df1,df2]).drop_duplicates(subset = ['col1','col2'], keep=False)
float
(ponieważ12.00000000001 != 12
). Lepszą praktyką jest znalezienie przecięcia zestawu identyfikatorów w dwóch ramkach danych i na tej podstawie obliczenie różnicy.indicator=True
) jest bardzo wszechstronnym i użytecznym narzędziem. Chciałbym zobaczyć ją na początku tej odpowiedzi, ale z łączeniem „zewnętrznym”, a nie „lewym”, obejmującym wszystkie 3 sytuacje.W przypadku wierszy spróbuj tego, gdzie
Name
jest kolumna wspólnego indeksu (może to być lista wielu wspólnych kolumn lub określićleft_on
iright_on
):m = df1.merge(df2, on='Name', how='outer', suffixes=['', '_'], indicator=True)
To
indicator=True
ustawienie jest przydatne, ponieważ dodaje kolumnę o nazwie_merge
, zawierającą wszystkie zmiany międzydf1
idf2
, podzielone na 3 możliwe rodzaje: „left_only”, „right_only” lub „both”.W przypadku kolumn spróbuj tego:
set(df1.columns).symmetric_difference(df2.columns)
źródło
merge
withindicator=True
to klasyczne rozwiązanie do porównywania ramek danych według danych pól.Zaakceptowana odpowiedź Metoda 1 nie będzie działać dla ramek danych z NaNami wewnątrz, as
pd.np.nan != pd.np.nan
. Nie jestem pewien, czy to najlepszy sposób, ale można tego uniknąćdf1[~df1.astype(str).apply(tuple, 1).isin(df2.astype(str).apply(tuple, 1))]
źródło
edit2, wymyśliłem nowe rozwiązanie bez potrzeby ustawiania indeksu
newdf=pd.concat([df1,df2]).drop_duplicates(keep=False)
Okay, znalazłem odpowiedź najwyższego głosowania już zawiera to, co odkryłem. Tak, możemy użyć tego kodu tylko pod warunkiem, że nie ma duplikatów w każdym z dwóch plików df.
Mam trudną metodę. Najpierw ustawiliśmy „Name” jako indeks dwóch ramek danych podanych w pytaniu. Ponieważ mamy tę samą „Nazwę” w dwóch plikach df, możemy po prostu usunąć indeks „mniejszego” pliku df z „większego” pliku df. Oto kod.
df1.set_index('Name',inplace=True) df2.set_index('Name',inplace=True) newdf=df1.drop(df2.index)
źródło
import pandas as pd # given df1 = pd.DataFrame({'Name':['John','Mike','Smith','Wale','Marry','Tom','Menda','Bolt','Yuswa',], 'Age':[23,45,12,34,27,44,28,39,40]}) df2 = pd.DataFrame({'Name':['John','Smith','Wale','Tom','Menda','Yuswa',], 'Age':[23,12,34,44,28,40]}) # find elements in df1 that are not in df2 df_1notin2 = df1[~(df1['Name'].isin(df2['Name']) & df1['Age'].isin(df2['Age']))].reset_index(drop=True) # output: print('df1\n', df1) print('df2\n', df2) print('df_1notin2\n', df_1notin2) # df1 # Age Name # 0 23 John # 1 45 Mike # 2 12 Smith # 3 34 Wale # 4 27 Marry # 5 44 Tom # 6 28 Menda # 7 39 Bolt # 8 40 Yuswa # df2 # Age Name # 0 23 John # 1 12 Smith # 2 34 Wale # 3 44 Tom # 4 28 Menda # 5 40 Yuswa # df_1notin2 # Age Name # 0 45 Mike # 1 27 Marry # 2 39 Bolt
źródło
Być może prostszy jednolinijkowy, z identycznymi lub różnymi nazwami kolumn. Działa nawet wtedy, gdy df2 ['Name2'] zawiera zduplikowane wartości.
newDf = df1.set_index('Name1') .drop(df2['Name2'], errors='ignore') .reset_index(drop=False)
źródło
Jak wspomniano tutaj, że
df1[~df1.apply(tuple,1).isin(df2.apply(tuple,1))]
jest poprawnym rozwiązaniem, ale jeśli
df1=pd.DataFrame({'A':[1],'B':[2]}) df2=pd.DataFrame({'A':[1,2,3,3],'B':[2,3,4,4]})
W takim przypadku powyższe rozwiązanie da Empty DataFrame , zamiast tego powinieneś użyć
concat
metody po usunięciu duplikatów z każdej ramki danych.Posługiwać się
concate with drop_duplicates
df1=df1.drop_duplicates(keep="first") df2=df2.drop_duplicates(keep="first") pd.concat([df1,df2]).drop_duplicates(keep=False)
źródło
df1[~df1.apply(tuple,1).isin(df2.apply(tuple,1))]
nawet w tym przypadku jest to poprawna odpowiedź. Jeśli chciałeś uzyskać wartości, które są w df1 lub df2, ale nie w obu, to sugerowane podejście jest poprawne (z zastrzeżeniem usuwania duplikatów z oryginalnych ramek danych).Niewielka odmiana rozwiązania nice @ liangli, które nie wymaga zmiany indeksu istniejących ramek danych:
newdf = df1.drop(df1.join(df2.set_index('Name').index))
źródło
Znajdowanie różnicy według indeksu. Zakładając, że df1 jest podzbiorem df2, a indeksy są przenoszone do przodu podczas podzbioru
df1.loc[set(df1.index).symmetric_difference(set(df2.index))].dropna() # Example df1 = pd.DataFrame({"gender":np.random.choice(['m','f'],size=5), "subject":np.random.choice(["bio","phy","chem"],size=5)}, index = [1,2,3,4,5]) df2 = df1.loc[[1,3,5]] df1 gender subject 1 f bio 2 m chem 3 f phy 4 m bio 5 f bio df2 gender subject 1 f bio 3 f phy 5 f bio df3 = df1.loc[set(df1.index).symmetric_difference(set(df2.index))].dropna() df3 gender subject 2 m chem 4 m bio
źródło
Oprócz zaakceptowanej odpowiedzi chciałbym zaproponować jeszcze jedno szersze rozwiązanie, w którym można znaleźć różnicę w zestawie 2D dwóch ramek danych z dowolnym
index
/columns
(mogą nie pokrywać się dla obu nazw danych). Metoda pozwala również na ustawienie tolerancji dlafloat
elementów do porównania ramek danych (wykorzystujenp.isclose
)import numpy as np import pandas as pd def get_dataframe_setdiff2d(df_new: pd.DataFrame, df_old: pd.DataFrame, rtol=1e-03, atol=1e-05) -> pd.DataFrame: """Returns set difference of two pandas DataFrames""" union_index = np.union1d(df_new.index, df_old.index) union_columns = np.union1d(df_new.columns, df_old.columns) new = df_new.reindex(index=union_index, columns=union_columns) old = df_old.reindex(index=union_index, columns=union_columns) mask_diff = ~np.isclose(new, old, rtol, atol) df_bool = pd.DataFrame(mask_diff, union_index, union_columns) df_diff = pd.concat([new[df_bool].stack(), old[df_bool].stack()], axis=1) df_diff.columns = ["New", "Old"] return df_diff
Przykład:
In [1] df1 = pd.DataFrame({'A':[2,1,2],'C':[2,1,2]}) df2 = pd.DataFrame({'A':[1,1],'B':[1,1]}) print("df1:\n", df1, "\n") print("df2:\n", df2, "\n") diff = get_dataframe_setdiff2d(df1, df2) print("diff:\n", diff, "\n")
Out [1] df1: A C 0 2 2 1 1 1 2 2 2 df2: A B 0 1 1 1 1 1 diff: New Old 0 A 2.0 1.0 B NaN 1.0 C 2.0 NaN 1 B NaN 1.0 C 1.0 NaN 2 A 2.0 NaN C 2.0 NaN
źródło