क्या पंडों में डेटाफ़्रेम में पिछली पंक्ति मूल्य का उपयोग करने का एक तरीका है। लागू होने में पिछले मूल्य की भी गणना की जाती है?


97

मेरे पास निम्नलिखित डेटाफ़्रेम हैं:

 Index_Date    A    B    C    D
 ===============================
 2015-01-31    10   10   Nan  10
 2015-02-01     2    3   Nan  22 
 2015-02-02    10   60   Nan  280
 2015-02-03    10   100   Nan  250

आवश्यक है:

 Index_Date    A    B    C    D
 ===============================
 2015-01-31    10   10   10   10
 2015-02-01     2    3   23   22
 2015-02-02    10   60   290  280
 2015-02-03    10   100  3000 250

Column Cके 2015-01-31द्वारा लिया गया valueहै D

तब मैं उपयोग करने की आवश्यकता valueके Cलिए 2015-01-31और गुणा valueके Aपर 2015-02-01और जोड़ने B

मैंने एक प्रयास किया है applyऔर इसके द्वारा एक shiftप्रयोग if elseएक महत्वपूर्ण त्रुटि देता है।


डेटाफ़्रेम में आपकी अंतिम पंक्तियाँ स्तंभों के लिए भिन्न क्यों हैं Aऔर B?
एंटोन प्रोतोपोपोव

@ एटन ने अभी इसके लिए माफी मांगी है।
ctrl-alt-delete

स्तंभ Aऔर स्तंभ में अगली पंक्ति का मूल्य क्या है D?
जेज़रेल

7
यह अच्छा प्रश्न है। मुझे एक वेक्टर समाधान की समान आवश्यकता है। यह अच्छा होगा यदि पंडों ने उस संस्करण को प्रदान किया apply()जहां उपयोगकर्ता का फ़ंक्शन पिछली पंक्ति से एक या अधिक मानों को अपनी गणना के भाग के रूप में एक्सेस करने में सक्षम है या कम से कम एक मान लौटाता है जो अगले पुनरावृत्ति पर 'स्वयं' में पारित हो जाता है। क्या यह लूप की तुलना में कुछ दक्षता हासिल करने की अनुमति नहीं देगा?
बिल

@ बिल, आप इस उत्तर में दिलचस्पी ले सकते हैं जो मैंने अभी जोड़ा है, numbaअक्सर यहाँ एक अच्छा विकल्प है।
जेपी

जवाबों:


68

सबसे पहले, व्युत्पन्न मूल्य बनाएँ:

df.loc[0, 'C'] = df.loc[0, 'D']

फिर शेष पंक्तियों के माध्यम से पुनरावृति करें और परिकलित मान भरें:

for i in range(1, len(df)):
    df.loc[i, 'C'] = df.loc[i-1, 'C'] * df.loc[i, 'A'] + df.loc[i, 'B']


  Index_Date   A   B    C    D
0 2015-01-31  10  10   10   10
1 2015-02-01   2   3   23   22
2 2015-02-02  10  60  290  280

42
वहाँ लंड के बिना ऐसा करने के लिए पांडा में एक समारोह है?
ctrl-alt-delete

1
गणना की पुनरावृत्ति प्रकृति जहां इनपुट पिछले चरणों के परिणामों पर निर्भर करते हैं, वेक्टरकरण को जटिल बनाता है। आप शायद applyएक फ़ंक्शन के साथ उपयोग कर सकते हैं जो लूप के समान गणना करता है, लेकिन पर्दे के पीछे यह भी एक लूप होगा। pandas.pydata.org/pandas-docs/version/0.17.1/generated/…
Stefan

अगर मैं इस लूप का उपयोग करता हूं और एक मर्ज किए गए डेटाफ्रेम पर गणना करता हूं और यह एक नैनो पाता है तो यह काम करता है लेकिन केवल नैनो के साथ पंक्ति में। कोई त्रुटि नहीं फेंकी जाती है, यदि मैं एक भरण का प्रयास करता हूं तो मुझे गुण प्राप्त होता है
ctrl-alt-delete

क्या आप के अलावा अन्य स्तंभों में गुम मूल्यों का मतलब है C?
स्टीफन

