2017-05-04 23 views
11

संपादित साथ बताए कॉलम:पांडा: कई की स्थिति और तारीख थ्रेसहोल्ड

मैं एक पांडा dataframe df, जहां सूचकांक तारीख है में एक वित्तीय पोर्टफोलियो है और मैं तारीख प्रति कई वित्तीय शेयरों की है।

जैसे dataframe:

Date Stock Weight Percentile Final weight 
1/1/2000 Apple 0.010 0.75 0.010 
1/1/2000 IBM 0.011 0.4  0 
1/1/2000 Google 0.012 0.45 0 
1/1/2000 Nokia 0.022 0.81 0.022 
2/1/2000 Apple 0.014 0.56 0 
2/1/2000 Google 0.015 0.45 0 
2/1/2000 Nokia 0.016 0.55 0 
3/1/2000 Apple 0.020 0.52 0 
3/1/2000 Google 0.030 0.51 0 
3/1/2000 Nokia 0.040 0.47 0 

मैं Weight के बताए मूल्यों कर जब भी Percentile से अधिक 0.7

अब मैं इस में थोड़ा और अधिक परिष्कृत होना चाहते है के द्वारा बनाई गई Final_weight, मैं अभी भी Weight चाहते होने के लिए Final_weight को Percentile is > 0.7 को सौंपा गया, हालांकि इस तिथि के बाद (भविष्य में किसी भी बिंदु पर) 0 के बजाय>0.7 नहीं है, हम अभी भी वजन कम करेंगे टी जब तक स्टॉक Percentile0.5 से ऊपर है (यानी केवल एक दिन से अधिक समय तक स्थिति धारण करना)।

फिर यदि स्टॉक 0.5 (निकट भविष्य में) Final_weight would become 0 से नीचे चला जाता है।

उदाहरण के ऊपर से dataframe संशोधित:

Date Stock Weight Percentile Final weight 
1/1/2000 Apple 0.010 0.75 0.010 
1/1/2000 IBM  0.011 0.4  0 
1/1/2000 Google 0.012 0.45 0 
1/1/2000 Nokia 0.022 0.81 0.022 
2/1/2000 Apple 0.014 0.56 0.014 
2/1/2000 Google 0.015 0.45 0 
2/1/2000 Nokia 0.016 0.55 0.016 
3/1/2000 Apple 0.020 0.52 0.020 
3/1/2000 Google 0.030 0.51 0 
3/1/2000 Nokia 0.040 0.47 0 

हर दिन विभागों विभिन्न हमेशा से पहले दिन से ही शेयर नहीं कर रहे हैं।

+0

क्या आपके पास हमें दिखाने के लिए कोई प्रयास कोड है? –

+0

कोड मैंने लिखा है यदि पीआईआरएसक्वार्डेस के समान ही उत्तर दिया गया है, हालांकि यह केवल एक दिन पहले देखता है, मैं चाहता हूं कि डेटासेट बड़े पैमाने पर – MysterioProgrammer91

उत्तर

4

यह समाधान अधिक स्पष्ट और कम पांडा-एस्क्यू है, लेकिन इसमें कई पंक्तियों के माध्यम से केवल एक ही पास शामिल है, बिना अस्थायी कॉलम बनाये, और इसलिए संभवतः तेज़ है। इसे एक अतिरिक्त राज्य चर की आवश्यकता है, जिसे मैंने कक्षा बनाने के लिए इसे बंद करने के लिए लपेट लिया है।

def closure(): 
    cur_weight = {} 
    def func(x): 
     if x["Percentile"] > 0.7: 
      next_weight = x["Weight"] 
     elif x["Percentile"] < 0.5 : 
      next_weight = 0 
     else: 
      next_weight = x["Weight"] if cur_weight.get(x["Stock"], 0) > 0 else 0 
     cur_weight[x["Stock"]] = next_weight 
     return next_weight 
    return func 

df["FinalWeight"] = df.apply(closure(), axis=1) 
+0

महान उत्तर .... इतनी तेज़! – MysterioProgrammer91

+0

@ MysterioProgrammer91 पूरे डेटासेट पर यह कितना तेज़ है? (जिसके लिए आपने कहा कि इसे दूसरे उत्तर के लिए लगभग 3 दिन लग गए)। –

