पांडा को ऐसी पंक्तियाँ मिलती हैं जो अन्य डेटाफ़्रेम में नहीं होती हैं


228

मेरे पास दो पांडा डेटा फ़्रेम हैं जिनमें कुछ पंक्तियाँ समान हैं।

मान लीजिए कि डेटाफ्रेम 2 डेटाफ्रेम 1 का सबसेट है।

मैं डेटाफ्रेम 1 की पंक्तियों को कैसे प्राप्त कर सकता हूं जो डेटाफ्रेम 2 में नहीं हैं?

df1 = pandas.DataFrame(data = {'col1' : [1, 2, 3, 4, 5], 'col2' : [10, 11, 12, 13, 14]}) 
df2 = pandas.DataFrame(data = {'col1' : [1, 2, 3], 'col2' : [10, 11, 12]})

1
@TedPetrou मैं यह देखने में विफल हूं कि आपने जो उत्तर दिया है वह सही है। अगर मेरे पास दो डेटाफ्रेम हैं, जिनमें से एक दूसरे का सबसेट है, तो मुझे उन सभी पंक्तियों को हटाने की जरूरत है, जो सबसेट में हैं। मैं डुप्लिकेट को निकालना नहीं चाहता। मैं पूरी तरह से सब्मिट निकालना चाहता हूं।
ज्यूकबॉक्स

जवाबों:


172

एक विधि दोनों dfs के आंतरिक मर्ज फॉर्म के परिणाम को संग्रहीत करने के लिए होगी, फिर हम बस उन पंक्तियों का चयन कर सकते हैं जब एक कॉलम का मान इस आम में नहीं है:

In [119]:

common = df1.merge(df2,on=['col1','col2'])
print(common)
df1[(~df1.col1.isin(common.col1))&(~df1.col2.isin(common.col2))]
   col1  col2
0     1    10
1     2    11
2     3    12
Out[119]:
   col1  col2
3     4    13
4     5    14

संपादित करें

एक अन्य तरीका जैसा कि आपने पाया है कि उपयोग करना है isinजो NaNपंक्तियों का उत्पादन करेगा जिसे आप छोड़ सकते हैं:

In [138]:

df1[~df1.isin(df2)].dropna()
Out[138]:
   col1  col2
3     4    13
4     5    14

हालाँकि अगर df2 समान तरीके से पंक्तियों को शुरू नहीं करता है तो यह काम नहीं करेगा:

df2 = pd.DataFrame(data = {'col1' : [2, 3,4], 'col2' : [11, 12,13]})

पूरे df का उत्पादन करेगा:

In [140]:

df1[~df1.isin(df2)].dropna()
Out[140]:
   col1  col2
0     1    10
1     2    11
2     3    12
3     4    13
4     5    14

13
df1[~df1.isin(df2)].dropna(how = 'all')चालबाजी करने लगता है। वैसे भी धन्यवाद - आपके उत्तर ने मुझे एक समाधान खोजने में मदद की।
अच्छी बातें सोचो

5
ध्यान दें कि उपयोग करने के लिए isinआवश्यक है कि दोनों dfs एक ही पंक्ति मान के साथ शुरू हों, उदाहरण के लिए यदि df2 था df2 = pd.DataFrame(data = {'col1' : [2, 3,4], 'col2' : [11,12, 13]})तो आपका तरीका काम नहीं करेगा
EdChum

2
इसने सभी चींटियों को तैरने में बदल दिया!
क्रिस नीलसन

3
@SergeyZakharov का यह जवाब लगभग 3 साल पहले पोस्ट किया गया था जहाँ तक ओपी का सवाल है और उनकी समस्या के लिए सही था, दूसरा जवाब एक बेहतर जवाब है और एक व्यापक समस्या को संभालता है जो मूल प्रश्न का हिस्सा नहीं था, यह बताना गलत है कि यह उत्तर गलत है, यह सही है कि समस्या को निर्धारित किया गया है। इसके अतिरिक्त किसी ने बिना स्पष्टीकरण के इसे नीचे कर दिया है, बहुत कम है जो मैं कर सकता हूं क्योंकि यह एक स्वीकृत उत्तर है, ओपी ने अपना दिमाग नहीं बदला है और मैं इसे सही करने के लिए एक और उत्तर को रद्द करने के लिए नहीं जा रहा हूं ।
EdChum