हां आपका हल ठीक है। मैं सिर्फ यह सुनिश्चित करता हूं कि मैं लूप से पहले डेटाफ्रेम में नैन्स भर दूं।
ctrl-alt-delete

43

संख्याओं के एक कॉलम को देखते हुए:

lst = []
cols = ['A']
for a in range(100, 105):
    lst.append([a])
df = pd.DataFrame(lst, columns=cols, index=range(5))
df

    A
0   100
1   101
2   102
3   103
4   104

आप पिछली पंक्ति को शिफ्ट के साथ संदर्भित कर सकते हैं:

df['Change'] = df.A - df.A.shift(1)
df

    A   Change
0   100 NaN
1   101 1.0
2   102 1.0
3   103 1.0
4   104 1.0

10
यह इस स्थिति में मदद नहीं करेगा क्योंकि पिछली पंक्ति से मूल्य की शुरुआत में ज्ञात नहीं है। इसे प्रत्येक पुनरावृत्ति की गणना करनी होती है और फिर अगले पुनरावृत्ति में उपयोग किया जाता है।
बिल

6
मैं अब भी इस जवाब के लिए आभारी हूं क्योंकि मैं इस मामले में लड़खड़ा गया था, एक ऐसे मामले की तलाश में था, जहां मुझे पिछली पंक्ति का मूल्य पता हो। तो धन्यवाद @kztd
केविन पाउली

28

numba

पुनरावर्ती गणनाओं के लिए numba, जो सदिश नहीं हैं , जो जेआईटी-संकलन का उपयोग करता है और निचले स्तर की वस्तुओं के साथ काम करता है, अक्सर बड़े प्रदर्शन में सुधार होता है। आपको केवल एक नियमित forलूप को परिभाषित करने और डेकोरेटर का उपयोग करने की आवश्यकता है @njitया (पुराने संस्करणों के लिए) @jit(nopython=True):

एक उचित आकार के डेटाफ्रेम के लिए, यह एक नियमित forलूप बनाम ~ 30x प्रदर्शन सुधार देता है :

from numba import jit

@jit(nopython=True)
def calculator_nb(a, b, d):
    res = np.empty(d.shape)
    res[0] = d[0]
    for i in range(1, res.shape[0]):
        res[i] = res[i-1] * a[i] + b[i]
    return res

df['C'] = calculator_nb(*df[list('ABD')].values.T)

n = 10**5
df = pd.concat([df]*n, ignore_index=True)

# benchmarking on Python 3.6.0, Pandas 0.19.2, NumPy 1.11.3, Numba 0.30.1
# calculator() is same as calculator_nb() but without @jit decorator
%timeit calculator_nb(*df[list('ABD')].values.T)  # 14.1 ms per loop
%timeit calculator(*df[list('ABD')].values.T)     # 444 ms per loop

1
यह अद्भुत है! मैंने अपने कार्य को तेज कर दिया है, जो पिछले मूल्यों से मूल्यों को गिनता है। धन्यवाद!
आर्टेम मलिकोव

@jit(nopython=True)ज्यूपिटर-नोटबुक में मैं कैसे उपयोग कर सकता हूं ?
sergzemsk

1
@sergzemsk, जैसा आपने लिखा है (और मेरे जवाब में), इसे डेकोरेटर कहा जाता है । नोट सुन्न के बाद के संस्करण शॉर्टकट का समर्थन करते हैं @njit
jpp

@jpp मेरे पास ifहालत है इसलिए यह सुधार विफल रहा। मुझे एक त्रुटि मिली "TypingError: Nopython Mode पाइपलाइन में विफल (step: nopython frontend)"
sergzemsk

@sergzemsk, मेरा सुझाव है कि आप एक नया प्रश्न पूछें, मेरे लिए यह स्पष्ट नहीं है कि ifकथन कहाँ बैठता है, यह सुन्न द्वारा सदिश क्यों नहीं किया जा रहा है।
jpp

23

खस्ता सरणियों पर पुनरावर्ती कार्य को लागू करना वर्तमान उत्तर की तुलना में तेज होगा।

df = pd.DataFrame(np.repeat(np.arange(2, 6),3).reshape(4,3), columns=['A', 'B', 'D'])
new = [df.D.values[0]]
for i in range(1, len(df.index)):
    new.append(new[i-1]*df.A.values[i]+df.B.values[i])
