One way you can create the same structure is by:
- Creating the lagged variables
df['lagged1'] = df['price'].shift(1)
df['lagged2'] = df['price'].shift(2)
df['lagged3'] = df['price'].shift(3)
df
Out[1]
price lagged1 lagged2 lagged3
0 1800 NaN NaN NaN
1 1750 1800.0 NaN NaN
2 1500 1750.0 1800.0 NaN
3 1240 1500.0 1750.0 1800.0
4 1456 1240.0 1500.0 1750.0
5 1302 1456.0 1240.0 1500.0
- Stacking those new variables
df.set_index('price').stack(dropna=False)\
.reset_index(1).drop('level_1', axis=1)\
.reset_index().rename(columns={0:'priceLags'})
Out[2]:
price priceLags
0 1800 NaN
1 1800 NaN
2 1800 NaN
3 1750 1800.0
4 1750 NaN
5 1750 NaN
6 1500 1750.0
7 1500 1800.0
8 1500 NaN
9 1240 1500.0
10 1240 1750.0
11 1240 1800.0
12 1456 1240.0
13 1456 1500.0
14 1456 1750.0
15 1302 1456.0
16 1302 1240.0
17 1302 1500.0
You can also drop the null values in the process:
df.set_index('price').stack(dropna=True).reset_index(level=1, drop=True).reset_index().rename(columns={0:'priceLags'})
Out[3]:
price priceLags
0 1750 1800.0
1 1500 1750.0
2 1500 1800.0
3 1240 1500.0
...
10 1302 1240.0
11 1302 1500.0
Added
After looking around a bit, I found this great answer on how to programatically create columns with lagged times. We can then stack and reset index a few times to get to our final result in one code call:
df.assign(**{
f'{col}_{t}': df[col].shift(t)
for t in lags
for col in df
})\
.set_index('price').stack(dropna=True)\ #group into one column
.reset_index(level=1, drop=True)\ #remove the column names
.reset_index().rename(columns={0:'priceLags'}) #reinsert the correct col names