पायथन पंडस मूल डेटाफ्रेम में कॉलम पर वापस ग्रुपबी ऑपरेशन परिणाम कैसे असाइन करें?


83

मेरे पास IPython में निम्नलिखित डेटा फ़्रेम है, जहाँ प्रत्येक पंक्ति एक एकल स्टॉक है:

In [261]: bdata
Out[261]:
<class 'pandas.core.frame.DataFrame'>
Int64Index: 21210 entries, 0 to 21209
Data columns:
BloombergTicker      21206  non-null values
Company              21210  non-null values
Country              21210  non-null values
MarketCap            21210  non-null values
PriceReturn          21210  non-null values
SEDOL                21210  non-null values
yearmonth            21210  non-null values
dtypes: float64(2), int64(1), object(4)

मैं एक ग्रुपबी ऑपरेशन लागू करना चाहता हूं जो "वार्षिक" कॉलम में प्रत्येक तिथि के अनुसार, हर चीज में कैप-वेटेड औसत रिटर्न की गणना करता है।

यह उम्मीद के मुताबिक काम करता है:

In [262]: bdata.groupby("yearmonth").apply(lambda x: (x["PriceReturn"]*x["MarketCap"]/x["MarketCap"].sum()).sum())
Out[262]:
yearmonth
201204      -0.109444
201205      -0.290546

लेकिन फिर मैं मूल डेटा फ़्रेम में इन मानों को "ब्रॉडकास्ट" पर वापस सॉर्ट करना चाहता हूं, और उन्हें निरंतर कॉलम के रूप में सहेजता हूं जहां तिथियां मेल खाती हैं।

In [263]: dateGrps = bdata.groupby("yearmonth")

In [264]: dateGrps["MarketReturn"] = dateGrps.apply(lambda x: (x["PriceReturn"]*x["MarketCap"]/x["MarketCap"].sum()).sum())
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/mnt/bos-devrnd04/usr6/home/espears/ws/Research/Projects/python-util/src/util/<ipython-input-264-4a68c8782426> in <module>()
----> 1 dateGrps["MarketReturn"] = dateGrps.apply(lambda x: (x["PriceReturn"]*x["MarketCap"]/x["MarketCap"].sum()).sum())

TypeError: 'DataFrameGroupBy' object does not support item assignment

मुझे एहसास है कि इस भोले काम को काम नहीं करना चाहिए। लेकिन मूल डेटाफ़्रेम पर एक नए कॉलम में एक ग्रुपबी ऑपरेशन के परिणाम को निर्दिष्ट करने के लिए "सही" पंडों का मुहावरा क्या है?

अंत में, मैं चाहता हूं कि "MarketReturn" नामक एक कॉलम उन सभी सूचकांकों के लिए एक निरंतर स्थिर मूल्य होगा जो ग्रुपबी ऑपरेशन के आउटपुट के साथ मिलान की तारीख है।

इसे प्राप्त करने के लिए एक हैक निम्नलिखित होगा:

marketRetsByDate  = dateGrps.apply(lambda x: (x["PriceReturn"]*x["MarketCap"]/x["MarketCap"].sum()).sum())

bdata["MarketReturn"] = np.repeat(np.NaN, len(bdata))

for elem in marketRetsByDate.index.values:
    bdata["MarketReturn"][bdata["yearmonth"]==elem] = marketRetsByDate.ix[elem]

लेकिन यह धीमा, बुरा और unPythonic है।


आप अपने मूल फ़्रेम के बजाय अपने समूहीकृत ऑब्जेक्ट पर वापस आ रहे हैं।
वाउचर ओवरमेइरे

2
मुझे पता है कि और मैंने इसे सीधे त्रुटि के नीचे कहा, जहां मैंने कहा: "मुझे एहसास है कि इस भोले असाइनमेंट को काम नहीं करना चाहिए। लेकिन माता-पिता पर एक नए कॉलम में ग्रुपबी ऑपरेशन के परिणाम को असाइन करने के लिए" सही "पांडस मुहावरा क्या है?" डेटा ढांचा?" LHS पर मेरे मूल डेटा फ्रेम के साथ असाइनमेंट करने से या तो काम नहीं होता है, और यह भी कम सहज है कि GroupBy-object स्तर पर कॉलम को जोड़ना।
ely

जवाबों:


74
In [97]: df = pandas.DataFrame({'month': np.random.randint(0,11, 100), 'A': np.random.randn(100), 'B': np.random.randn(100)})

In [98]: df.join(df.groupby('month')['A'].sum(), on='month', rsuffix='_r')
Out[98]:
           A         B  month       A_r
