पांडा डेटाफ़्रेम में टुपल्स के कॉलम को कैसे विभाजित करें?


91

मेरे पास एक पांडा डेटाफ़्रेम है (यह केवल एक छोटा सा टुकड़ा है)

>>> d1
   y norm test  y norm train  len(y_train)  len(y_test)  \
0    64.904368    116.151232          1645          549   
1    70.852681    112.639876          1645          549   

                                    SVR RBF  \
0   (35.652207342877873, 22.95533537448393)   
1  (39.563683797747622, 27.382483096332511)   

                                        LCV  \
0  (19.365430594452338, 13.880062435173587)   
1  (19.099614489458364, 14.018867136617146)   

                                   RIDGE CV  \
0  (4.2907610988480362, 12.416745648065584)   
1    (4.18864306788194, 12.980833914392477)   

                                         RF  \
0   (9.9484841581029428, 16.46902345373697)   
1  (10.139848213735391, 16.282141345406522)   

                                           GB  \
0  (0.012816232716538605, 15.950164822266007)   
1  (0.012814519804493328, 15.305745202851712)   

                                             ET DATA  
0  (0.00034337162272515505, 16.284800366214057)  j2m  
1  (0.00024811554516431878, 15.556506191784194)  j2m  
>>> 

मैं उन सभी स्तंभों को विभाजित करना चाहता हूं जिनमें टुपल्स शामिल हैं। उदाहरण के लिए मैं कॉलम के LCVसाथ कॉलम को बदलना चाहता हूं LCV-aऔर LCV-b

मैं उसे कैसे कर सकता हूँ?

जवाबों:


167

आप इसे pd.DataFrame(col.tolist())उस कॉलम पर कर सकते हैं :

In [2]: df = pd.DataFrame({'a':[1,2], 'b':[(1,2), (3,4)]})                                                                                                                      

In [3]: df                                                                                                                                                                      
Out[3]: 
   a       b
0  1  (1, 2)
1  2  (3, 4)

In [4]: df['b'].tolist()                                                                                                                                                        
Out[4]: [(1, 2), (3, 4)]

In [5]: pd.DataFrame(df['b'].tolist(), index=df.index)                                                                                                                                          
Out[5]: 
   0  1
0  1  2
1  3  4

In [6]: df[['b1', 'b2']] = pd.DataFrame(df['b'].tolist(), index=df.index)                                                                                                                       

In [7]: df                                                                                                                                                                      
Out[7]: 
   a       b  b1  b2
0  1  (1, 2)   1   2
1  2  (3, 4)   3   4

नोट: एक पुराने संस्करण में, इस उत्तर के df['b'].apply(pd.Series)बजाय उपयोग करने की सिफारिश की गई है pd.DataFrame(df['b'].tolist(), index=df.index)। यह भी काम करता है (क्योंकि यह प्रत्येक टपल को एक श्रृंखला बनाता है, जिसे बाद में डेटाफ़्रेम की एक पंक्ति के रूप में देखा जाता है), लेकिन धीमी है / tolistसंस्करण की तुलना में अधिक स्मृति का उपयोग करता है , जैसा कि अन्य उत्तरों द्वारा यहां उल्लेख किया गया है (@denfromufa के लिए धन्यवाद) ।
मैंने इस उत्तर को अपडेट किया है, यह सुनिश्चित करने के लिए कि सबसे दृश्यमान उत्तर के पास सबसे अच्छा समाधान है।


2
क्या बड़ी संख्या में स्तंभों के कारण इसे स्वचालित करने का एक तरीका है?
डोंबेबो

सीधे तौर पर मुझे नहीं लगता। लेकिन आप आसानी से उपरोक्त कोड (+ मूल को हटाकर) का उपयोग करके इसके लिए एक फ़ंक्शन लिख सकते हैं
जोरिस

यदि आपके पास बड़ी संख्या में स्तंभ हैं, तो आप अपने डेटा को 'साफ' करने पर विचार कर सकते हैं: vita.had.co.nz/papers/tidy-data.html आप इसे पिघल फ़ंक्शन का उपयोग करके कर सकते हैं।
एक्सल

.apply (pd.Series) ठीक काम करता है, लेकिन बड़े डेटासेट के लिए बहुत अधिक मेमोरी की खपत होती है और मेमोरी एरर का कारण बन सकता है
यूरी वॉलेट

27

