पायथन पंडों - दो डेटा फ़्रेमों के बीच अंतर ज्ञात करें


103

मेरे पास दो डेटा फ़्रेम df1 और df2 हैं, जहाँ df2 df1 का सबसेट है। मुझे एक नया डेटा फ़्रेम (df3) कैसे मिलेगा, जो दो डेटा फ़्रेमों के बीच का अंतर है?

दूसरे शब्द में, एक डेटा फ्रेम जिसमें df1 में सभी पंक्तियाँ / स्तंभ हैं जो df2 में नहीं हैं?

यहां छवि विवरण दर्ज करें


3
ऐसा करने का सबसे आसान तरीका इस बात पर निर्भर करेगा कि आपके डेटाफ़्रेम कैसे संरचित हैं (यानी कि क्या अनुक्रमित का उपयोग किया जा सकता है, आदि)। यह एक अच्छा उदाहरण है कि आपको हमेशा पांडा के सवालों में एक प्रतिलिपि प्रस्तुत करने योग्य उदाहरण क्यों शामिल करना चाहिए ।
16

1
मैंने
डेटाफ्रेम

जवाबों:


162

का उपयोग करके 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]})

यह नीचे की तरह आउटपुट देगा, जो गलत है

गलत आउटपुट:

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

कैसे प्राप्त करें?

विधि 1: का उपयोग isinकरtuple

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

विधि 2: के mergeसाथindicator

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

4
आप यह भी निर्धारित कर सकते हैं कि कौन से कॉलम पर विचार किया जाना है, जब डुप्लिकेट की तलाश की जा रही है:pd.concat([df1,df2]).drop_duplicates(subset = ['col1','col2'], keep=False)
Szpaqn

1
@Szpaqn नोटिस इस विधि विशेष मामले को संभाल नहीं होगा। :-)
बेन्नी

ध्यान दें कि यदि परिणाम आपके डेटा प्रकारों में से एक float(क्योंकि 12.00000000001 != 12) है तो यह अनपेक्षित पंक्तियों के कारण हो सकता है । एक बेहतर अभ्यास दो डेटा फ़्रेमों में आईडी के सेट चौराहे को खोजने और उस पर आधारित अंतर प्राप्त करना है।
जिग49ग

1
@DtekNet आपको दो डेटा फ़्रेम बनाने की आवश्यकता है एक ही नाम है
BENY

2
विधि 2 ( indicator=True) एक बहुत ही बहुमुखी और उपयोगी उपकरण है, मैं इसे इस उत्तर के शीर्ष पर देखना पसंद करूंगा, लेकिन 'बाहरी' नहीं 'के साथ' सभी 3 स्थितियों को कवर करने के लिए शामिल हो जाएगा।
mirekphd 11

34

पंक्तियों के लिए, यह कोशिश करें, जहां Nameसंयुक्त सूचकांक कॉलम है (कई सामान्य स्तंभों के लिए एक सूची हो सकती है, या निर्दिष्ट करें left_onऔर right_on):

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

indicator=Trueके रूप में यह एक स्तंभ कहा जाता है कहते हैं सेटिंग उपयोगी होती है _merge, के बीच सभी परिवर्तन के साथ df1और df2, 3 संभव प्रकार में वर्गीकृत किया: "left_only", "right_only" या "दोनों"।

स्तंभों के लिए, यह आज़माएँ:

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

9
टिप्पणी करने के लिए डाउनवॉटर की देखभाल? mergeके साथ indicator=Trueदिए गए फ़ील्ड द्वारा डेटाफ़्रेम की तुलना करने के लिए क्लासिक समाधान है।
jpp

9

स्वीकृत उत्तर पद्धति 1, NaNs के साथ डेटा फ़्रेम के लिए अंदर काम नहीं करेगा, जैसा कि pd.np.nan != pd.np.nan। मुझे यकीन नहीं है कि यह सबसे अच्छा तरीका है, लेकिन इससे बचा जा सकता है

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

7

edit2, मैंने इंडेक्स सेट करने की आवश्यकता के बिना एक नया समाधान निकाला

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

ठीक है, मैंने पाया कि सबसे ज्यादा वोट का जवाब पहले से ही मेरे पास मौजूद है। हां, हम केवल इस कोड का उपयोग इस शर्त पर कर सकते हैं कि प्रत्येक दो dfs में कोई डुप्लिकेट नहीं है।


मेरे पास एक मुश्किल तरीका है। पहले हमने 'नाम' को प्रश्न द्वारा दिए गए दो डेटाफ्रेम के सूचकांक के रूप में सेट किया। चूंकि हमारे पास दो dfs में समान 'नाम' हैं, इसलिए हम 'छोटे' df के सूचकांक को 'बड़े' df से गिरा सकते हैं। यहाँ कोड है।

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

1
आपका शायद pd.concat ([df1, df2]) से मतलब है। drop_duplicates (रखना = गलत होना)
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

'~' का क्या अर्थ है?
पियोट्रेक लेनिआक

'~' बुलियन इंडेक्सिंग के लिए नहीं है। देखें: pandas.pydata.org/pandas-docs/stable/user_guide/…
स्पीडकॉडर 5

3

शायद समान या अलग कॉलम नामों के साथ एक सरल एक-लाइनर। तब भी काम किया जब df2 ['Name2'] में डुप्लिकेट मान शामिल थे।

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

2
सरल और प्रभावी। जोड़ा त्रुटियों = 'नजरअंदाज' मामले को हल करने के लिए जहां गंतव्य मान स्रोत (यानी चौराहे) में नहीं हैं और अंत में सूचकांक को रीसेट करने से एक डीएफ मिलता है जो मूल के समान है।
श्रीमती

1

जैसा कि यहां बताया गया है

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

सही समाधान है, लेकिन अगर यह गलत आउटपुट का उत्पादन करेगा

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

उस मामले में उपरोक्त समाधान खाली डेटाफ़्रेम देगा , इसके बजाय आपको concatप्रत्येक डेटाफ़्रेम से डुप्लिकेट को हटाने के बाद विधि का उपयोग करना चाहिए ।

उपयोग concate with drop_duplicates

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

प्रश्न के लेखक ने df1 में सभी मूल्यों को वापस करने के लिए कहा जो df2 में नहीं हैं। इसलिए, df1[~df1.apply(tuple,1).isin(df2.apply(tuple,1))]इस मामले में भी सही उत्तर है। यदि आप उन मानों को प्राप्त करना चाहते हैं जो या तो df1 या df2 में हैं, लेकिन दोनों में नहीं है, तो आपका सुझाया दृष्टिकोण सही है (मूल डेटाफ़्रेम से डुप्लिकेट को हटाने के कैविएट के साथ)।
इरा

0

अच्छा @ लिआंग्ली के समाधान की थोड़ी भिन्नता जिसे मौजूदा डेटाफ़्रेम के सूचकांक को बदलने की आवश्यकता नहीं है:

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

0

सूचकांक द्वारा अंतर खोजना। Df1 को मान लेना df2 का सबसेट है और सब्मिट करते समय इंडेक्स को आगे बढ़ाया जाता है

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

स्वीकृत जवाब के अलावा, मैं एक और व्यापक समाधान का प्रस्ताव करना चाहूंगा जो कि किसी भी / के साथ दो डेटाफ्रेम के 2 डी सेट अंतर को पा सकता है (वे दोनों डेटामार्क के लिए मेल नहीं खा सकते हैं)। इसके अलावा विधि डेटाफ़्रेम तुलना के लिए तत्वों के लिए सहिष्णुता को स्थापित करने की अनुमति देती है (यह उपयोग करता है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

उदाहरण:

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 
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.