दो डेटाफ्रेम की तुलना करना और अंतर प्राप्त करना


89

मेरे पास दो डेटाफ्रेम हैं। उदाहरण:

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

प्रत्येक डेटाफ्रेम में दिनांक एक सूचकांक के रूप में होती है। दोनों डेटाफ्रेम में एक ही संरचना होती है।

मैं क्या करना चाहता हूं, इन दो डेटाफ्रेम की तुलना करें और खोजें कि कौन सी पंक्तियां df2 में हैं जो df1 में नहीं हैं। मैं दिनांक (सूचकांक) और पहले स्तंभ (बनाना, एपीपीएल, आदि) की तुलना यह देखना चाहता हूं कि क्या वे df2 बनाम df1 में मौजूद हैं।

मैंने निम्नलिखित कोशिश की है:

पहले दृष्टिकोण के लिए मुझे यह त्रुटि मिलती है: "अपवाद: केवल पहचान किए गए डेटाफ़्रेम ऑब्जेक्ट्स की तुलना कर सकते हैं" । मैंने दिनांक को अनुक्रमणिका के रूप में निकालने का प्रयास किया है, लेकिन वही त्रुटि मिलती है।

पर तीसरे दृष्टिकोण , मैं झूठी वापस जाने के लिए ज़ोर मिलता है लेकिन समझ नहीं कैसे वास्तव में विभिन्न पंक्तियों को देखने के लिए।

किसी भी संकेत का स्वागत किया जाएगा


यदि आप ऐसा करते हैं: रसोई की किताब-r.com/Manipulating_data/…, तो क्या यह 'पहचान-लेबल किए गए डेटाफ़्रेम ऑब्जेक्ट्स' अपवाद से छुटकारा दिलाएगा?
एंथनी काँग

मैंने कई बार कॉलम के नाम बदले हैं, इस मुद्दे को बिना किसी भाग्य के साथ लाने की कोशिश करने के लिए।
एरिक डी। ब्राउन

1
FWIW, मैंने दोनों डेटाफ्रेम पर कॉलम नाम को "ए, बी, सी, डी" में बदल दिया और एक ही त्रुटि संदेश प्राप्त किया।
एरिक डी। ब्राउन

जवाबों:


105

यह दृष्टिकोण, df1 != df2केवल समान पंक्तियों और स्तंभों के साथ डेटाफ़्रेम के लिए काम करता है। वास्तव में, सभी डेटाफ़्रेम कुल्हाड़ियों की तुलना _indexed_sameविधि के साथ की जाती है, और यदि स्तंभों / सूचकांकों के क्रम में अंतर पाया जाता है, तो अपवाद उठाया जाता है।

अगर मैं तुम्हें सही कर पाया, तो तुम बदलाव नहीं ढूंढना चाहते, बल्कि सममित अंतर चाहते हो। उस के लिए, एक दृष्टिकोण डेटाफ्रेम हो सकता है:

>>> df = pd.concat([df1, df2])
>>> df = df.reset_index(drop=True)

समूह द्वारा

>>> df_gpby = df.groupby(list(df.columns))

अद्वितीय रिकॉर्ड का सूचकांक प्राप्त करें

>>> idx = [x[0] for x in df_gpby.groups.values() if len(x) == 1]

फिल्टर

>>> df.reindex(idx)
         Date   Fruit   Num   Color
9  2013-11-25  Orange   8.6  Orange
8  2013-11-25   Apple  22.1     Red

यह उत्तर था। मैंने "दिनांक" सूचकांक को हटा दिया और इस दृष्टिकोण का पालन किया और मुझे सही आउटपुट मिला।
एरिक डी। ब्राउन

10
क्या यह देखने के लिए एक ध्वज जोड़ने का एक आसान तरीका है कि कौन सी पंक्तियों को df1 से df2 में हटा दिया गया / जोड़ा / बदल दिया गया?
20