बहुत बड़े डेटासेट पर, मैंने पाया कि .apply()कुछ ऑर्डर धीमा हैpd.DataFrame(df['b'].values.tolist(), index=df.index)

यह प्रदर्शन समस्या GitHub में बंद कर दी गई थी, हालांकि मैं इस निर्णय से सहमत नहीं हूं:

https://github.com/pandas-dev/pandas/issues/11615

EDIT: इस उत्तर पर आधारित: https://stackoverflow.com/a/44196843/2230844


5
pd.DataFrame(df['b'].tolist())बिना .valuesकाम भी ठीक लगता है। (और धन्यवाद, आपका समाधान इससे कहीं अधिक तेज है .apply())
स्वियर

मैं सूचकांक पर कब्जा करने के बारे में चिंतित था, इसलिए .values ​​का स्पष्ट उपयोग।
denfromufa

1
@denfromufa द्वारा समाधान सुपर फास्ट df [['b1', 'b2']] = pd.DataFrame (df ['b'] काम करता है। मान ..tolist (), index = df.index और कोई मेमोरी त्रुटि का कारण (के रूप में) .apply (pd.Series) की तुलना में
यूरी वॉलेट

22

strएक्सेसर कि के लिए उपलब्ध है pandas.Seriesकी वस्तुओं dtype == objectवास्तव में एक iterable है।

मान लें pandas.DataFrame df:

df = pd.DataFrame(dict(col=[*zip('abcdefghij', range(10, 101, 10))]))

df

        col
0   (a, 10)
1   (b, 20)
2   (c, 30)
3   (d, 40)
4   (e, 50)
5   (f, 60)
6   (g, 70)
7   (h, 80)
8   (i, 90)
9  (j, 100)

हम परीक्षण कर सकते हैं अगर यह एक चलने योग्य है

from collections import Iterable

isinstance(df.col.str, Iterable)

True

हम इसे तब से असाइन कर सकते हैं जैसे हम अन्य पुनरावृत्तियाँ करते हैं:

var0, var1 = 'xy'
print(var0, var1)

x y

सबसे सरल उपाय

तो एक पंक्ति में हम दोनों कॉलम असाइन कर सकते हैं

df['a'], df['b'] = df.col.str

df

        col  a    b
0   (a, 10)  a   10
1   (b, 20)  b   20
2   (c, 30)  c   30
3   (d, 40)  d   40
4   (e, 50)  e   50
5   (f, 60)  f   60
6   (g, 70)  g   70
7   (h, 80)  h   80
8   (i, 90)  i   90
9  (j, 100)  j  100

तेजी से समाधान

केवल थोड़ा और जटिल, हम zipएक समान चलने योग्य बनाने के लिए उपयोग कर सकते हैं

df['c'], df['d'] = zip(*df.col)

df

        col  a    b  c    d
0   (a, 10)  a   10  a   10
1   (b, 20)  b   20  b   20
2   (c, 30)  c   30  c   30
3   (d, 40)  d   40  d   40
4   (e, 50)  e   50  e   50
5   (f, 60)  f   60  f   60
6   (g, 70)  g   70  g   70
7   (h, 80)  h   80  h   80
8   (i, 90)  i   90  i   90
9  (j, 100)  j  100  j  100

पंक्ति में

मतलब, मौजूदा को म्यूट न करें df
क्योंकि यह काम करता है क्योंकि assignकीवर्ड तर्क लेता है जहां कीवर्ड नए (या मौजूदा) कॉलम नाम हैं और मान नए कॉलम के मान होंगे। आप एक डिक्शनरी का उपयोग कर सकते हैं और इसे अनपैक कर सकते हैं **और यह कीवर्ड तर्क के रूप में कार्य कर सकता है। तो यह एक नया कॉलम असाइन करने का एक चतुर तरीका है जिसका नाम 'g'है, जो df.col.strपुनरावृत्त में पहला आइटम है और 'h'जो पुनरावृत्त में दूसरा आइटम है df.col.str

df.assign(**dict(zip('gh', df.col.str)))

        col  g    h
0   (a, 10)  a   10
1   (b, 20)  b   20
2   (c, 30)  c   30
3   (d, 40)  d   40
4   (e, 50)  e   50
5   (f, 60)  f   60
6   (g, 70)  g   70
7   (h, 80)  h   80
8   (i, 90)  i   90
9  (j, 100)  j  100

का मेरा संस्करण list दृष्टिकोण

आधुनिक सूची की समझ और चर unpacking के साथ।
नोट: इनलाइन का उपयोग करjoin

df.join(pd.DataFrame([*df.col], df.index, [*'ef']))

        col  g    h
0   (a, 10)  a   10
1   (b, 20)  b   20
2   (c, 30)  c   30
3   (d, 40)  d   40
4   (e, 50)  e   50
5   (f, 60)  f   60
6   (g, 70)  g   70
7   (h, 80)  h   80
8   (i, 90)  i   90
9  (j, 100)  j  100

उत्परिवर्तन संस्करण होगा

df[['e', 'f']] = pd.DataFrame([*df.col], df.index)

Naive Time Test

लघु डेटाफ़्रेम

ऊपर परिभाषित एक का उपयोग करें

%timeit df.assign(**dict(zip('gh', df.col.str)))
%timeit df.assign(**dict(zip('gh', zip(*df.col))))
%timeit df.join(pd.DataFrame([*df.col], df.index, [*'gh']))

1.16 ms ± 21.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
635 µs ± 18.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
795 µs ± 42.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
लंबा डाटाफ़्रेम

10 ^ 3 गुना बड़ा

df = pd.concat([df] * 1000, ignore_index=True)

%timeit df.assign(**dict(zip('gh', df.col.str)))
%timeit df.assign(**dict(zip('gh', zip(*df.col))))
%timeit df.join(pd.DataFrame([*df.col], df.index, [*'gh']))

11.4 ms ± 1.53 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.1 ms ± 41.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.33 ms ± 35.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

2
TL जोड़ने पर विचार करें; DR: df['a'], df['b'] = df.col.str:)
mirekphd

