अजगर पांडा डुप्लिकेट कॉलम हटाते हैं


126

डेटाफ़्रेम से डुप्लिकेट कॉलम हटाने का सबसे आसान तरीका क्या है?

मैं एक पाठ फ़ाइल पढ़ रहा हूँ जिसमें डुप्लिकेट कॉलम हैं:

import pandas as pd

df=pd.read_table(fname)

स्तंभ नाम हैं:

Time, Time Relative, N2, Time, Time Relative, H2, etc...

सभी समय और समय सापेक्ष कॉलम में समान डेटा होता है। मुझे चाहिए:

Time, Time Relative, N2, H2

मेरे सभी प्रयास छोड़ने, हटाने आदि जैसे:

df=df.T.drop_duplicates().T

विशिष्ट मूल्य सूचकांक त्रुटियों में परिणाम:

Reindexing only valid with uniquely valued index objects

पंडों के नोब होने के लिए क्षमा करें। किसी भी सुझाव की सराहना की जाएगी।


अतिरिक्त जानकारिया

पंडों का संस्करण: 0.9.0
पायथन संस्करण: 2.7.3
विंडोज 7
(पायथनियस 2.7.3.0 के माध्यम से स्थापित)

डेटा फ़ाइल (ध्यान दें: वास्तविक फ़ाइल में, कॉलम टैब द्वारा अलग किए जाते हैं, यहां उन्हें 4 स्थानों से अलग किया जाता है):

Time    Time Relative [s]    N2[%]    Time    Time Relative [s]    H2[ppm]
2/12/2013 9:20:55 AM    6.177    9.99268e+001    2/12/2013 9:20:55 AM    6.177    3.216293e-005    
2/12/2013 9:21:06 AM    17.689    9.99296e+001    2/12/2013 9:21:06 AM    17.689    3.841667e-005    
2/12/2013 9:21:18 AM    29.186    9.992954e+001    2/12/2013 9:21:18 AM    29.186    3.880365e-005    
... etc ...
2/12/2013 2:12:44 PM    17515.269    9.991756+001    2/12/2013 2:12:44 PM    17515.269    2.800279e-005    
2/12/2013 2:12:55 PM    17526.769    9.991754e+001    2/12/2013 2:12:55 PM    17526.769    2.880386e-005
2/12/2013 2:13:07 PM    17538.273    9.991797e+001    2/12/2013 2:13:07 PM    17538.273    3.131447e-005

आपके पास पंडों का कौन सा संस्करण है? ( import pandas as pd; pd.__version__ )
दाढ़ी

1
@BirdJaguarIV, मैं पांडा संस्करण का उपयोग कर रहा हूं 0.9.0
केवल

आप 0.10 में अपग्रेड करने का प्रयास कर सकते हैं। मेरा संस्करण मेरे द्वारा read_tableबनाए गए उदाहरण के साथ कॉलम को अद्वितीय बनाता है ।
दाढ़ी

इस बात से सावधान रहें कि df = df.T.drop_duplicates ()। T कॉलम नाम पर विचार नहीं करता है। यदि आपके पास एक ही डेटा के साथ दो कॉलम हैं, लेकिन अलग-अलग नाम हैं, तो एक गलती से गिरा दिया जाएगा।
जॉयलोव

जवाबों:


392

समस्या का एक पंक्ति समाधान है। यह लागू होता है यदि कुछ कॉलम नामों की नकल की जाती है और आप उन्हें हटाना चाहते हैं:

df = df.loc[:,~df.columns.duplicated()]

यह काम किस प्रकार करता है:

मान लें कि डेटा फ़्रेम के कॉलम हैं ['alpha','beta','alpha']

df.columns.duplicated()एक बूलियन सरणी देता है: Trueया Falseप्रत्येक स्तंभ के लिए। यदि यह है, Falseतो स्तंभ नाम उस बिंदु तक अद्वितीय है, यदि यह है Trueतो स्तंभ नाम पहले दोहरा हुआ है। उदाहरण के लिए, दिए गए उदाहरण का उपयोग करके, लौटाया गया मान होगा [False,False,True]