@ जलको मैं सोच रहा था, क्या इसमें pd.concatसे केवल गायब वस्तुओं को जोड़ा जाता है df1? या यह df1पूरी तरह से साथ बदल देता है df2?
जेक वोंग

@ जेकवोंग pd.concat- जैसा कि यहां इस्तेमाल किया गया है - एक बाहरी जुड़ता है । दूसरे शब्दों में, यह दोनों डीएफ से सभी सूचकांकों को जोड़ता है और यह वास्तव में डिफ़ॉल्ट व्यवहार है pd.concat(), यहाँ डॉक्स pandas.pydata.org/pandas-docs/stable/merging.html
थानोस

पंडों का उपयोग करते हुए हम रिकॉर्ड की अधिकतम संख्या क्या है?
pyd

25

किसी डिक्शनरी में डेटाफ्रेम पास करना, मल्टी-इंडेक्स डेटाफ्रेम में परिणाम देता है जिससे आप आसानी से डुप्लिकेट को हटा सकते हैं, जिसके परिणामस्वरूप मल्टीफ्रेम डेटाफ्रेम में डेटाफ्रेम के बीच अंतर होता है:

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)

परिणाम:

             Date   Fruit   Num   Color
DF2 4  2013-11-25   Apple  22.1     Red
    5  2013-11-25  Orange   8.6  Orange

1
यह एक बहुत आसान तरीका है, बस एक और संशोधन इसे और अधिक आसान बना सकता है। शब्दकोश में संक्षिप्त करने की आवश्यकता नहीं है, df = pd.concat का उपयोग करें ([df1, df2]) ऐसा ही करेंगे
ling

आपको अंतर्निहित कीवर्ड को अधिलेखित नहीं करना चाहिए dict!
डेनिफ्रोमुफा

क्या यह जोड़ने का एक तरीका है कि यह निर्धारित करने के लिए कि किस डेटा फ़्रेम में अद्वितीय पंक्ति है?
२ich बजे जेलेविकोविच

आप मल्टीएंडेक्स में पहले स्तर तक बता सकते हैं जिसमें डिक्शनरी में डेटाफ़्रेम की कुंजी है (मैंने सही कुंजियों के साथ आउटपुट को अपडेट किया है)
jur

25

अद्यतन कर रहा है और रखने, कहीं यह दूसरों को खोजने के लिए आसान हो जाएगा, लिंग 'पर टिप्पणी Jur ऊपर की प्रतिक्रिया।

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

इन DataFrames के साथ परीक्षण:

# with import pandas as pd

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'],
    })

इस में परिणाम:

# for df1

         Date   Fruit   Num   Color
0  2013-11-24  Banana  22.1  Yellow
1  2013-11-24  Orange   8.6  Orange
2  2013-11-24   Apple   7.6   Green
3  2013-11-24  Celery  10.2   Green


# for df2

         Date   Fruit   Num   Color
0  2013-11-24  Banana  22.1  Yellow
1  2013-11-24  Orange   8.6  Orange
2  2013-11-24   Apple   7.6   Green
3  2013-11-24  Celery  10.2   Green
4  2013-11-25   Apple  22.1     Red
5  2013-11-25  Orange   8.6  Orange


# for df_diff

         Date   Fruit   Num   Color
4  2013-11-25   Apple  22.1     Red
5  2013-11-25  Orange   8.6  Orange

5

एल्को के उत्तर पर निर्माण करना, जो लगभग मेरे लिए काम करता है, फ़िल्टरिंग चरण (जहां मुझे मिलता है ValueError: cannot reindex from a duplicate axis) को छोड़कर , यहां अंतिम चरण है जो मैंने चुना है:

# 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]

जवाब में अच्छा लगा। धन्यवाद
एरिक डी। ब्राउन

1
मुझे त्रुटि मिल रही है, ' IndexError: index out of bounds', जब मैं तीसरी पंक्ति को चलाने की कोशिश करता हूं।
मूंदड़ा