0  -0.040710  0.182269      0 -0.331816
1  -0.004867  0.642243      1  2.448232
2  -0.162191  0.442338      4  2.045909
3  -0.979875  1.367018      5 -2.736399
4  -1.126198  0.338946      5 -2.736399
5  -0.992209 -1.343258      1  2.448232
6  -1.450310  0.021290      0 -0.331816
7  -0.675345 -1.359915      9  2.722156

इसके बाद भी मुझे उस लाइनबी पर सीधे LHS पर असाइनमेंट करने के बजाय, जहां मैं ग्रुपबी ऑपरेशन करता हूं, ग्रुपबी की गणना से बचाने की आवश्यकता है। लागू हो सकता है सवाल के तल पर मेरी हैक में लूप से थोड़ा बेहतर हो सकता है, लेकिन वे मूल रूप से एक ही विचार हैं।
ely

ज्वाइन कर सकते हैं, लेकिन आपको जोड़े गए कॉलम का नाम बदलना होगा। इस मामले में A_r new_col है।
राउटर ओवरमेइरे

तल पर सम्मिलित उदाहरण काम करता है, लेकिन यह स्पष्ट रूप से प्रस्तुत नहीं किया गया है। यदि आपको उत्तर के पहले भाग को हटाने और बाद वाले हिस्से को थोड़ा और स्पष्ट करने का मन है, तो मैं स्वीकार करने के अलावा भी उठूंगा।
एली

12
मैंने पहला तरीका निकाला। ईमानदार होने के लिए मुझे लगता है कि कोड खुद के लिए बोलता है, यदि आप डॉक्स के लिए कुछ स्पष्टीकरण या संदर्भ जोड़ना चाहते हैं तो संपादित करने के लिए स्वतंत्र महसूस करें। मैं वास्तव में इतने मतदान प्रणाली में नहीं हूं, बस यहां पंडों को थोड़ा समर्थन देने के लिए।
राउटर ओवरमीयर

1
मैंने एक लंबे समय के लिए इस उत्तर की तलाश में बिताया, एक नेक्रो पोस्ट का थोड़ा लेकिन धन्यवाद! +1
डेन कार्टर

52

जब मैं अभी भी अविश्वसनीय रूप से स्मार्ट तरीके खोज रहा हूं, जो applyउसके द्वारा दिए गए टुकड़ों को समेटता है, तो यहां एक और तरीका है कि एक ग्रुपबी ऑपरेशन के बाद माता-पिता में एक नया कॉलम जोड़ें।

In [236]: df
Out[236]: 
  yearmonth    return
0    201202  0.922132
1    201202  0.220270
2    201202  0.228856
3    201203  0.277170
4    201203  0.747347

In [237]: def add_mkt_return(grp):
   .....:     grp['mkt_return'] = grp['return'].sum()
   .....:     return grp
   .....: 

In [238]: df.groupby('yearmonth').apply(add_mkt_return)
Out[238]: 
  yearmonth    return  mkt_return
0    201202  0.922132    1.371258
1    201202  0.220270    1.371258
2    201202  0.228856    1.371258
3    201203  0.277170    1.024516
4    201203  0.747347    1.024516

1
आप df.groupby('yearmonth').apply(lambda grp: grp.assign(mkt_return=grp['return'].sum()))
लंबोदा

32

ग्रुपबी () का उपयोग करते समय एक सामान्य नियम के रूप में, यदि आप .transform () फ़ंक्शन पांडा का उपयोग करते हैं तो आपके मूल के समान लंबाई के साथ एक तालिका वापस आ जाएगी। जब आप अन्य कार्यों जैसे .sum () या .first () का उपयोग करते हैं तो पांडा एक तालिका लौटाएगा जहां प्रत्येक पंक्ति एक समूह है।

मुझे यकीन नहीं है कि यह कैसे लागू होता है, लेकिन परिवर्तन के साथ विस्तृत लंबो कार्यों को लागू करना काफी मुश्किल हो सकता है इसलिए जो रणनीति मुझे सबसे अधिक उपयोगी लगती है वह यह है कि मुझे जिन चर की जरूरत है, उन्हें मूल डेटासेट में रखें और फिर वहां अपना संचालन करें।

अगर मुझे समझ में आ गया है कि आप पहले सही ढंग से क्या करने की कोशिश कर रहे हैं, तो आप प्रत्येक समूह के लिए कुल मार्केट कैप की गणना कर सकते हैं:

bdata['group_MarketCap'] = bdata.groupby('yearmonth')['MarketCap'].transform('sum')

