2015-12-05 6 views
6

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

यहाँ एक उदाहरण dataframe है:

foo_function = lambda x: np.sum(x.a+x.b) 

df = pd.DataFrame({'a':[1,2,3,4,5,6], 
        'b':[1,2,3,4,5,6], 
        'c':['q', 'q', 'q', 'q', 'w', 'w'], 
        'd':['z','z','z','o','o','o']}) 

# works with apply, but I want transform: 
df.groupby(['c', 'd'])[['a','b']].apply(foo_function) 
# transform doesn't work! 
df.groupby(['c', 'd'])[['a','b']].transform(foo_function) 
TypeError: cannot concatenate a non-NDFrame object 

लेकिन transform जाहिरा तौर पर एकाधिक स्तंभों को एक साथ गठबंधन करने के लिए सक्षम नहीं है, क्योंकि यह (लागू विपरीत) अलग से प्रत्येक स्तंभ पर लग रहा है। गति/लालित्य के मामले में अगला सबसे अच्छा विकल्प क्या है? जैसे मैं apply का उपयोग कर सकता हूं और फिर pd.match का उपयोग कर बना सकता हूं, लेकिन कभी-कभी कई समूह-कॉलम (col1 और col2) से मेल खाने की आवश्यकता होती है जो वास्तव में हैकी/उचित मात्रा में कोड लेती है।

-> क्या कोई ऐसा फ़ंक्शन है जो groupby() के रूप में है। ट्रांसफॉर्म जो कई कॉलम पर काम करने वाले फ़ंक्शंस का उपयोग कर सकता है? यदि यह अस्तित्व में नहीं है, तो सबसे अच्छा हैक क्या है?

उत्तर

5

सर्का पांडा संस्करण 0.18, ऐसा लगता है कि मूल उत्तर (नीचे) अब काम नहीं करता है।

इसके बजाय, आप, GroupBy एकाधिक स्तंभों के पार एक GroupBy गणना कर बहु-स्तंभ गणना पहले करते हैं, और उसके बाद करने की आवश्यकता है:

df = pd.DataFrame({'a':[1,2,3,4,5,6], 
        'b':[1,2,3,4,5,6], 
        'c':['q', 'q', 'q', 'q', 'w', 'w'], 
        'd':['z','z','z','o','o','o']}) 
df['e'] = df['a'] + df['b'] 
df['e'] = (df.groupby(['c', 'd'])['e'].transform('sum')) 
print(df) 

पैदावार

a b c d e 
0 1 1 q z 12 
1 2 2 q z 12 
2 3 3 q z 12 
3 4 4 q o 8 
4 5 5 w o 22 
5 6 6 w o 22 

मूल उत्तर:

मुझे त्रुटि ssage:

TypeError: cannot concatenate a non-NDFrame object 

पता चलता है कि आदेश को श्रेणीबद्ध करने के लिए, foo_function एक NDFrame लौटना चाहिए (जैसे कि एक सीरीज या DataFrame के रूप में)। यदि आप एक श्रृंखला, तो वापस नहीं आ जाते:

In [99]: df.groupby(['c', 'd']).transform(lambda x: pd.Series(np.sum(x['a']+x['b']))) 
Out[99]: 
    a b 
0 12 12 
1 12 12 
2 12 12 
3 8 8 
4 22 22 
5 22 22 
+0

यह 0.1 9 .1 में एक महत्वपूर्ण त्रुटि फेंक रहा है। यह मेरी समझ थी कि रूपांतरण एक श्रृंखला (प्रत्येक कॉलम) को फ़ंक्शन में पास करता है। लेकिन बहुत अजीब बात यह है कि उपरोक्त डेटा के साथ निम्नलिखित चलने पर भी एक बार डेटाफ्रेम भी गुजरता है। 'df.groupby (['c', 'd'])। ट्रांसफॉर्म (लैम्ब्डा x: प्रिंट (प्रकार (x)))'।यह एक बग –

+0

@TedPetrou जैसा दिखता है: इसे इंगित करने के लिए धन्यवाद। एक प्रदर्शन वृद्धि के रूप में, 'ट्रांसफॉर्म' - जैसे 'लागू करें' - फ़ंक्शन को (उप-) डेटाफ्रेम पर लागू करने का प्रयास कर सकता है। कुछ परिस्थितियों में (जैसे वेक्टरकृत फ़ंक्शन और कॉलम के बहुत सारे) यह प्रत्येक समूह और कॉलम के लिए फ़ंक्शन को लागू करने से तेज़ हो सकता है। – unutbu

+0

@TedPetrou: 'KeyError' के बारे में - अब जब मैं अपने मूल उत्तर पर वापस देखता हूं, तो मुझे नहीं लगता कि मैंने जो समाधान सुझाया है वह एक अच्छा है। 'ट्रांसफॉर्म' प्रत्येक समूह के लिए फ़ंक्शन को एक बार कॉल करता है। यदि आप बड़े इनपुट पर वेक्टरिज्ड कार्यों को कम समय कहते हैं तो आपको बेहतर प्रदर्शन मिलता है। इसलिए, कॉलिंग 'ट्रांसफॉर्म' से पहले * पूरे कॉलम पर' df ['a'] + df ['b'] 'की गणना करने के लिए यह अधिक समझ में आता है। मैंने उपर्युक्त पोस्ट को संशोधित करने के लिए संशोधित किया है जो मेरा मतलब है। – unutbu

1

तरह से मैं सवाल पढ़ा है, आप कुछ दोनों दोनों स्तंभ से अलग-अलग मूल्यों के साथ मनमाना ऐसा करने में सक्षम होना चाहता हूँ। तुम बस एक ही आकार के एक dataframe वापस जाने के लिए के रूप में आप में पारित हो सुनिश्चित करने की आवश्यकता मुझे लगता है कि सबसे अच्छा तरीका है बस एक नया स्तंभ बनाने के लिए, इस तरह है:।

df = pd.DataFrame({'a':[1,2,3,4,5,6], 
        'b':[1,2,3,4,5,6], 
        'c':['q', 'q', 'q', 'q', 'w', 'w'], 
        'd':['z','z','z','o','o','o']}) 
df['e']=0 

def f(x): 
    y=(x['a']+x['b'])/sum(x['b']) 
    return pd.DataFrame({'e':y,'a':x['a'],'b':x['b']}) 

df.groupby(['c','d']).transform(f) 

:

a b e 
0 1 1 0.333333 
1 2 2 0.666667 
2 3 3 1.000000 
3 4 4 2.000000 
4 5 5 0.909091 
5 6 6 1.090909 

आप एक बहुत ही जटिल dataframe है, तो आप अपने कॉलम (जैसे df.groupby(['c'])['a','b','e'].transform(f))

यह सुनिश्चित करें कि मेरे लिए बहुत असजीला लग रहा है, लेकिन यह अभी भी बहुत तेजी से apply से बड़े डेटा सेट पर है चुन सकते हैं।

एक और विकल्प set_index का उपयोग करने के लिए आवश्यक सभी कॉलम कैप्चर करने के लिए है और फिर केवल एक कॉलम transform पर पास करें।

संबंधित मुद्दे