5
# 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']

यह सबसे अच्छा जवाब है
15

3

एक सरल उपाय है जो तेजी से और बेहतर है, और यदि संख्या भिन्न हैं, तो आप मात्रा में अंतर भी दे सकते हैं:

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_'])

यहाँ df_diff मतभेदों का एक सारांश है। आप इसका उपयोग मात्राओं में अंतर जानने के लिए भी कर सकते हैं। आपके उदाहरण में:

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

स्पष्टीकरण: इसी तरह दो सूचियों की तुलना करने के लिए, इसे कुशलतापूर्वक करने के लिए हमें पहले उन्हें आदेश देना चाहिए फिर उनकी तुलना करना चाहिए (सूची को सेट / हैशिंग में परिवर्तित करना भी तेज़ होगा; दोनों सरल O (N ^ 2) डबल तुलना लूप के लिए एक अविश्वसनीय सुधार हैं)

नोट: निम्न कोड तालिकाओं का निर्माण करता है:

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'],
})

3

संस्थापक यहां एक सरल समाधान:

https://stackoverflow.com/a/47132808/9656339

pd.concat([df1, df2]).loc[df1.index.symmetric_difference(df2.index)]


1
ढेर अतिप्रवाह Tom2shoes में आपका स्वागत है। कृपया लिंक-ओनली उत्तर प्रदान न करें, लिंक से सामग्री को निकालने का प्रयास करें और इसे केवल एक संदर्भ के रूप में छोड़ दें (जैसा कि लिंक में सामग्री को हटाया जा सकता है या लिंक खुद ही टूट सकता है)। अधिक जानकारी के लिए "मैं एक अच्छा उत्तर कैसे लिखूं?" । यदि आपको लगता है कि यह प्रश्न पहले से ही एक और प्रश्न में उत्तर दिया गया था, तो कृपया इसे डुप्लिकेट के रूप में चिह्नित करें।
GGG

2
# 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

2

चूंकि pandas >= 1.1.0हमारे पास DataFrame.compareऔर है Series.compare

नोट: विधि केवल पहचान किए गए DataFrame ऑब्जेक्ट्स की तुलना कर सकती है, इसका अर्थ है समान पंक्ति और स्तंभ लेबल वाले DataFrames।

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

इस जानकारी के लिए आपका धन्यवाद। मैं अभी तक 1.1 में स्थानांतरित नहीं हुआ हूं, लेकिन यह जानना अच्छा है।
एरिक डी। ब्राउन

1

मुझे इसका हल मिल गया। क्या यह आपकी मदद करता है?

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))

परिणाम

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

सहायता के लिए धन्यवाद। मैंने @ पलको द्वारा उत्तर देखा और उस कोड ने अच्छा काम किया।
एरिक डी। ब्राउन

0

नोटिस करने के लिए एक महत्वपूर्ण विवरण यह है कि आपके डेटा में डुप्लिकेट इंडेक्स वैल्यूज़ हैं , इसलिए किसी भी सीधी तुलना को करने के लिए हमें सब कुछ अद्वितीय के साथ चालू करने की आवश्यकता है df.reset_index()और इसलिए हम शर्तों के आधार पर चयन कर सकते हैं। एक बार जब आपके मामले में सूचकांक को परिभाषित किया जाता है, तो मुझे लगता है कि आप डी इंडेक्स रखना चाहेंगे ताकि एक-पंक्ति समाधान हो:

[~df2.reset_index().isin(df1.reset_index())].dropna().set_index('Date')

एक बार पाइथोनिक दृष्टिकोण से उद्देश्य पठनीयता में सुधार करना है, हम थोड़ा सा तोड़ सकते हैं:

# 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)

0

आशा है कि यह आपके लिए उपयोगी होगा। ^ ओ ^

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
"""

0

मैंने इस विधि की कोशिश की, और यह काम किया। मुझे आशा है कि यह भी मदद कर सकता है:

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