1
@ सीसिलिया आपको पास करने की आवश्यकता है keep=False: df0.append(df1).drop_duplicates(keep=False)डिफ़ॉल्ट रूप से यह पहली डुप्लिकेट रखता है, आप सभी डुप्लिकेट को छोड़ना चाहते हैं
एडचम

189

वर्तमान में चयनित समाधान गलत परिणाम उत्पन्न करता है। सही ढंग से इस समस्या को हल करने के लिए हम से एक बाएँ में शामिल होने के प्रदर्शन कर सकते हैं df1करने के लिए df2, पहले के लिए सिर्फ अद्वितीय पंक्तियों मिल यकीन है कि करने के लिए कर रही हैdf2

सबसे पहले, हमें डेटा [3, 10] के साथ पंक्ति जोड़ने के लिए मूल DataFrame को संशोधित करना होगा।

df1 = pd.DataFrame(data = {'col1' : [1, 2, 3, 4, 5, 3], 
                           'col2' : [10, 11, 12, 13, 14, 10]}) 
df2 = pd.DataFrame(data = {'col1' : [1, 2, 3],
                           'col2' : [10, 11, 12]})

df1

   col1  col2
0     1    10
1     2    11
2     3    12
3     4    13
4     5    14
5     3    10

df2

   col1  col2
0     1    10
1     2    11
2     3    12

डुप्लिकेट को समाप्त करते हुए एक ले-जॉइन करें, df2ताकि प्रत्येक पंक्ति में df1ठीक 1 पंक्ति से जुड़ जाए df2indicatorएक अतिरिक्त कॉलम को लौटाने के लिए पैरामीटर का उपयोग करें जो यह दर्शाता है कि पंक्ति किस तालिका से थी।

df_all = df1.merge(df2.drop_duplicates(), on=['col1','col2'], 
                   how='left', indicator=True)
df_all

   col1  col2     _merge
0     1    10       both
1     2    11       both
2     3    12       both
3     4    13  left_only
4     5    14  left_only
5     3    10  left_only

एक बूलियन स्थिति बनाएँ:

df_all['_merge'] == 'left_only'

0    False
1    False
2    False
3     True
4     True
5     True
Name: _merge, dtype: bool

अन्य उपाय गलत क्यों हैं

कुछ समाधान एक ही गलती करते हैं - वे केवल यह जांचते हैं कि प्रत्येक स्तंभ प्रत्येक स्तंभ में स्वतंत्र रूप से है, एक ही पंक्ति में एक साथ नहीं। अंतिम पंक्ति को जोड़ना, जो अद्वितीय है, लेकिन df2गलती को उजागर करने वाले दोनों स्तंभों से मान हैं :

common = df1.merge(df2,on=['col1','col2'])
(~df1.col1.isin(common.col1))&(~df1.col2.isin(common.col2))
0    False
1    False
2    False
3     True
4     True
5    False
dtype: bool

इस समाधान का एक ही गलत परिणाम मिलता है:

df1.isin(df2.to_dict('l')).all(1)

2
लेकिन, मुझे लगता है, वे मान रहे थे कि कॉल 1 एक सूचकांक है (सवाल में उल्लेख नहीं है, लेकिन स्पष्ट है)। इसलिए, अगर ऐसा कोई मामला नहीं है जहां col1 के समान मान के लिए col2 के दो मान हैं (ऊपर दो col1 = 3 पंक्तियाँ नहीं हो सकती हैं) तो ऊपर दिए गए उत्तर सही हैं।
पश्तुते

14
यह निश्चित रूप से स्पष्ट नहीं है, इसलिए आपकी बात अमान्य है। मेरा समाधान अधिक मामलों के लिए सामान्यीकृत करता है।
टेड पेट्रोउ 13

प्रश्न, क्या बूलियन एरे के बजाय स्लाइस बनाना आसान नहीं होगा? चूंकि उद्देश्य पंक्तियों को प्राप्त करना है।
माटियास रोमियो

5
df_all[df_all['_merge'] == 'left_only']परिणाम के साथ df करने के लिए उपयोग करें
gies0r

77

यह मानकर कि अनुक्रमणिका डेटाफ़्रेम (वास्तविक कॉल मानों को ध्यान में न रखते हुए) में सुसंगत हैं:

df1[~df1.index.isin(df2.index)]

1
@ChrisNielsen हालत की उपेक्षा। तो इस उदाहरण में इसका मतलब है "उन पंक्तियों को लें df1जिनसे अनुक्रमित नहीं हैं df2.index"। नकार पर अधिक: stackoverflow.com/q/19960077/304209 (आश्चर्यजनक रूप से, मुझे पंडों के डॉक्स में टिल्ड का कोई उल्लेख नहीं मिला)।
डेनिस गोलोमेज़ोव

ऐसा लगता है कि dfs की लंबाई समान है, नहीं? मैं हो रहा हूँValueError: Item wrong length x instead of y.
शब्दभेदी

@wordsforthewise नहीं, वे नहीं। मास्क की लंबाई df1 है और इसे df1 पर भी लागू किया जाता है। क्या आप अपना उदाहरण प्रदान कर सकते हैं?
डेनिस गोलोमेज़ोव

आइटम की लंबाई की समस्या को ठीक करने के लिए आपको .loc
Moreno

13

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

In [77]: df1 = pandas.DataFrame(data = {'col1' : [1, 2, 3, 4, 5, 3], 'col2' : [10, 11, 12, 13, 14, 10]})
In [78]: df2 = pandas.DataFrame(data = {'col1' : [1, 3, 4], 'col2' : [10, 12, 13]})
In [79]: df1.loc[~df1.set_index(list(df1.columns)).index.isin(df2.set_index(list(df2.columns)).index)]
Out[79]:
   col1  col2
1     2    11
4     5    14
5     3    10

यदि अनुक्रमणिका को ध्यान में रखा जाना चाहिए, तो set_index में मौजूदा तर्जनी पर कॉलम जोड़ने के लिए कीवर्ड तर्क है। यदि कॉलम पंक्तिबद्ध नहीं हैं, तो डेटा को संरेखित करने के लिए सूची (df.columns) को कॉलम विनिर्देशों के साथ बदला जा सकता है।

pandas.MultiIndex.from_tuples(df<N>.to_records(index = False).tolist())

वैकल्पिक रूप से सूचकांकों को बनाने के लिए इस्तेमाल किया जा सकता है, हालांकि मुझे संदेह है कि यह अधिक कुशल है।


@ Dev_123 शुरू में ~ निकालें। कोर एक विधेय सूची बनाने के लिए है कि क्या df1 में पंक्तियाँ भी df2 में होती हैं, इसलिए df1 में पंक्तियाँ df1 के लिए अद्वितीय नहीं होती हैं, ~ यह इस बात की भविष्यवाणी करता है कि क्या df1 में पंक्तियाँ df1 में नहीं हैं।
रुने लिंगगूस

11

मान लें कि आपके पास दो डेटाफ्रेम हैं, df_1 और df_2 जिनके पास कई फ़ील्ड्स (column_names) हैं और आप केवल उन प्रविष्टियों को df_1 में ढूंढना चाहते हैं जो कुछ फ़ील्ड्स (जैसे फ़ील्ड_x, फ़ील्ड_y) के आधार पर df_2 में नहीं हैं, निम्न चरणों का पालन करें।

Step1। एक कॉलम key1 और key2 को क्रमशः df_1 और df_2 में जोड़ें।

Step2। नीचे दिए गए अनुसार डेटाफ्रेम को प्रिंट करें। field_x और field_y हमारे इच्छित कॉलम हैं।

Step3। केवल उन पंक्तियों को df_1 से चुनें जहाँ Key1 Key2 के बराबर नहीं है।

Step4.Drop key1 और key2।

यह विधि आपकी समस्या का समाधान करेगी और बड़े डेटा सेट के साथ भी तेजी से काम करेगी। मैंने इसे 1,000,000 से अधिक पंक्तियों के साथ डेटाफ्रेम के लिए आज़माया है।

df_1['key1'] = 1
df_2['key2'] = 1
df_1 = pd.merge(df_1, df_2, on=['field_x', 'field_y'], how = 'left')
df_1 = df_1[~(df_1.key2 == df_1.key1)]
df_1 = df_1.drop(['key1','key2'], axis=1)

