Pandas rolling () с groupby () изменяет индекс странным образом

#python #pandas

#python #pandas

Вопрос:

Предположим, у меня есть DataFrame с MultiIndex таким:

 import pandas as pd
import numppy as np

iterables = [[1,2],['2011Q4','2012Q1','2012Q2','2012Q3','2012Q4','2013Q1','2013Q2','2013Q4']]

data = pd.DataFrame(np.random.random((16,1)), columns=['val'], 
                index=pd.MultiIndex.from_product(iterables,names=['id','date']))
  

Если я хочу создать задержку val , я бы сделал это:

 data['val_lag1'] = data.groupby(level=0)['val'].shift(1)
  

что дает

                 val  val_lag1
id date                      
1  2011Q4  0.215183       NaN
   2012Q1  0.929456  0.215183
   2012Q2  0.171601  0.929456
   2012Q3  0.387254  0.171601
   2012Q4  0.805295  0.387254
   2013Q1  0.592925  0.805295
   2013Q2  0.446619  0.592925
   2013Q4  0.962464  0.446619
2  2011Q4  0.723046       NaN
   2012Q1  0.840808  0.723046
   2012Q2  0.249003  0.840808
   2012Q3  0.306059  0.249003
   2012Q4  0.199025  0.306059
   2013Q1  0.815567  0.199025
   2013Q2  0.835140  0.815567
   2013Q4  0.322251  0.835140
  

Однако, когда я пытаюсь сделать по существу что-то очень похожее, rolling() это не работает, потому что оно дублирует один уровень индекса в процессе. То есть невозможно назначить

  data['val_ma4'] = data.groupby(level=0)['val'].rolling(4).mean()
  

как могло бы показаться естественным / очевидным, потому data.groupby(level=0)['val'].rolling(4).mean() что теперь имеет индекс третьего уровня:

 id  id  date  
1   1   2011Q4         NaN
        2012Q1         NaN
        2012Q2         NaN
        2012Q3    0.466110
        2012Q4    0.392576
        2013Q1    0.408187
        2013Q2    0.432501
        2013Q4    0.600802
2   2   2011Q4         NaN
        2012Q1         NaN
        2012Q2         NaN
        2012Q3    0.535583
        2012Q4    0.463489
        2013Q1    0.639357
        2013Q2    0.683905
        2013Q4    0.686587
Name: val, dtype: float64
  

Я могу избавиться от дополнительного уровня индекса, но почему он появляется и почему я должен это делать? Для меня не имеет смысла, что я должен это делать:

 xx = data.groupby(level=0)['val'].rolling(4).mean()
data['val_ma4'] = xx.unstack().groupby(level=0).mean().stack()
  

Комментарии:

1. Быстрый поиск в Google показывает, что это ошибка с 2016 года. И предложения показывают, как использовать apply .

Ответ №1:

В этом случае вам нужно использовать apply() :

 data['val_ma4'] = data.groupby(level=0)['val'].apply(lambda x: x.rolling(4).mean())
  

И вы достигаете желаемого результата:

                 val  val_lag1   val_ma4
id date                                
1  2011Q4  0.071332       NaN       NaN
   2012Q1  0.738045  0.071332       NaN
   2012Q2  0.578402  0.738045       NaN
   2012Q3  0.670338  0.578402  0.514529
   2012Q4  0.595443  0.670338  0.645557
   2013Q1  0.389000  0.595443  0.558296
   2013Q2  0.632672  0.389000  0.571863
   2013Q4  0.031375  0.632672  0.412123
2  2011Q4  0.860161       NaN       NaN
   2012Q1  0.337713  0.860161       NaN
   2012Q2  0.480819  0.337713       NaN
   2012Q3  0.167317  0.480819  0.461502
   2012Q4  0.650774  0.167317  0.409156
   2013Q1  0.197799  0.650774  0.374178
   2013Q2  0.417418  0.197799  0.358327
   2013Q4  0.705662  0.417418  0.492913
  

Комментарии:

1. Извините, я, наверное, не понял в своем вопросе, что скользящее среднее должно быть вычислено для каждой группы. Таким образом, для id=2 значений, связанных с 2011Q4 through 2012Q2 , должно отсутствовать

2. Я соответствующим образом обновил свой ответ, спасибо за разъяснение!