2015-08-10 9 views
6

Ho il seguente dataframe:più recente valore max/min

date   value 
2014-01-20 10 
2014-01-21 12 
2014-01-22 13 
2014-01-23 9 
2014-01-24 7 
2014-01-25 12 
2014-01-26 11 

ho bisogno di essere in grado di tenere traccia di quando l'ultimo valore massimo e minimo si è verificato all'interno di una specifica finestra di rotolamento. Per esempio, se dovessi usare un periodo finestra di rotolamento 5, allora avrei bisogno di un output simile al seguente:

date   value rolling_max_date rolling_min_date 
2014-01-20 10  2014-01-20   2014-01-20 
2014-01-21 12  2014-01-21   2014-01-20 
2014-01-22 13  2014-01-22   2014-01-20 
2014-01-23 9  2014-01-22   2014-01-23 
2014-01-24 7  2014-01-22   2014-01-24 
2014-01-25 12  2014-01-22   2014-01-24 
2014-01-26 11  2014-01-25   2014-01-24 

Tutto questo dimostra è, qual è la data dell'ultima valore massimo e minimo all'interno della laminazione finestra. So che i panda hanno rolling_min e rolling_max, ma non sono sicuro di come tenere traccia dell'indice/data di quando il max/min più recente si è verificato all'interno della finestra.

risposta

4

C'è una più generale rolling_apply dove è possibile fornire la propria funzione. Tuttavia, le funzioni personalizzate ricevono le finestre come matrici, non come dataframes, quindi le informazioni dell'indice non sono disponibili (quindi non è possibile utilizzare idxmin/max).

Ma Proviamo a raggiungere questo obiettivo in due fasi:

In [41]: df = df.set_index('date') 
In [42]: pd.rolling_apply(df, window=5, func=lambda x: x.argmin(), min_periods=1) 
Out[42]: 
      value 
date 
2014-01-20  0 
2014-01-21  0 
2014-01-22  0 
2014-01-23  3 
2014-01-24  4 
2014-01-25  3 
2014-01-26  2 

Questo vi dà l'indice nella finestra in cui si trova il minimo. Ma questo indice è per quella particolare finestra e non per l'intero dataframe. Aggiungiamo quindi l'inizio della finestra, e quindi utilizzare questa posizione intero per recuperare l'indice corretto percorsi dell'indice:

In [45]: ilocs_window = pd.rolling_apply(df, window=5, func=lambda x: x.argmin(), min_periods=1) 

In [46]: ilocs = ilocs_window['value'] + ([0, 0, 0, 0] + range(len(ilocs_window)-4)) 

In [47]: ilocs 
Out[47]: 
date 
2014-01-20 0 
2014-01-21 0 
2014-01-22 0 
2014-01-23 3 
2014-01-24 4 
2014-01-25 4 
2014-01-26 4 
Name: value, dtype: float64 

In [48]: df.index.take(ilocs) 
Out[48]: 
Index([u'2014-01-20', u'2014-01-20', u'2014-01-20', u'2014-01-23', 
     u'2014-01-24', u'2014-01-24', u'2014-01-24'], 
     dtype='object', name=u'date') 

In [49]: df['rolling_min_date'] = df.index.take(ilocs) 

In [50]: df 
Out[50]: 
      value rolling_min_date 
date 
2014-01-20  10  2014-01-20 
2014-01-21  12  2014-01-20 
2014-01-22  13  2014-01-20 
2014-01-23  9  2014-01-23 
2014-01-24  7  2014-01-24 
2014-01-25  12  2014-01-24 
2014-01-26  11  2014-01-24 

Lo stesso può essere fatto per la massima:

ilocs_window = pd.rolling_apply(df, window=5, func=lambda x: x.argmax(), min_periods=1) 
ilocs = ilocs_window['value'] + ([0, 0, 0, 0] + range(len(ilocs_window)-4)) 
df['rolling_max_date'] = df.index.take(ilocs) 
1

Ecco una soluzione.

import pandas as pd 
import numpy as np 

# sample data 
# =============================================== 
np.random.seed(0) 
df = pd.DataFrame(np.random.randint(1,30,20), index=pd.date_range('2015-01-01', periods=20, freq='D'), columns=['value']) 
df 

      value 
2015-01-01  13 
2015-01-02  16 
2015-01-03  22 
2015-01-04  1 
2015-01-05  4 
2015-01-06  28 
2015-01-07  4 
2015-01-08  8 
2015-01-09  10 
2015-01-10  20 
2015-01-11  22 
2015-01-12  19 
2015-01-13  5 
2015-01-14  24 
2015-01-15  7 
2015-01-16  25 
2015-01-17  25 
2015-01-18  13 
2015-01-19  27 
2015-01-20  2 

# processing 
# ========================================== 
# your cumstom function to track on max/min value/date 
def track_minmax(df): 
    return pd.Series({'current_date': df.index[-1], 'rolling_max_val': df['value'].max(), 'rolling_max_date': df['value'].idxmax(), 'rolling_min_val': df['value'].min(), 'rolling_min_date': df['value'].idxmin()}) 

window = 5 
# use list comprehension to do the for loop 
pd.DataFrame([track_minmax(df.iloc[i:i+window]) for i in range(len(df)-window+1)]).set_index('current_date').reindex(df.index) 

      rolling_max_date rolling_max_val rolling_min_date rolling_min_val 
2015-01-01    NaT    NaN    NaT    NaN 
2015-01-02    NaT    NaN    NaT    NaN 
2015-01-03    NaT    NaN    NaT    NaN 
2015-01-04    NaT    NaN    NaT    NaN 
2015-01-05  2015-01-03    22  2015-01-04    1 
2015-01-06  2015-01-06    28  2015-01-04    1 
2015-01-07  2015-01-06    28  2015-01-04    1 
2015-01-08  2015-01-06    28  2015-01-04    1 
2015-01-09  2015-01-06    28  2015-01-05    4 
2015-01-10  2015-01-06    28  2015-01-07    4 
2015-01-11  2015-01-11    22  2015-01-07    4 
2015-01-12  2015-01-11    22  2015-01-08    8 
2015-01-13  2015-01-11    22  2015-01-13    5 
2015-01-14  2015-01-14    24  2015-01-13    5 
2015-01-15  2015-01-14    24  2015-01-13    5 
2015-01-16  2015-01-16    25  2015-01-13    5 
2015-01-17  2015-01-16    25  2015-01-13    5 
2015-01-18  2015-01-16    25  2015-01-15    7 
2015-01-19  2015-01-19    27  2015-01-15    7 
2015-01-20  2015-01-19    27  2015-01-20    2 
Problemi correlati