+0

@ क्रोनोस जब तक यह मेरा सबमिशन नहीं था, जो हो सकता है, यह हो सकता है कि 'बंद करें' को बदलकर संकेतक चर दें और फिर 'डीएफ [' अंतिम वजन '] = डीएफ [' अंतिम वजन '] * डीएफ ['वज़न'] 'आवेदन करने के बाद इसे तेज करना चाहिए, जब मैंने इसका परीक्षण किया तो मेरे लिए लगभग 10%। – EFT

3
  • मैं पहली बार
  • फिर सूचकांक में 'Stock' डाल था unstack उन्हें स्तंभों में डाल करने के लिए
  • मैं तो प्रतिशतक
  • के लिए वजन के लिए w और p
  • विभाजित था तब की एक श्रृंखला के साथ हेरफेर where

d1 = df.set_index('Stock', append=True) 

d2 = d1.unstack() 

w, p = d2.Weight, d2.Percentile 

d1.join(w.where(p > .7, w.where((p.shift() > .7) & (p > .5), 0)).stack().rename('Final Weight')) 

        Weight Percentile Final Weight 
Date  Stock         
2000-01-01 Apple 0.010  0.75   0.010 
      IBM  0.011  0.40   0.000 
      Google 0.012  0.45   0.000 
      Nokia 0.022  0.81   0.022 
2000-02-01 Apple 0.014  0.56   0.014 
      Google 0.015  0.45   0.000 
      Nokia 0.016  0.55   0.016 
+0

के कारण लूप के बिना अधिमानतः ऐसा करने के लिए एक अच्छा पांडा तरीका चाहता था हाय उत्तर के लिए बहुत बहुत धन्यवाद। मैंने प्रश्न में उदाहरण डेटाफ्रेम में संशोधन किया है। मैं वास्तव में केवल एक शिफ्ट को नहीं देख रहा हूं, यानी, हम स्टॉक खरीदने के बाद शीर्ष 30 प्रतिशत में, जब तक यह 0.5 से अधिक रहता है, तब तक हम इसका स्वामित्व करेंगे, उदाहरण के लिए 10 दिनों तक भी हो सकता है। मैं अभी भी एक भार आवंटित करूंगा, लेकिन जैसे ही प्रतिशत 0.5 से नीचे है, यह अंतिम वजन को वजन नहीं देगा और यह तब तक इंतजार करेगा जब तक यह 0.7 प्रतिशत से अधिक न हो। – MysterioProgrammer91

1

मुझे लगता है कि आप पांडा का उपयोग करना चाह सकते हैं। श्रृंखला rolling विंडो विधि।

शायद कुछ इस तरह:

import pandas as pd 

grouped = df.groupby('Stock') 

df['MaxPercentileToDate'] = np.NaN 
df.index = df['Date'] 

for name, group in grouped: 
    df.loc[df.Stock==name, 'MaxPercentileToDate'] = group['Percentile'].rolling(min_periods=0, window=4).max() 

# Mask selects rows that have ever been greater than 0.75 (including current row in max) 
# and are currently greater than 0.5 
mask = ((df['MaxPercentileToDate'] > 0.75) & (df['Percentile'] > 0.5)) 
df.loc[mask, 'Finalweight'] = df.loc[mask, 'Weight'] 

मेरा मानना ​​है कि यह मान लिया गया मूल्यों की तिथि (अपने प्रारंभिक डाटासेट है लगता है) द्वारा हल कर रहे हैं, और आप भी अधिकतम संख्या होने के लिए min_periods पैरामीटर को समायोजित करने के लिए होगा प्रति स्टॉक प्रविष्टियों की।

2

एक विधि, लूप और सीमित लुकबैक अवधि से परहेज।

import pandas as pd 
import numpy as np 


>>>df = pd.DataFrame([['1/1/2000', 'Apple', 0.010, 0.75], 
         ['1/1/2000', 'IBM',  0.011, 0.4], 
         ['1/1/2000', 'Google', 0.012, 0.45], 
         ['1/1/2000', 'Nokia', 0.022, 0.81], 
         ['2/1/2000', 'Apple', 0.014, 0.56], 
         ['2/1/2000', 'Google', 0.015, 0.45], 
         ['2/1/2000', 'Nokia', 0.016, 0.55], 
         ['3/1/2000', 'Apple', 0.020, 0.52], 
         ['3/1/2000', 'Google', 0.030, 0.51], 
         ['3/1/2000', 'Nokia', 0.040, 0.47]], 
        columns=['Date', 'Stock', 'Weight', 'Percentile']) 

