2017-04-30 6 views
4

Ich versuche, die Spaltenwerte eines Pandas Datenrahmens "rekursiv" zu berechnen.Berechne DataFrame Werte rekursiv

Angenommen, es gibt Daten für zwei verschiedene Tage mit jeweils 10 Beobachtungen und Sie möchten eine Variable r berechnen, in der nur der erste Wert von r angegeben ist (an jedem Tag) und Sie die verbleibenden 2 * 9 Einträge berechnen möchten jeder nachfolgende Wert hängt von der vorherigen Eingabe von r und einer zusätzlichen 'zeitgleichen' Variablen 'x' ab.

enter image description here

Das erste Problem ist, dass ich die Berechnungen für jeden Tag ausführen möchten individuell dh würde Ich mag die pandas.groupby() Funktion für alle meine Berechnungen verwenden ... aber wenn ich versuche, die Daten der Teilmenge und verwenden Sie die shift(1) Funktion, ich nur bekommen "NaN" Einträge

data.groupby(data.index)['r'] = ((1+data.groupby(data.index)['x']*0.25) * (1+data.groupby(data.index)['r'].shift(1))) 

für meinen zweiten Ansatz ich eine for-Schleife verwendet, um den Index zu iterieren (Termine):

for i in range(2,21): 
    data[data['rank'] == i]['r'] = ((1+data[data['rank'] == i]['x']*0.25) * (1+data[data['rank'] == i]['r'].shift(1)) 

aber immer noch, das funktioniert nicht für mich. Gibt es eine Möglichkeit, eine solche Berechnung auf DataFrames durchzuführen? Vielleicht etwas wie Rollen anwenden?

Daten:

df = pd.DataFrame({ 
    'rank' : [1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10], 
    'x' : [0.00275,0.00285,0.0031,0.0036,0.0043,0.0052,0.0063,0.00755,0.00895,0.0105,0.0027,0.00285,0.0031,0.00355,0.00425,0.0051,0.00615,0.00735,0.00875,0.0103], 
    'r' : [0.00158,'NaN','NaN','NaN','NaN','NaN','NaN','NaN','NaN','NaN',0.001485,'NaN','NaN','NaN','NaN','NaN','NaN','NaN','NaN','NaN'] 
    },index=['2014-01-02', '2014-01-02', '2014-01-02', '2014-01-02', 
      '2014-01-02', '2014-01-02', '2014-01-02', '2014-01-02', 
      '2014-01-02', '2014-01-02', '2014-01-03', '2014-01-03', 
      '2014-01-03', '2014-01-03', '2014-01-03', '2014-01-03', 
      '2014-01-03', '2014-01-03', '2014-01-03', '2014-01-03']) 
+0

Es gibt eine Reihe von Fragen zu diesem Thema, aber es ist Derzeit gibt es keine schnelle Möglichkeit, diese Art von Rekursionsrelationsberechnungen in Pandas durchzuführen. Sie müssen Schleife. Es gibt [ein offenes Problem] (https://github.com/pandas-dev/pandas/issues/4567) darüber. – BrenBarn

Antwort

3

Ihre Rollen zu tun anwenden, können Sie pandas.groupby().apply() verwenden. Innerhalb der Anwendung können Sie eine Schleife verwenden, um die Berechnungen pro Gruppe durchzuführen. Die innere Schleife könnte möglicherweise auch mit scipy.lfilter gemacht werden, aber ich konnte die genaue Formel nicht verstehen, nach der Sie suchen, also habe ich nur diesen Teil geflügelt.

Code:

def rolling_apply(group): 
    r = [group.r.iloc[0]] 
    for x in group.x: 
     r.append((1 + r[-1]) * (1 + x * 0.25)) 
    group.r = r[1:] 
    return group 

df['R'] = df.groupby(df.index).apply(rolling_apply).r 

Ergebnisse:

    r rank  x   R 
2014-01-02 0.00158  1 0.00275 1.002269 
2014-01-02  NaN  2 0.00285 2.003695 
2014-01-02  NaN  3 0.00310 3.006023 
2014-01-02  NaN  4 0.00360 4.009628 
2014-01-02  NaN  5 0.00430 5.015014 
2014-01-02  NaN  6 0.00520 6.022833 
2014-01-02  NaN  7 0.00630 7.033894 
2014-01-02  NaN  8 0.00755 8.049058 
2014-01-02  NaN  9 0.00895 9.069306 
2014-01-02  NaN 10 0.01050 10.095737 
2014-01-03 0.001485  1 0.00270 1.002161 
2014-01-03  NaN  2 0.00285 2.003588 
2014-01-03  NaN  3 0.00310 3.005915 
2014-01-03  NaN  4 0.00355 4.009471 
2014-01-03  NaN  5 0.00425 5.014793 
2014-01-03  NaN  6 0.00510 6.022462 
2014-01-03  NaN  7 0.00615 7.033259 
2014-01-03  NaN  8 0.00735 8.048020 
2014-01-03  NaN  9 0.00875 9.067813 
2014-01-03  NaN 10 0.01030 10.093737 

Testdaten:

df = pd.DataFrame({ 
    'rank': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 
    'x': [0.00275, 0.00285, 0.0031, 0.0036, 0.0043, 0.0052, 0.0063, 0.00755, 
      0.00895, 0.0105, 0.0027, 0.00285, 0.0031, 0.00355, 0.00425, 
      0.0051, 0.00615, 0.00735, 0.00875, 0.0103], 
    'r': [0.00158, 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 
      'NaN', 0.001485, 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 
      'NaN', 'NaN'] 
}, index=['2014-01-02', '2014-01-02', '2014-01-02', '2014-01-02', 
      '2014-01-02', '2014-01-02', '2014-01-02', '2014-01-02', 
      '2014-01-02', '2014-01-02', '2014-01-03', '2014-01-03', 
      '2014-01-03', '2014-01-03', '2014-01-03', '2014-01-03', 
      '2014-01-03', '2014-01-03', '2014-01-03', '2014-01-03']) 

Aktualisierung:

Nun, da die tatsächliche Rekursivgleichung erwünscht ist bekannt, hier ist ein Update für die Funktion anwenden:

def rolling_apply(group): 
    r = [group.r.iloc[0]] 
    for x in group.x[:-1]: 
     r.append((1 + r[-1]) * (1 + x * 0.25) - 1) 
    group.r = r 
    return group 

df.r = df.groupby(df.index).apply(rolling_apply).r 
+0

Wäre es auch möglich, dies als Lambda-Funktion zu tun und anzuwenden? Ich bin nur Neugierig. – Moondra

+1

@ Moondra, die OP-Berechnung ist ein bisschen beteiligt, und selbst wenn es in einem Lambda ausdrückbar wäre, würde ich vorschlagen, es wäre schlechte Codierung Stil. –

0

Stephen Rauchs Antwort war sehr hilfreich. Da ich nach einer Spalte "r" suchte, wo nur die aufeinanderfolgenden Werte jedes Tages berechnet werden, während die Anfangswerte (0,00158, 0,001485) unverändert bleiben, werde ich die endgültige Lösung zusätzlich posten (nur für den Fall, dass jemand ein ähnliches Problem hat). In Stephen Rauchs Lösung gehört der Wert von R [0] zu r [1] usw. Daher muss man die Daten für alle "Ränge" mit Ausnahme von 1 verschieben.

Testdaten

df = pd.DataFrame({ 
'rank': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 
'x': [0.00275, 0.00285, 0.0031, 0.0036, 0.0043, 0.0052, 0.0063, 0.00755, 
     0.00895, 0.0105, 0.0027, 0.00285, 0.0031, 0.00355, 0.00425, 
     0.0051, 0.00615, 0.00735, 0.00875, 0.0103], 
'r': [0.00158, 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 
     'NaN', 0.001485, 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 
     'NaN', 'NaN'] }, index=['2014-01-02', '2014-01-02', '2014-01-02', '2014-01-02', 
     '2014-01-02', '2014-01-02', '2014-01-02', '2014-01-02', 
     '2014-01-02', '2014-01-02', '2014-01-03', '2014-01-03', 
     '2014-01-03', '2014-01-03', '2014-01-03', '2014-01-03', 
     '2014-01-03', '2014-01-03', '2014-01-03', '2014-01-03']) 

-Code

def rolling_apply(group): 
    r = [group.r.iloc[0]] 
    for x in group.x: 
     r.append((1 + r[-1]) * (1 + x * 0.25) -1) 
    group.r = r[1:] 
    return group 

df['R'] = df.groupby(df.index).apply(rolling_apply).r 

df['r'] = np.where(df['rank']==1,df['r'],df['R'].shift(1)) 

df = df.drop('R',1) 

Ergebnis

     r rank  x 
2014-01-02  0.00158  1 0.00275 
2014-01-02 0.00226859  2 0.00285 
2014-01-02 0.0029827  3 0.00310 
2014-01-02 0.00376001  4 0.00360 
2014-01-02 0.0046634  5 0.00430 
2014-01-02 0.00574341  6 0.00520 
2014-01-02 0.00705088  7 0.00630 
2014-01-02 0.00863698  8 0.00755 
2014-01-02 0.0105408  9 0.00895 
2014-01-02 0.0128019 10 0.01050 
2014-01-03 0.001485  1 0.00270 
2014-01-03 0.002161  2 0.00285 
2014-01-03 0.00287504  3 0.00310 
2014-01-03 0.00365227  4 0.00355 
2014-01-03 0.00454301  5 0.00425 
2014-01-03 0.00561034  6 0.00510 
2014-01-03 0.00689249  7 0.00615 
2014-01-03 0.00844059  8 0.00735 
2014-01-03 0.0102936  9 0.00875 
2014-01-03 0.0125036 10 0.01030