2015-02-23 9 views
14

समस्या पर आधारितकी गणना नया मान मूल्य घटते

क्या मैं करना चाहता हूँ कदम-दर-कदम एक लगातार कम हो रही आधार आंकड़ा द्वारा एक Series में एक मूल्य को कम है।

मैं इस के लिए शब्दावली का यकीन नहीं है - मुझे लगता है कि था कि मैं cumsum और diff साथ कुछ कर सकते हैं लेकिन मुझे लगता है मैं अपने आप को वहाँ एक जंगली हंस का पीछा करने पर अग्रणी हूँ ...

कोड शुरू :

import pandas as pd 

ALLOWANCE = 100 
values = pd.Series([85, 10, 25, 30]) 

वांछित उत्पादन:

desired = pd.Series([0, 0, 20, 30]) 

दलील:

ALLOWANCE का एक आधार के साथ शुरू -, Series में प्रत्येक मान राशि शेष द्वारा कम हो जाता है के रूप में भत्ता ही है, इसलिए निम्न चरणों के होते हैं:

  • 100 के साथ शुरू , हम पूरी तरह से 85 निकाल सकते हैं तो यह 0 हो जाता है, अब हम 15ALLOWANCE
  • अगले मूल्य 10 है और हम अभी भी 15 availa है के रूप में छोड़ दिया है खून, तो यह 0 फिर से बन जाता है और हमारे पास 5 शेष है।
  • अगला मान 25 है - हमारे पास केवल 5 शेष है, इसलिए यह 20 बन गया है और अब हमारे पास कोई और भत्ता नहीं है।
  • अगला मान 30 है, और चूंकि कोई भत्ता नहीं है, इसलिए मान 30 के रूप में रहता है।
+0

मैं 'वैल्यू' वैरिएबल को 'व्यय' और' वांछित' चर 'में' ऋण 'में बदल दूंगा, जो' भत्ता 'के संयोजन में पाठक को समझता है कि आप पाठ को देखे बिना पूरा करने की कोशिश कर रहे हैं, imo। – mucaho

उत्तर

10

cumsum और diff के अपने प्रारंभिक विचार के बाद, आप लिख सकते हैं:

>>> (values.cumsum() - ALLOWANCE).clip_lower(0).diff().fillna(0) 
0  0 
1  0 
2 20 
3 30 
dtype: float64 

यह values शून्य से भत्ता के संचयी योग है।ऋणात्मक मान शून्यों पर फिसल जाते हैं (चूंकि हम संख्याओं की परवाह नहीं करते हैं जब तक कि हम अपने भत्ते को ओवरड्राउन नहीं करते हैं)। वहां से, आप अंतर की गणना कर सकते हैं।

हालांकि, अगर पहले मान भत्ता से अधिक हो सकता है, निम्नलिखित दो लाइन भिन्नता पसंद किया जाता है:

s = (values.cumsum() - ALLOWANCE).clip_lower(0) 
desired = s.diff().fillna(s) 

इस के साथ पहली NaN मूल्य भरता है "पहले मूल्य - भत्ता" मूल्य। तो इस मामले में जहां ALLOWANCE 75 तक कम हो गया है, यह desiredSeries([10, 10, 25, 30]) के रूप में लौटाता है।

+0

यह 'सीरीज़'>' आवंटन 'का पहला तत्व कहां संभालता प्रतीत नहीं होता है :( –

+0

@ जोन क्लेमेंट्स आपको केवल' .fillna (0) ' – EdChum

+0

@EdChum cant' को जोड़ना होगा - मुझे लगता है कि कार्स्टन के जवाब के समान उपयोग करने की आवश्यकता है, यदि श्रृंखला में पहला मान '85' रहता है, और 'आवंटन' 70 है, तो परिणाम' 0' है - जो गलत है - यह '15' –

1

यह एक while पाश के साथ काम करना चाहिए:

ii = 0 
while (ALLOWANCE > 0 and ii < len(values)): 
    if (ALLOWANCE > values[ii]): 
     ALLOWANCE -= values[ii] 
     values[ii] = 0 
    else: 
     values[ii] -= ALLOWANCE 
     ALLOWANCE = 0 
    ii += 1 
+2

धन्यवाद। हालांकि यह काम करेगा, मैं 'पांडा' में अन्य परिचालन करने की भी योजना बना रहा हूं - इसलिए यदि संभव हो तो मैं वास्तव में 'पांडा' आधारित समाधान के बाद हूं। –

5

यह शायद इसलिए performant नहीं है, लेकिन इस समय इस rolling_apply का उपयोग कर ऐसा करने का एक पांडा तरीका है:

In [53]: 

ALLOWANCE = 100 
def reduce(x): 
    global ALLOWANCE 
    # short circuit if we've already reached 0 
    if ALLOWANCE == 0: 
     return x 
    val = max(0, x - ALLOWANCE) 
    ALLOWANCE = max(0, ALLOWANCE - x) 
    return val 

pd.rolling_apply(values, window=1, func=reduce) 
Out[53]: 
0  0 
1  0 
2 20 
3 30 
dtype: float64 

या अधिक सरल:

In [58]: 

values.apply(reduce) 
Out[58]: 
0  0 
1  0 
2 20 
3 30 
dtype: int64 
+0

मेरे फ़ंक्शन को फिर से लिखने का एक बेहतर तरीका है, मैं एक अजगर विशेषज्ञ नहीं हूं, मैं सोच रहा था कि इसे जनरेटर का उपयोग करके फिर से लिखा जा सकता है लेकिन यह किसी कारण से काफी काम नहीं करता है। आदर्श रूप से अगर यह भत्ता पहले से ही 0 है और पारित मूल्य मान – EdChum

+0

पर वापस लौटाता है तो यह निश्चित रूप से मुझे सही दिशा की तरह दिखता है और मुझे कुछ विचार दिए गए हैं ... बहुत अधिक धन्यवाद - 'रोलिंग_प्ली पर पढ़ना ' –

8

cumsum और diff के साथ आपका विचार काम करता है। यह बहुत जटिल नहीं लग रहा है; सुनिश्चित नहीं है कि यहां तक ​​कि एक छोटा समाधान भी है। सबसे पहले, हम संचयी योग की गणना करते हैं, उस पर काम करते हैं, और फिर वापस जाते हैं (diffcumsum के व्यस्त कार्य को क्रमबद्ध करते हैं)।

import math 

c = values.cumsum() - ALLOWANCE 
# now we've got [-15, -5, 20, 50] 
c[c < 0] = 0 # negative values don't make sense here 

# (c - c.shift(1)) # <-- what I had first: diff by accident 

# it is important that we don't fill with 0, in case that the first 
# value is greater than ALLOWANCE 
c.diff().fillna(math.max(0, values[0] - ALLOWANCE)) 
संबंधित मुद्दे