Search code examples
pythonpandasdataframerolling-average

Moving average in a pandas dataframe on valid values (non empty rows)


I have a df like this:

                    a001         a002         a003         a004         a005  
time_axis                                                                     
2017-02-07            1          NaN          NaN          NaN          NaN   
2017-02-14          NaN          NaN          NaN          NaN          NaN   
2017-03-20          NaN          NaN            2          NaN          NaN   
2017-04-03          NaN            3          NaN          NaN          NaN   
2017-05-15          NaN          NaN          NaN          NaN          NaN   
2017-06-05          NaN          NaN          NaN          NaN          NaN   
2017-07-10          NaN            6          NaN          NaN          NaN   
2017-07-17            4          NaN          NaN          NaN          NaN   
2017-07-24          NaN          NaN          NaN            1          NaN   
2017-08-07          NaN          NaN          NaN          NaN          NaN   
2017-08-14          NaN          NaN          NaN          NaN          NaN   
2017-08-28          NaN          NaN          NaN          NaN            5

And I would like to make a rolling mean for each row on the previous 3 valid values(not empty rows) and save in another df:

                  last_3           
time_axis                                                                     
2017-02-07            1   # still there is only a row          
2017-02-14            1   # only a valid value(in the first row) -> average is the value itself          
2017-03-20          1.5   # average on the previous rows (only 2 rows contain value-> (2+1)/2            
2017-04-03            2   # average on the previous rows with non-NaN values(2017-02-14 excluded) (2+3+1)/3            
2017-05-15            2   # Same reason as the previous row         
2017-06-05            2   # Same reason          
2017-07-10          3.6   # Now the considered values are:2,3,6          
2017-07-17          4.3   # considered values: 4,6,3          
2017-07-24          3.6   # considered values: 1,4,6             
2017-08-07          3.6   # no new values in this row, so again 1,4,6             
2017-08-14          3.6   # same reason            
2017-08-28          3.3   # now the considered values are: 5,1,4       

I was trying deleting the empty rows in the first dataframe and then apply rolling and mean, but I think it is the wrong approach(df1 in my example already exist):

df2 = df.dropna(how='all')
df1['last_3'] = df2.mean(axis=1).rolling(window=3, min_periods=3).mean()

Solution

  • I think you need:

    df2 = df.dropna(how='all')
    df['last_3'] = df2.mean(axis=1).rolling(window=3, min_periods=1).mean()
    df['last_3'] = df['last_3'].ffill()
    print (df)
                a001  a002  a003  a004  a005    last_3
    2017-02-07   1.0   NaN   NaN   NaN   NaN  1.000000
    2017-02-14   NaN   NaN   NaN   NaN   NaN  1.000000
    2017-03-20   NaN   NaN   2.0   NaN   NaN  1.500000
    2017-04-03   NaN   3.0   NaN   NaN   NaN  2.000000
    2017-05-15   NaN   NaN   NaN   NaN   NaN  2.000000
    2017-06-05   NaN   NaN   NaN   NaN   NaN  2.000000
    2017-07-10   NaN   6.0   NaN   NaN   NaN  3.666667
    2017-07-17   4.0   NaN   NaN   NaN   NaN  4.333333
    2017-07-24   NaN   NaN   NaN   1.0   NaN  3.666667
    2017-08-07   NaN   NaN   NaN   NaN   NaN  3.666667
    2017-08-14   NaN   NaN   NaN   NaN   NaN  3.666667
    2017-08-28   NaN   NaN   NaN   NaN   5.0  3.333333