Python Pandas - İki veri çerçevesi arasındaki farkı bul


99

İki veri çerçevem ​​var df1 ve df2, burada df2, df1'in bir alt kümesidir. İki veri çerçevesi arasındaki fark olan yeni bir veri çerçevesini (df3) nasıl elde ederim?

Başka bir deyişle, df1'de df2'de olmayan tüm satırları / sütunları içeren bir veri çerçevesi?

görüntü açıklamasını buraya girin


3
Bunu yapmanın en kolay yolu, veri çerçevelerinizin nasıl yapılandırıldığına (yani, dizinlerin kullanılıp kullanılamayacağına, vb.) Bağlı olacaktır. Bu, pandaların sorularına neden her zaman tekrarlanabilir bir örnek eklemeniz gerektiğinin iyi bir örneğidir .
cmaher

Dataframe örnek görüntüsünü
ekledim

Yanıtlar:


154

Kullanarak drop_duplicates

pd.concat([df1,df2]).drop_duplicates(keep=False)

Update :

Above method only working for those dataframes they do not have duplicate itself, For example

df1=pd.DataFrame({'A':[1,2,3,3],'B':[2,3,4,4]})
df2=pd.DataFrame({'A':[1],'B':[2]})

Aşağıdaki gibi çıktı verecek, bu yanlış

Yanlış Çıktı:

pd.concat([df1, df2]).drop_duplicates(keep=False)
Out[655]: 
   A  B
1  2  3

Doğru Çıktı

Out[656]: 
   A  B
1  2  3
2  3  4
3  3  4

Bunu nasıl başarabilirim?

Yöntem 1: isiniletuple

df1[~df1.apply(tuple,1).isin(df2.apply(tuple,1))]
Out[657]: 
   A  B
1  2  3
2  3  4
3  3  4

Yöntem 2: mergeileindicator

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

3
Yinelenenleri ararken hangi sütunların dikkate alınacağını da belirleyebilirsiniz:pd.concat([df1,df2]).drop_duplicates(subset = ['col1','col2'], keep=False)
Szpaqn

@Szpaqn, bu yöntemin özel durumu ele almayacağını fark eder. :-)
BEN_YO

Veri türlerinizden biri float(çünkü 12.00000000001 != 12) ise, bunun beklenmeyen satırların sonuçta kalmasına neden olabileceğini unutmayın . Daha iyi bir uygulama, iki veri çerçevesinde kimliklerin küme kesişimini bulmak ve buna göre farkı elde etmektir.
Jiāgěng

1
@DtechNet iki veri çerçevesinin aynı ada sahip
olmasını sağlamalısınız

2
Yöntem 2 ( indicator=True) çok yönlü ve kullanışlı bir araçtır, bu cevabın en üstünde görmeyi çok isterim, ancak 3 durumu da kapsayacak şekilde "dış" "değil" sol "birleştirme ile.
mirekphd

32

Satırlar için şunu deneyin, burada Namebirleşik dizin sütunu (birden çok ortak sütun için bir liste olabilir veya left_onve belirtebilirsiniz right_on):

m = df1.merge(df2, on='Name', how='outer', suffixes=['', '_'], indicator=True)

indicator=TrueO adında bir sütun ekler olarak ayar kullanışlıdır _mergetüm arasındaki değişikliklerle, df1ve df2"left_only" "right_only" veya "hem",: 3 olası türlü olarak kategorilere.

Sütunlar için şunu deneyin:

set(df1.columns).symmetric_difference(df2.columns)

8
Olumsuz oy verenler yorum yapmak ister mi? mergeile indicator=True, veri çerçevelerini verilen alanlara göre karşılaştırmak için klasik bir çözümdür.
jpp

9

Kabul edilen cevap Yöntem 1, içinde NaN bulunan veri çerçeveleri için çalışmayacaktır pd.np.nan != pd.np.nan. Bunun en iyi yol olup olmadığından emin değilim, ancak bundan kaçınılabilir

df1[~df1.astype(str).apply(tuple, 1).isin(df2.astype(str).apply(tuple, 1))]

6

edit2, indeks ayarlamaya gerek kalmadan yeni bir çözüm buldum

newdf=pd.concat[df1,df2].drop_duplicates(keep=False)

tamam, en yüksek oy cevabının zaten anladığım şeyi içerdiğini buldum. Evet, bu kodu yalnızca her iki df'de kopya olmaması koşuluyla kullanabiliriz.


Zor bir yöntemim var. İlk olarak soru tarafından verilen iki veri çerçevesinin indeksi olarak 'Ad'ı belirledik.İki dfs'de aynı' Ad'a sahip olduğumuz için, 'daha küçük' df'nin dizinini 'daha büyük' ​​df'den çıkarabiliriz. . İşte kod.

df1.set_index('Name',inplace=True)
df2.set_index('Name',inplace=True)
newdf=df1.drop(df2.index)

muhtemelen pd.concat'i ([df1, df2]) kastettiniz. drop_duplicates (devam = False)
Manaslu

4
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

'~' Ne anlama geliyor?
Piotrek Leśniak

'~' boole indeksleme için değildir. Bakınız: pandas.pydata.org/pandas-docs/stable/user_guide/…
SpeedCoder5

3

Belki aynı veya farklı sütun adlarına sahip daha basit bir tek satırlık. Df2 ['Ad2'] yinelenen değerler içerdiğinde bile çalıştı.

newDf = df1.set_index('Name1')
           .drop(df2['Name2'], errors='ignore')
           .reset_index(drop=False)

2
basit ve etkili. Hedef değerlerin kaynakta olmadığı (yani kesişme) durum için sorunu çözmek için hatalar = 'göz ardı et' eklendi ve sonunda dizini sıfırlamak orijinaline benzer bir df getirdi.
MrE

0

Nice @ liangli çözümünün, mevcut veri çerçevelerinin dizinini değiştirmeyi gerektirmeyen küçük bir varyasyonu:

newdf = df1.drop(df1.join(df2.set_index('Name').index))

0

Endekse göre fark bulma. Df1'in df2'nin bir alt kümesi olduğunu ve alt kümeleme sırasında dizinler ileri taşındığını varsayarsak

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


0

Kabul edilen cevaba ek olarak, herhangi bir / ile iki veri çerçevesinin 2B küme farkını bulabilen daha geniş bir çözüm önermek istiyorum (her iki veri adı için çakışmayabilirler). Ayrıca yöntem, veri çerçevesi karşılaştırması için öğeler için tolerans ayarlanmasına izin verir (kullanır )indexcolumnsfloatnp.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

Misal:

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 

0

Belirtildiği gibi burada o

df1[~df1.apply(tuple,1).isin(df2.apply(tuple,1))]

doğru çözümdür ancak yanlış çıktı üretecektir.

df1=pd.DataFrame({'A':[1],'B':[2]})
df2=pd.DataFrame({'A':[1,2,3,3],'B':[2,3,4,4]})

Bu durumda yukarıdaki çözüm Boş DataFrame verecektir , bunun yerine concather datframe'den kopyaları kaldırdıktan sonra yöntemi kullanmalısınız .

Kullanım concate with drop_duplicates

df1=df1.drop_duplicates(keep="first") 
df2=df2.drop_duplicates(keep="first") 
pd.concat([df1,df2]).drop_duplicates(keep=False)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.