With numpy>=1.20.0 only.
Input data for demo:
import pandas as pd
import numpy as np
from numpy.lib.stride_tricks import sliding_window_view
WINDOWSIZE = 3
df = pd.DataFrame(data=10 * np.arange(5*10).reshape((5, 10)))
>>> df
0 1 2 3 4 5 6 7 8 9
0 0 10 20 30 40 50 60 70 80 90
1 100 110 120 130 140 150 160 170 180 190
2 200 210 220 230 240 250 260 270 280 290
3 300 310 320 330 340 350 360 370 380 390
4 400 410 420 430 440 450 460 470 480 490
Use sliding_window_view to create a sliding window view into the array with the given window shape:
>>> sliding_window_view(df, (WINDOWSIZE, len(df.columns)))
array([[[[ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90],
[100, 110, 120, 130, 140, 150, 160, 170, 180, 190],
[200, 210, 220, 230, 240, 250, 260, 270, 280, 290]]],
[[[100, 110, 120, 130, 140, 150, 160, 170, 180, 190],
[200, 210, 220, 230, 240, 250, 260, 270, 280, 290],
[300, 310, 320, 330, 340, 350, 360, 370, 380, 390]]],
[[[200, 210, 220, 230, 240, 250, 260, 270, 280, 290],
[300, 310, 320, 330, 340, 350, 360, 370, 380, 390],
[400, 410, 420, 430, 440, 450, 460, 470, 480, 490]]]])
Apply argmax over the third axis (index=2) and squeeze to get a 2D-array (dataframe like):
>>> sliding_window_view(df, (WINDOWSIZE, len(df.columns))).argmax(axis=2)
array([[[2, 2, 2, 2, 2, 2, 2, 2, 2, 2]],
[[2, 2, 2, 2, 2, 2, 2, 2, 2, 2]],
[[2, 2, 2, 2, 2, 2, 2, 2, 2, 2]]])
>>> sliding_window_view(df, (WINDOWSIZE, len(df.columns))).argmax(axis=2).squeeze()
array([[2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2]])
Finally, convert array to DataFrame:
out = pd.DataFrame(index=df.index, columns=df.columns)
out.iloc[WINDOWSIZE-1:] = sliding_window_view(df, (WINDOWSIZE, len(df.columns))) \
.argmax(axis=2).squeeze()
>>> out
0 1 2 3 4 5 6 7 8 9
2 2 2 2 2 2 2 2 2 2 2
3 2 2 2 2 2 2 2 2 2 2
4 2 2 2 2 2 2 2 2 2 2
Performance
WINDOWSIZE = 20
df1 = pd.DataFrame(data=np.random.randint(10000, size=(3774, 3000)), index=pd.date_range('2010-01-01', '2020-05-01', freq='d'))
>>> %timeit sliding_window_view(df1, (WINDOWSIZE, len(df1.columns))).argmax(axis=2).squeeze()
1.43 s ± 5.63 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)