पहले, पहचान जब शेयरों शुरू करने या बंद कर देंगे अंतिम वजन में पता लगाया जा रहा:

>>>df['bought'] = np.where(df['Percentile'] >= 0.7, 1, np.nan) 
>>>df['bought or sold'] = np.where(df['Percentile'] < 0.5, 0, df['bought']) 

'1' के साथ खरीदने के लिए एक शेयर का संकेत है, और '0

अपने उदाहरण का उपयोग 'स्वामित्व वाले, बेचने के लिए एक।

इससे, आप यह पहचान सकते हैं कि स्टॉक का स्वामित्व है या नहीं। ध्यान दें कि यह जरूरी है कि पहले से ही dataframe कालक्रम के अनुसार हल हो, अगर किसी भी बिंदु पर आप एक तिथि सूचकांक के बिना एक dataframe पर इसका इस्तेमाल:

>>>df['own'] = df.groupby('Stock')['bought or sold'].fillna(method='ffill').fillna(0) 

'ffill' आगे भरने, खरीद से आगे स्वामित्व की स्थिति के प्रचार और तिथियों को बेचने जाता है। .fillna(0) डेटाफ्रेम की पूरी तरह से .5 और .7 के बीच बने किसी भी स्टॉक को पकड़ता है। फिर,

>>>df['Final Weight'] = df['own']*df['Weight'] 

गुणा, गणना अंतिम भार df['own'] पहचान या शून्य होने के साथ, एक और np.where की तुलना में थोड़ा तेज है और एक ही परिणाम देता है।

संपादित करें:

के बाद से गति चिंता का विषय है, एक स्तंभ में सब कुछ कर रही है, के रूप में @cronos ने सुझाव दिया है, मेरे परीक्षणों में 20 पंक्तियों में एक गति को बढ़ावा देने, एक 37% सुधार के आसपास में आ रहा है प्रदान करता है, या 18% 2,000,000 पर। मैं बाद में बड़ा कल्पना कर सकता हूं कि इंटरमीडिएट कॉलम को संग्रहीत करना कुछ प्रकार की मेमोरी-थ्रेशोल्ड को पार करना था या सिस्टम विनिर्देशों में कुछ और शामिल था जिसे मैंने अनुभव नहीं किया था।

यह दिखाई देगा:

>>>df['Final Weight'] = np.where(df['Percentile'] >= 0.7, 1, np.nan) 
>>>df['Final Weight'] = np.where(df['Percentile'] < 0.5, 0, df['Final Weight']) 
>>>df['Final Weight'] = df.groupby('Stock')['Final Weight'].fillna(method='ffill').fillna(0) 
>>>df['Final Weight'] = df['Final Weight']*df['Weight'] 

या तो इस पद्धति का उपयोग या मध्यवर्ती क्षेत्रों को हटाने परिणाम देना होगा:

>>>df 
     Date Stock Weight Percentile Final Weight 
0 1/1/2000 Apple 0.010  0.75   0.010 
1 1/1/2000  IBM 0.011  0.40   0.000 
2 1/1/2000 Google 0.012  0.45   0.000 
3 1/1/2000 Nokia 0.022  0.81   0.022 
4 2/1/2000 Apple 0.014  0.56   0.014 
5 2/1/2000 Google 0.015  0.45   0.000 
6 2/1/2000 Nokia 0.016  0.55   0.016 
7 3/1/2000 Apple 0.020  0.52   0.020 
8 3/1/2000 Google 0.030  0.51   0.000 
9 3/1/2000 Nokia 0.040  0.47   0.000 

आगे सुधार के लिए, मैं स्थापित करने के लिए एक तरह से जोड़ने को देखो चाहते हैं एक प्रारंभिक स्थिति जिसमें शेयरों का स्वामित्व है, उसके बाद डेटाफ्रेम को तोड़ने के बाद छोटे समय सीमा को देखने के लिए। यह इन छोटे dataframes में से एक के अंतर्गत आने वाले समय अवधि के लिए एक प्रारंभिक शर्त जोड़ने, तो