Pandasबूलियन मानों का उपयोग करके एक को अनुक्रमणित करने की अनुमति देता है जिससे यह केवल Trueमानों का चयन करता है । चूंकि हम निर्विवाद कॉलम रखना चाहते हैं, इसलिए हमें उपरोक्त बूलियन सरणी को फ़्लिप करना होगा (अर्थात [True, True, False] = ~[False,False,True])

अंत में, df.loc[:,[True,True,False]]उपरोक्त अनुक्रमित क्षमता का उपयोग करके केवल गैर-डुप्लिकेट किए गए कॉलम का चयन करता है।

नोट : उपरोक्त केवल कॉलम के नामों की जाँच करता है, कॉलम के मूल्यों का नहीं


16
एक आदर्श उत्तर नकली मूल्यों के लिए भी काम करेगा, न कि केवल नामों के लिए।
GrimSqueaker

7
@GrimSqueaker: यदि आप विचार करना चाहते हैं कि क्या मूल्यों की नकल की जाती है, तो आप कुछ ऐसा चाहते हैं df.T.drop_duplicates().T
जॉन ज़्विनक

3
अब तक का सबसे तेज़ समाधान
AtotheSiv

2
@ VaidøtasIvøška कृपया इस प्रश्न
जीन बरिंस्की

2
@ जॉन्जविन: यह केवल छोटे डेटाफ्रेम के लिए काम करता है, क्योंकि आपके द्वारा लिए जाने वाले कॉलम की संख्या की सीमा होती है। मेरे लिए यह उदाहरण के लिए 100,000 पंक्तियों के साथ एक डेटाफ्रेम के लिए असफल रहा, क्योंकि यह ट्रांसपोज़िंग के बाद 100,000 कॉलम देता है, जो संभव नहीं है
ईलको वैन Vliet

40

ऐसा लगता है कि आप पहले से ही अद्वितीय स्तंभ नामों को जानते हैं। अगर ऐसा है, तो df = df['Time', 'Time Relative', 'N2']काम करेंगे।

यदि नहीं, तो आपका समाधान काम करना चाहिए:

In [101]: vals = np.random.randint(0,20, (4,3))
          vals
Out[101]:
array([[ 3, 13,  0],
       [ 1, 15, 14],
       [14, 19, 14],
       [19,  5,  1]])

In [106]: df = pd.DataFrame(np.hstack([vals, vals]), columns=['Time', 'H1', 'N2', 'Time Relative', 'N2', 'Time'] )
          df
Out[106]:
   Time  H1  N2  Time Relative  N2  Time
0     3  13   0              3  13     0
1     1  15  14              1  15    14
2    14  19  14             14  19    14
3    19   5   1             19   5     1

In [107]: df.T.drop_duplicates().T
Out[107]:
   Time  H1  N2
0     3  13   0
1     1  15  14
2    14  19  14
3    19   5   1

संभवतः आपके पास अपने डेटा के लिए कुछ विशिष्ट है जो इसे गड़बड़ कर रहा है। यदि आप डेटा के बारे में अधिक जानकारी दे सकते हैं तो हम और अधिक सहायता दे सकते हैं।

संपादित करें: जैसे एंडी ने कहा, समस्या संभवतः डुप्लिकेट कॉलम शीर्षक के साथ है।

एक नमूना तालिका फ़ाइल 'dummy.csv' के लिए मैंने बनाया:

Time    H1  N2  Time    N2  Time Relative
3   13  13  3   13  0
1   15  15  1   15  14
14  19  19  14  19  14
19  5   5   19  5   1

का उपयोग करते हुए read_tableअद्वितीय स्तंभों देता है और ठीक से काम करता है:

In [151]: df2 = pd.read_table('dummy.csv')
          df2
Out[151]:
         Time  H1  N2  Time.1  N2.1  Time Relative
      0     3  13  13       3    13              0
      1     1  15  15       1    15             14
      2    14  19  19      14    19             14
      3    19   5   5      19     5              1
In [152]: df2.T.drop_duplicates().T
Out[152]:
             Time  H1  Time Relative
          0     3  13              0
          1     1  15             14
          2    14  19             14
          3    19   5              1  