यह आपके समूह के डेटा में "group_MarketCap" नामक एक कॉलम जोड़ेगा जिसमें प्रत्येक समूह के लिए मार्केट कैप का योग होगा। फिर आप सीधे भारित मानों की गणना कर सकते हैं:

bdata['weighted_P'] = bdata['PriceReturn'] * (bdata['MarketCap']/bdata['group_MarketCap'])

और अंत में आप एक ही ट्रांसफ़ॉर्म फ़ंक्शन का उपयोग करके प्रत्येक समूह के लिए भारित औसत की गणना करेंगे:

bdata['MarketReturn'] = bdata.groupby('yearmonth')['weighted_P'].transform('sum')

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

उम्मीद है की यह मदद करेगा :)


24

क्या मैं transformविधि (कुल के बजाय) का सुझाव दे सकता हूं ? यदि आप इसे अपने मूल उदाहरण में उपयोग करते हैं तो यह वही करना चाहिए जो आप चाहते हैं (प्रसारण)।


मेरी समझ यह थी कि परिवर्तन एक ऐसी वस्तु का उत्पादन करता है जो दिखता है जैसे इसे पारित किया गया था। इसलिए यदि आप एक DataFrame को रूपांतरित करते हैं, तो आप केवल एक कॉलम वापस नहीं पाते हैं, आप एक DataFrame वापस पाते हैं जबकि मेरे मामले में, मैं मूल डेटा फ़्रेम में एक नया परिणाम जोड़ना चाहता हूं। या आप कह रहे हैं कि मुझे एक अलग फ़ंक्शन लिखना चाहिए जो डेटा फ़्रेम लेता है, नए कॉलम की गणना करता है, और नए कॉलम को जोड़ता है, और फिर उस फ़ंक्शन के साथ बदल जाता है?
एली

2
मैं मानता हूं, रूपांतरण एक बेहतर विकल्प है, df ['A-month-sum'] = df.groupby ('month') ['A']। transform (राशि)
Wouter Overmeire

लेकिन यह बेहतर क्यों होगा? यह वही करता है, नहीं? क्या यह तेज है?
के-माइकल ऐ

1
IMHO, transformक्लीनर दिखता है। मेरे पास इसकी पुष्टि करने के लिए ईएमएस डेटा नहीं है, लेकिन यह काम कर सकता है (हालाँकि bdata['mkt_return'] = bdata.groupby("yearmonth").transform(lambda x: (x["PriceReturn"]*x["MarketCap"]/x["MarketCap"].sum()).sum())
लंबो

1
मुझे सही करें अगर मैं गलत हूं, transformतो एक के बाद एक कई कॉलमों को संचालित करने की अनुमति नहीं देता groupby, उदाहरण के लिए df.groupby('col_3')[['col_1','col_2']].transform(lambda x: ((1-x.col_1.mean()) - x.col_2.std()))'कोई विशेषता XXX' शिकायत दर्ज करने में त्रुटि होगी
जेसन गोल

0

मुझे मूल डेटाफ्रेम में असाइनमेंट करने का कोई तरीका नहीं मिला। इसलिए मैं सिर्फ समूहों से परिणामों को संग्रहीत करता हूं और उन्हें संक्षिप्त करता हूं। फिर हम इनपुट डेटाफ्रेम के रूप में मूल आदेश प्राप्त करने के लिए इंडेक्स द्वारा कॉन्टेनेटेड डेटाफ्रेम को सॉर्ट करते हैं। यहाँ एक नमूना कोड है:

In [10]: df = pd.DataFrame({'month': np.random.randint(0,11, 100), 'A': np.random.randn(100), 'B': np.random.randn(100)})

In [11]: df.head()
Out[11]:
   month         A         B
0      4 -0.029106 -0.904648
1      2 -2.724073  0.492751
2      7  0.732403  0.689530
3      2  0.487685 -1.017337
4      1  1.160858 -0.025232

In [12]: res = []

In [13]: for month, group in df.groupby('month'):
    ...:     new_df = pd.DataFrame({
    ...:         'A^2+B': group.A ** 2 + group.B,
    ...:         'A+B^2': group.A + group.B**2
    ...:     })
    ...:     res.append(new_df)
    ...:

In [14]: res = pd.concat(res).sort_index()

In [15]: res.head()
Out[15]:
      A^2+B     A+B^2
0 -0.903801  0.789282
1  7.913327 -2.481270
2  1.225944  1.207855
3 -0.779501  1.522660
4  1.322360  1.161495

यह विधि बहुत तेज़ और एक्स्टेंसिबल है। आप यहां किसी भी सुविधा को प्राप्त कर सकते हैं।

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