11

मुझे लगता है कि एक सरल तरीका है:

>>> import pandas as pd
>>> df = pd.DataFrame({'a':[1,2], 'b':[(1,2), (3,4)]}) 
>>> df
   a       b
0  1  (1, 2)
1  2  (3, 4)
>>> df['b_a']=df['b'].str[0]
>>> df['b_b']=df['b'].str[1]
>>> df
   a       b  b_a  b_b
0  1  (1, 2)    1    2
1  2  (3, 4)    3    4

1
यह समाधान वास्तव में बहुत अधिक सरल है
ApplePie

@jinhuawang ऐसा प्रतीत होता है कि यह strकिसी pd.Seriesवस्तु के प्रतिनिधित्व के शीर्ष पर हैक है । क्या आप बता सकते हैं कि यह कैसे काम करता है ?!

मुझे लगता है कि यह कैसे str ऑब्जेक्ट काम करता है? आप str के साथ एरे ऑब्जेक्ट को एक्सेस कर सकते हैं
जिंहुआ वांग

क्या होगा यदि कुछ पंक्तियों में भिन्न मानों के साथ ट्यूपल हैं?
मामिकिन्स

मुझे लगता है कि यह स्वीकार किया जाना चाहिए। यह और अधिक 'पांडा-ऑनिक' है ... यदि यह बात है।
नटच

8

मुझे पता है कि यह कुछ समय पहले की बात है, लेकिन दूसरे समाधान का एक विवरण:

pd.DataFrame(df['b'].values.tolist())

यह है कि यह स्पष्ट रूप से सूचकांक को छोड़ देगा, और डिफ़ॉल्ट अनुक्रमिक सूचकांक में जोड़ देगा, जबकि स्वीकृत उत्तर

apply(pd.Series)

नहीं होगा, क्योंकि आवेदन का परिणाम पंक्ति सूचकांक को बनाए रखेगा। हालांकि आदेश को मूल सरणी से बनाए रखा गया है, पंडों दो डेटाफ्रेम से संकेतों से मेल खाने की कोशिश करेंगे।

यह बहुत महत्वपूर्ण हो सकता है यदि आप पंक्तियों को संख्यात्मक रूप से अनुक्रमित सरणी में सेट करने का प्रयास कर रहे हैं, और पांडा स्वचालित रूप से नए सरणी के सूचकांक को पुराने से मिलान करने का प्रयास करेंगे, और क्रम में कुछ विरूपण का कारण बनेंगे।

एक बेहतर हाइब्रिड समाधान मूल डेटाफ्रेम के सूचकांक को नए पर सेट करने के लिए होगा, अर्थात

pd.DataFrame(df['b'].values.tolist(), index=df.index)

जो आदेश को सुनिश्चित करते हुए दूसरी विधि का उपयोग करने की गति को बनाए रखेगा और परिणाम पर अनुक्रमण को बनाए रखेगा।


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