यदि आपका संस्करण आपकी अनुमति नहीं देता है, तो आप उन्हें अद्वितीय बनाने के लिए एक समाधान हैक कर सकते हैं:

In [169]: df2 = pd.read_table('dummy.csv', header=None)
          df2
Out[169]:
              0   1   2     3   4              5
        0  Time  H1  N2  Time  N2  Time Relative
        1     3  13  13     3  13              0
        2     1  15  15     1  15             14
        3    14  19  19    14  19             14
        4    19   5   5    19   5              1
In [171]: from collections import defaultdict
          col_counts = defaultdict(int)
          col_ix = df2.first_valid_index()
In [172]: cols = []
          for col in df2.ix[col_ix]:
              cnt = col_counts[col]
              col_counts[col] += 1
              suf = '_' + str(cnt) if cnt else ''
              cols.append(col + suf)
          cols
Out[172]:
          ['Time', 'H1', 'N2', 'Time_1', 'N2_1', 'Time Relative']
In [174]: df2.columns = cols
          df2 = df2.drop([col_ix])
In [177]: df2
Out[177]:
          Time  H1  N2 Time_1 N2_1 Time Relative
        1    3  13  13      3   13             0
        2    1  15  15      1   15            14
        3   14  19  19     14   19            14
        4   19   5   5     19    5             1
In [178]: df2.T.drop_duplicates().T
Out[178]:
          Time  H1 Time Relative
        1    3  13             0
        2    1  15            14
        3   14  19            14
        4   19   5             1 

5
दुर्भाग्य से df['Time']सभी समय श्रृंखला का चयन करता है (अर्थात एक DataFrame लौटाता है), और df['Time', ..]यह पूरा DataFrame लौटाएगा।
एंडी हेडन

हाँ, यह बहुत थकाऊ है ... उम्मीद है कि यह सिर्फ एक संस्करण अंतर है।
दाढ़ी

2
दोहरे ट्रांज़ोज़ का उपयोग करने से अनपेक्षित साइड इफेक्ट्स हो सकते हैं जैसे कि संख्यात्मक प्रकार को ऑब्जेक्ट में परिवर्तित करना जैसे कि आपके पास मिश्रित प्रकार के साथ डीएफ है। देखें: stackoverflow.com/questions/24682396/…
पेट्रैविनविंक 19

यह समाधान मुझे बड़े डेटाफ़्रेम पर समस्याएं देता है: RecursionError: maximum recursion depth exceeded
स्कॉट

बड़े डेटा फ्रेम का स्थानांतरण धीमी प्रक्रिया होगी
कुश पटेल

13

बड़े डेटाफ़्रेम के लिए ट्रांसपोज़िंग अक्षम है। यहाँ एक विकल्प है:

def duplicate_columns(frame):
    groups = frame.columns.to_series().groupby(frame.dtypes).groups
    dups = []
    for t, v in groups.items():
        dcols = frame[v].to_dict(orient="list")

        vs = dcols.values()
        ks = dcols.keys()
        lvs = len(vs)

        for i in range(lvs):
            for j in range(i+1,lvs):
                if vs[i] == vs[j]: 
                    dups.append(ks[i])
                    break

    return dups       

इसे इस तरह उपयोग करें:

dups = duplicate_columns(frame)
frame = frame.drop(dups, axis=1)

संपादित करें

एक स्मृति कुशल संस्करण जो किसी अन्य मान की तरह नैन का इलाज करता है:

from pandas.core.common import array_equivalent

def duplicate_columns(frame):
    groups = frame.columns.to_series().groupby(frame.dtypes).groups
    dups = []

    for t, v in groups.items():

        cs = frame[v].columns
        vs = frame[v]
        lcs = len(cs)

        for i in range(lcs):
            ia = vs.iloc[:,i].values
            for j in range(i+1, lcs):
                ja = vs.iloc[:,j].values
                if array_equivalent(ia, ja):
                    dups.append(cs[i])
                    break

    return dups

3
एक आकर्षण की तरह काम करता है, बहुत कुशल! का उपयोग कर my_df.T.drop_duplicates().Tबड़े डेटाफ़्रेम पर लटका होगा।
विल

