2016-06-26 10 views
7

Ich habe einen ziemlich anspruchsvollen Vorhersage-Code mit über 20 Spalten und Millionen von Daten pro Spalte mit wls. Jetzt benutze ich Iterrow, um Daten zu durchlaufen, und dann basierend auf diesen Daten und Werten in diesen Daten verschiedene Größen von Daten für die Berechnung zu extrahieren. es dauert Stunden in meiner Produktion laufen, ich den Code in das folgende vereinfachen:Wie vektorisieren Pandas Berechnung, die auf letzten x Zeilen von Daten basiert ist

import pandas as pd 
import numpy as np 
from datetime import timedelta 

df=pd.DataFrame(np.random.randn(1000,2), columns=list('AB')) 
df['dte'] = pd.date_range('9/1/2014', periods=1000, freq='D') 

def calculateC(A, dte): 
    if A>0: #based on values has different cutoff length for trend prediction 
     depth=10 
    else: 
     depth=20 
    lastyear=(dte-timedelta(days=365)) 
    df2=df[df.dte<lastyear].head(depth) #use last year same date data for basis of prediction 
    return df2.B.mean() #uses WLS in my model but for simplification replace with mean 

for index, row in df.iterrows(): 
    if index>365: 
     df.loc[index,'C']=calculateC(row.A, row.dte) 

ich gelesen, dass iterrow die Hauptursache ist, weil es keine wirksame Methode ist Pandas zu verwenden, und ich sollte Vektor Methoden. Jedoch kann ich nicht in der Lage sein, basierend auf Bedingungen (Daten, unterschiedliche Länge und Wertebereich) einen Weg zum Vektor zu finden. Gibt es einen Weg?

+0

Ich weiß, das ist eine alte Frage, aber für was es sich lohnt 'itituples()' ist merklich schneller als 'iterrows()'. – shadowtalker

Antwort

0

Ich würde versuchen, pandas.DataFrame.apply (func, Achse = 1)

def calculateC2(row): 
    if row.name >365: # row.name is the index of the row 
     if row.A >0: #based on values has different cutoff length for trend prediction 
      depth=10 
     else: 
      depth=20 
     lastyear=(row.dte-timedelta(days=365)) 
     df2=df[df.dte<lastyear].B.head(depth) #use last year same date data for basis of prediction 
     print row.name,np.mean(df2) #uses WLS in my model but for simplification replace with mean 

df.apply(calculateC2,axis=1) 
2

Ich habe gute und schlechte Nachrichten. Die gute Nachricht ist, dass ich etwas vektorisiert habe, das ungefähr 300x schneller ist, aber die schlechte Nachricht ist, dass ich deine Ergebnisse nicht ganz replizieren kann. Aber ich denke, dass Sie in der Lage sein sollten, die hier beschriebenen Prinzipien zu verwenden, um Ihren Code erheblich zu beschleunigen, auch wenn dieser Code Ihre Ergebnisse im Moment nicht repliziert.

df['result'] = np.where(df['A'] > 0, 
         df.shift(365).rolling(10).B.mean(), 
         df.shift(365).rolling(20).B.mean()) 

Der zähe (langsam) Teil des Codes ist dies:

df2=df[df.dte<lastyear].head(depth) 

jedoch solange Ihre Termine sind alle 365 Tage auseinander, können Sie folgenden Code verwenden, die vektorisiert und viel schneller:

df.shift(365).rolling(10).B.mean() 

shift(365) ersetzt df.dte < lastyear und die rolling().mean() ersetzt head().mean(). Es wird viel schneller und weniger Speicher verbrauchen.

Und eigentlich, selbst wenn Ihre Daten nicht ganz regelmäßig sind, können Sie wahrscheinlich resample und diesen Weg zur Arbeit bekommen. Oder, etwas äquivalent, wenn Sie das Datum zu Ihrem Index machen, kann die Verschiebung dazu gebracht werden, basierend auf einer Häufigkeit statt auf Zeilen zu arbeiten (z. B. 365 Tage verschieben, auch wenn das nicht 365 Zeilen sind). Es wäre wahrscheinlich eine gute Idee, 'dte' hier unabhängig von Ihrem Index zu machen.

+0

Ich wäre skeptisch gegenüber Index-basierten Schichten, wenn ich mit Daten arbeite: http://infiniteundo.com/post/25326999628/falsehoods-programmers-believe-about-time – shadowtalker

+0

Ich stimme natürlich zu, daher mein Vorschlag zu mache das Datum zum Index ;-) Aber letztendlich hängt es von den Daten ab, ob eine Zeilenverschiebung oder Time-Shift sinnvoller ist. – JohnE

Verwandte Themen