I would use numpy product here. NAN will be a string when we copy/paste it into our from your sample, so I went ahead and replaced it with np.nan. From there you can replace NaN with 1, since it's a product if won't change the outcome, but will fulfill the rolling period requirement.
import pandas as pd
import numpy as np
df = pd.DataFrame({'month': ['1994-07',
'1994-08',
'1994-09',
'1994-10',
'1994-11',
'1995-07',
'1995-08'],
'A': [1, 5, 1, 1, 1, 1, 1],
'B': ['2', '2', '2', '2', 'NAN', '2', '2'],
'C': ['NAN', '3', '1', '3', '3', '2', '3'],
'D': ['NAN', '4', '1', '1', '1', '4', '4']})
(
df.replace('NAN',np.nan)
.set_index('month')
.fillna(1)
.rolling(5)
.apply(np.product)
.dropna()
.reset_index()
)
Output
month A B C D
0 1994-11 5.0 16.0 27.0 4.0
1 1995-07 5.0 16.0 54.0 16.0
2 1995-08 1.0 16.0 54.0 16.0
Another option if you are worried about entirely null columns:
import pandas as pd
import numpy as np
window = 5
df = pd.DataFrame({'month': ['1994-07',
'1994-08',
'1994-09',
'1994-10',
'1994-11',
'1995-07',
'1995-08'],
'A': [1, 5, 1, 1, 1, 1, 1],
'B': ['2', '2', '2', '2', 'NAN', '2', '2'],
'C': ['NAN', '3', '1', '3', '3', '2', '3'],
'D': ['NAN', '4', '1', '1', '1', '4', '4']})
df['C'] = np.nan
(
df.replace('NAN',np.nan)
.set_index('month')
.rolling(window=window, min_periods=1)
.apply(np.nanprod)
.reset_index()
).iloc[window-1:]
Output
month A B C D
4 1994-11 5.0 16.0 NaN 4.0
5 1995-07 5.0 16.0 NaN 16.0
6 1995-08 1.0 16.0 NaN 16.0