1
लवली समाधान लेकिन 26 अप्रैल, 2017 को मुझे मिला /usr/local/lib/python3.5/dist-packages/ipykernel_launcher.py:17: DeprecationWarning: 'pandas.core.common.array_equivalent' is deprecated and is no longer public API
जॉर्ज फिशर

के if array_equivalent(ia, ja):साथ बदलने के if np.array_equal(ia, ja):लिए एक ही परिणाम का उत्पादन लगता है, लेकिन मैंने पढ़ा है कि यह अच्छी तरह से NaN को संभाल नहीं करता है।
जॉर्ज फिशर

@GeorgeFisher क्या array_equivalentअब भी किसी पुरानी शाखा पर, सार्वजनिक रेपो में अंतर्निहित कोड उपलब्ध है?
कुल्लू

@ लालू अब करंट है numpy.array_equiv; पांडा के लिए, मुझे GitHub पर कोई भी पहले रिलीज़ शाखाएं नहीं pandas.core.commonदिखती हैं , लेकिन शायद देखने के लिए अन्य स्थान हैं
जॉर्ज फिशर

11

यदि मैं गलत नहीं हूं, तो निम्नलिखित में वही होता है जो ट्रांसल्यूशन सॉल्यूशन की मेमोरी प्रॉब्लम्स के बिना और किसी भी समान नाम वाले कॉलम के पहले रखते हुए @kalu के फंक्शन से कम लाइनों के साथ पूछा गया था।

Cols = list(df.columns)
for i,item in enumerate(df.columns):
    if item in df.columns[:i]: Cols[i] = "toDROP"
df.columns = Cols
df = df.drop("toDROP",1)

आपका समाधान मेरे मामले में काम नहीं करता है, यह मुझे दिखाता है: "ValueError: लेबल ['toDROP'] अक्ष में निहित नहीं है" अंतिम लाइन निष्पादित करने के बाद
NuValue

4

ऐसा लग रहा है कि आप सही रास्ते पर थे। यहाँ एक लाइनर है जिसे आप देख रहे थे:

df.reset_index().T.drop_duplicates().T

लेकिन चूंकि संदर्भित त्रुटि संदेश का निर्माण करने वाला कोई उदाहरण डेटा फ़्रेम नहीं है Reindexing only valid with uniquely valued index objects, इसलिए यह कहना मुश्किल है कि समस्या का समाधान क्या होगा। यदि मूल सूचकांक को पुनर्स्थापित करना आपके लिए महत्वपूर्ण है, तो आप यह करें:

original_index = df.index.names
df.reset_index().T.drop_duplicates().reset_index(original_index).T

0

पहला चरण: - पहली पंक्ति को पढ़ें अर्थात सभी कॉलम सभी डुप्लिकेट कॉलम को हटा दें।

दूसरा चरण: - अंत में केवल उस कॉलम को पढ़ें।

cols = pd.read_csv("file.csv", header=None, nrows=1).iloc[0].drop_duplicates()
df = pd.read_csv("file.csv", usecols=cols)

0

मैं इस समस्या में भाग गया, जहां पहले उत्तर द्वारा प्रदान किए गए एक लाइनर ने अच्छी तरह से काम किया। हालाँकि, मुझे अतिरिक्त जटिलता थी जहां कॉलम की दूसरी प्रतिलिपि में सभी डेटा था। पहली प्रति नहीं थी।

समाधान नेगेटिव ऑपरेटर द्वारा टॉगल करके एक डेटा फ़्रेम को विभाजित करके दो डेटा फ़्रेम बनाने के लिए किया गया था। एक बार जब मेरे पास दो डेटा फ़्रेम थे, तो मैंने निम्नलिखित कथन का उपयोग करके भाग लियाlsuffix । इस तरह, मैं तब डेटा के बिना कॉलम को संदर्भ और हटा सकता था।

- इ


0

नीचे दिया गया तरीका मूल रूप से डेटाफ़्रेम के गलत निर्माण के बारे में समीक्षा करने के लिए डूप कॉलम की पहचान करेगा।

dupes = pd.DataFrame(df.columns)
dupes[dupes.duplicated()]

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