>>>df['Final Weight'] = np.where((df['Percentile'] >= 0.7) | (df['Final Weight'] != 0), 1, np.nan) 

तरह

>>>df['Final Weight'] = np.where(df['Percentile'] >= 0.7, 1, np.nan) 

बदलते कुछ करने के लिए है कि मान्यता प्राप्त है और प्रचार करने की अनुमति देने के द्वारा किया जा सकता है।

+0

यह काम करता है लेकिन मेरे पोर्टफोलियो में शेयरों की संख्या और बड़ी डेटा प्रकृति के कारण इसे चलाने में लगभग 3 दिन लगते हैं। इसे तेजी से बनाने का कोई तरीका? – MysterioProgrammer91

+1

अच्छा जवाब। लेकिन आप शुरुआत से ही एक 'फाइनलवाइट' कॉलम का उपयोग कर इसे तेजी से बना सकते हैं और उस पर काम कर सकते हैं। 3 अस्थायी कॉलम रखने की आवश्यकता नहीं है। – cronos

+0

@ MysterioProgrammer91 क्या आप अपने डेटासेट (# पंक्तियों, # विशिष्ट स्टॉक) की आंतरिक संरचना और उस वातावरण को वर्णित कर सकते हैं जिसमें आप इसे चला रहे हैं? मुझे एक परिदृश्य का निर्माण करने में कुछ परेशानी हो रही है जिसमें मेरा उस समय कहीं भी ले जाता है, जबकि डेटाफ्रेम जिस पर यह काम करता है, स्मृति में फिट बैठता है, और यह जानकारी यह पता लगाने में एक बड़ी मदद होगी कि मैं वर्तमान में कहां और कैसे तकनीक में विफल हूं पैमाने। – EFT

2

सेटअप

Dataframe: 

      Stock Weight Percentile Finalweight 
Date            
2000-01-01 Apple 0.010  0.75   0 
2000-01-01  IBM 0.011  0.40   0 
2000-01-01 Google 0.012  0.45   0 
2000-01-01 Nokia 0.022  0.81   0 
2000-02-01 Apple 0.014  0.56   0 
2000-02-01 Google 0.015  0.45   0 
2000-02-01 Nokia 0.016  0.55   0 
2000-03-01 Apple 0.020  0.52   0 
2000-03-01 Google 0.030  0.51   0 
2000-03-01 Nokia 0.040  0.57   0 

समाधान

df = df.reset_index() 
#find historical max percentile for a Stock 
df['max_percentile'] = df.apply(lambda x: df[df.Stock==x.Stock].iloc[:x.name].Percentile.max() if x.name>0 else x.Percentile, axis=1) 
#set weight according to max_percentile and the current percentile 
df['Finalweight'] = df.apply(lambda x: x.Weight if (x.Percentile>0.7) or (x.Percentile>0.5 and x.max_percentile>0.7) else 0, axis=1) 

Out[1041]: 
     Date Stock Weight Percentile Finalweight max_percentile 
0 2000-01-01 Apple 0.010  0.75  0.010   0.75 
1 2000-01-01  IBM 0.011  0.40  0.000   0.40 
2 2000-01-01 Google 0.012  0.45  0.000   0.45 
3 2000-01-01 Nokia 0.022  0.81  0.022   0.81 
4 2000-02-01 Apple 0.014  0.56  0.014   0.75 
5 2000-02-01 Google 0.015  0.45  0.000   0.51 
6 2000-02-01 Nokia 0.016  0.55  0.016   0.81 
7 2000-03-01 Apple 0.020  0.52  0.020   0.75 
8 2000-03-01 Google 0.030  0.51  0.000   0.51 
9 2000-03-01 Nokia 0.040  0.57  0.040   0.81 

नोट

अपने उदाहरण डेटा की अंतिम पंक्ति में, नोकिया के प्रतिशतता 0.57 है, जबकि अपने परिणामों में यह हो जाता है 0.47। इस उदाहरण में, मैंने 0.57 का उपयोग किया ताकि आउटपुट आपकी अंतिम पंक्ति के लिए थोड़ा अलग हो।

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