Saya memiliki dua bingkai data df1 dan df2, di mana df2 adalah bagian dari df1. Bagaimana cara mendapatkan bingkai data baru (df3) yang merupakan perbedaan antara kedua bingkai data tersebut?
Dengan kata lain, bingkai data yang memiliki semua baris / kolom di df1 yang tidak ada di df2?
Jawaban:
Dengan menggunakan
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]})
Ini akan menghasilkan seperti di bawah ini, yang salah
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
Metode 1: Menggunakan
isin
dengantuple
df1[~df1.apply(tuple,1).isin(df2.apply(tuple,1))] Out[657]: A B 1 2 3 2 3 4 3 3 4
Metode 2:
merge
denganindicator
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
sumber
pd.concat([df1,df2]).drop_duplicates(subset = ['col1','col2'], keep=False)
float
(karena12.00000000001 != 12
). Praktik yang lebih baik adalah menemukan perpotongan kumpulan ID dalam dua bingkai data dan mendapatkan perbedaan berdasarkan itu.indicator=True
) adalah alat yang sangat serbaguna dan berguna, saya ingin melihatnya di bagian atas jawaban ini, tetapi dengan gabungan 'luar' bukan 'kiri' untuk mencakup semua 3 situasi.Untuk baris, coba ini, di mana
Name
kolom indeks gabungan (dapat berupa daftar untuk beberapa kolom umum, atau tentukanleft_on
danright_on
):m = df1.merge(df2, on='Name', how='outer', suffixes=['', '_'], indicator=True)
The
indicator=True
Pengaturan ini berguna saat menambahkan kolom yang disebut_merge
, dengan semua perubahan antaradf1
dandf2
, dikategorikan menjadi 3 kemungkinan jenis: "left_only", "right_only" atau "baik".Untuk kolom, coba ini:
sumber
merge
withindicator=True
adalah solusi klasik untuk membandingkan kerangka data dengan bidang tertentu.Jawaban yang diterima Metode 1 tidak akan berfungsi untuk bingkai data dengan NaN di dalamnya, seperti
pd.np.nan != pd.np.nan
. Saya tidak yakin apakah ini cara terbaik, tetapi dapat dihindari dengandf1[~df1.astype(str).apply(tuple, 1).isin(df2.astype(str).apply(tuple, 1))]
sumber
edit2, saya menemukan solusi baru tanpa perlu menyetel indeks
newdf=pd.concat[df1,df2].drop_duplicates(keep=False)
oke saya menemukan jawaban dari voting tertinggi sudah berisi apa yang saya ketahui. Ya, kita hanya dapat menggunakan kode ini dengan syarat tidak ada duplikat di setiap dua dfs.
Saya memiliki metode yang rumit. Pertama kita tetapkan 'Nama' sebagai indeks dari dua kerangka data yang diberikan oleh pertanyaan. Karena kita memiliki 'Nama' yang sama di dua dfs, kita bisa melepaskan indeks df 'lebih kecil' dari df 'lebih besar' . Ini kodenya.
df1.set_index('Name',inplace=True) df2.set_index('Name',inplace=True) newdf=df1.drop(df2.index)
sumber
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
sumber
Mungkin satu baris yang lebih sederhana, dengan nama kolom yang identik atau berbeda. Bekerja bahkan ketika df2 ['Name2'] berisi nilai duplikat.
newDf = df1.set_index('Name1') .drop(df2['Name2'], errors='ignore') .reset_index(drop=False)
sumber
Sedikit variasi dari solusi @ liangli yang bagus yang tidak perlu mengubah indeks kerangka data yang ada:
newdf = df1.drop(df1.join(df2.set_index('Name').index))
sumber
Menemukan perbedaan berdasarkan indeks. Dengan asumsi df1 adalah himpunan bagian dari df2 dan indeks dibawa maju saat membuat subset
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
sumber
Selain jawaban yang diterima, saya ingin mengusulkan satu solusi yang lebih luas yang dapat menemukan perbedaan set 2D dari dua dataframe dengan
index
/columns
(mereka mungkin tidak bertepatan untuk kedua datarames). Juga metode memungkinkan untuk mengatur toleransi untukfloat
elemen untuk perbandingan kerangka data (yang digunakannyanp.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
Contoh:
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
sumber
Seperti yang disebutkan di sini itu
df1[~df1.apply(tuple,1).isin(df2.apply(tuple,1))]
adalah solusi yang benar tetapi akan menghasilkan keluaran yang salah jika
df1=pd.DataFrame({'A':[1],'B':[2]}) df2=pd.DataFrame({'A':[1,2,3,3],'B':[2,3,4,4]})
Dalam kasus di atas solusi akan memberikan DataFrame Kosong , sebagai gantinya Anda harus menggunakan
concat
metode setelah menghapus duplikat dari setiap datframe.Menggunakan
concate with drop_duplicates
df1=df1.drop_duplicates(keep="first") df2=df2.drop_duplicates(keep="first") pd.concat([df1,df2]).drop_duplicates(keep=False)
sumber