मुझे नहीं लगता कि यह तकनीकी रूप से वह क्या चाहता है - वह जानना चाहता है कि कौन सी पंक्तियाँ किस डीएफ के लिए अद्वितीय थीं। लेकिन, मुझे लगता है कि यह समाधान पंक्तियों का एक df देता है जो या तो पहले df या दूसरे df के लिए अद्वितीय थे।
लेगिट स्टैक

6

थोड़ा देर से, लेकिन यह pd.merge के "संकेतक" पैरामीटर की जांच करने के लायक हो सकता है।

एक उदाहरण के लिए इस अन्य प्रश्न को देखें: पांडा डेटाफ्रेम और रिटर्न पंक्तियों की तुलना करें जो पहले एक से गायब हैं


हाँ! यहाँ भी: stackoverflow.com/questions/49487263/…
Dan

3

आप इसे आइसिन (तानाशाही) विधि का उपयोग कर कर सकते हैं :

In [74]: df1[~df1.isin(df2.to_dict('l')).all(1)]
Out[74]:
   col1  col2
3     4    13
4     5    14

स्पष्टीकरण:

In [75]: df2.to_dict('l')
Out[75]: {'col1': [1, 2, 3], 'col2': [10, 11, 12]}

In [76]: df1.isin(df2.to_dict('l'))
Out[76]:
    col1   col2
0   True   True
1   True   True
2   True   True
3  False  False
4  False  False

In [77]: df1.isin(df2.to_dict('l')).all(1)
Out[77]:
0     True
1     True
2     True
3    False
4    False
dtype: bool

यह गलत परिणाम उत्पन्न करता है। मेरी व्याख्या नीचे देखें।
टेड पेट्रोउ

2

तुम भी concat कर सकते हैं df1, df2:

x = pd.concat([df1, df2])

और फिर सभी डुप्लिकेट हटा दें:

y = x.drop_duplicates(keep=False, inplace=False)

StackOverflow में आपका स्वागत है: यदि आप कोड, XML या डेटा नमूने पोस्ट करते हैं, तो कृपया टेक्स्ट एडिटर में उन पंक्तियों को हाइलाइट करें और एडिटर टूलबार पर "कोड नमूने" बटन ({}) पर क्लिक करें या अपने कीबोर्ड पर Ctrl + K का उपयोग करके अच्छी तरह से फॉर्मेट करें। और वाक्य रचना इसे उजागर!
WhatsThePoint

4
यह उन सभी डेटा को लौटाएगा जो या तो सेट में हैं, न कि केवल df1 में है।
जेमी मार्शल

1

इस बारे में कैसा है:

df1 = pandas.DataFrame(data = {'col1' : [1, 2, 3, 4, 5], 
                               'col2' : [10, 11, 12, 13, 14]}) 
df2 = pandas.DataFrame(data = {'col1' : [1, 2, 3], 
                               'col2' : [10, 11, 12]})
records_df2 = set([tuple(row) for row in df2.values])
in_df2_mask = np.array([tuple(row) in records_df2 for row in df1.values])
result = df1[~in_df2_mask]

1

इसे हल करने का एक और तरीका है:

df1[~df1.index.isin(df1.merge(df2, how='inner', on=['col1', 'col2']).index)]

या:

df1.loc[df1.index.difference(df1.merge(df2, how='inner', on=['col1', 'col2']).index)]

0

ऐसा करने के मेरे तरीके में एक नया कॉलम जोड़ना शामिल है जो एक डेटाफ़्रेम के लिए अद्वितीय है और इसका उपयोग यह चुनने के लिए है कि क्या प्रविष्टि रखना है

df2[col3] = 1
df1 = pd.merge(df_1, df_2, on=['field_x', 'field_y'], how = 'outer')
df1['Empt'].fillna(0, inplace=True)

यह बनाता है ताकि df1 में हर प्रविष्टि में एक कोड हो - 0 यदि यह df1 के लिए अद्वितीय है, 1 यदि यह दोनों डेटाफ्रेम में है। आप इसका उपयोग तब तक करना चाहते हैं जब आप चाहते हैं

answer = nonuni[nonuni['Empt'] == 0]

0
मर्ज फ़ंक्शन का उपयोग करके डिस्मिलर पंक्तियों को निकालें
df = df.merge(same.drop_duplicates(), on=['col1','col2'], 
               how='left', indicator=True)
CSV में भिन्न पंक्तियों को सहेजें
df[df['_merge'] == 'left_only'].to_csv('output.csv')
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.