df['C'] = new

उत्पादन

      A  B  D    C
   0  1  1  1    1
   1  2  2  2    4
   2  3  3  3   15
   3  4  4  4   64
   4  5  5  5  325

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

यह काम मेरे लिए भी सही है, धन्यवाद। मैं iterrows, itertuples, apply इत्यादि के कई रूपों से जूझ रहा था और यह समझने और प्रदर्शन करने में आसान लगता है।
चैम

10

हालाँकि इस प्रश्न को पूछे जाने में कुछ समय हो गया है, मैं अपना उत्तर इस उम्मीद से दूंगा कि यह किसी की मदद करता है।

अस्वीकरण: मुझे पता है कि यह समाधान मानक नहीं है , लेकिन मुझे लगता है कि यह अच्छी तरह से काम करता है।

import pandas as pd
import numpy as np

data = np.array([[10, 2, 10, 10],
                 [10, 3, 60, 100],
                 [np.nan] * 4,
                 [10, 22, 280, 250]]).T
idx = pd.date_range('20150131', end='20150203')
df = pd.DataFrame(data=data, columns=list('ABCD'), index=idx)
df
               A    B     C    D
 =================================
 2015-01-31    10   10    NaN  10
 2015-02-01    2    3     NaN  22 
 2015-02-02    10   60    NaN  280
 2015-02-03    10   100   NaN  250

def calculate(mul, add):
    global value
    value = value * mul + add
    return value

value = df.loc['2015-01-31', 'D']
df.loc['2015-01-31', 'C'] = value
df.loc['2015-02-01':, 'C'] = df.loc['2015-02-01':].apply(lambda row: calculate(*row[['A', 'B']]), axis=1)
df
               A    B     C     D
 =================================
 2015-01-31    10   10    10    10
 2015-02-01    2    3     23    22 
 2015-02-02    10   60    290   280
 2015-02-03    10   100   3000  250

इसलिए मूल रूप से हम applyपांडा से और एक वैश्विक वैरिएबल की मदद लेते हैं जो पिछले गणना मूल्य का ट्रैक रखता है।


एक forलूप के साथ समय की तुलना :

data = np.random.random(size=(1000, 4))
idx = pd.date_range('20150131', end='20171026')
df = pd.DataFrame(data=data, columns=list('ABCD'), index=idx)
df.C = np.nan

df.loc['2015-01-31', 'C'] = df.loc['2015-01-31', 'D']

%%timeit
for i in df.loc['2015-02-01':].index.date:
    df.loc[i, 'C'] = df.loc[(i - pd.DateOffset(days=1)).date(), 'C'] * df.loc[i, 'A'] + df.loc[i, 'B']

3.2 एस d 114 एमएस प्रति लूप (मतलब dev एसटीडी। 7 रन का। 1 लूप प्रत्येक)

data = np.random.random(size=(1000, 4))
idx = pd.date_range('20150131', end='20171026')
df = pd.DataFrame(data=data, columns=list('ABCD'), index=idx)
df.C = np.nan

def calculate(mul, add):
    global value
    value = value * mul + add
    return value

value = df.loc['2015-01-31', 'D']
df.loc['2015-01-31', 'C'] = value

%%timeit
df.loc['2015-02-01':, 'C'] = df.loc['2015-02-01':].apply(lambda row: calculate(*row[['A', 'B']]), axis=1)

1.82 s 82 64.4 एमएस प्रति लूप (मतलब dev एसटीडी। 7 रन का देवता, 1 लूप प्रत्येक)

तो औसतन 0.57 गुना तेज।


0

सामान्य तौर पर, एक स्पष्ट लूप से बचने के लिए कुंजी पंक्ति में डेटाफ्रेम के 2 उदाहरणों को मिलाना (मर्ज करना) होगा।

तब आपके पास r और r-1 की पंक्तियों वाली एक बड़ी डेटाफ़्रेम होगी, जहाँ से आप df.apply () फ़ंक्शन कर सकते थे।

हालांकि बड़े डेटासेट बनाने के ओवरहेड समानांतर प्रसंस्करण के लाभों की भरपाई कर सकते हैं ...

एचटीएच मार्टिन

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