I am looking for a faster and more elegant way to solve the following problem:
Given a pandas data frame, I want to combine the current row and the previous k (prev_len) rows into a new row (of a new data frame). I want to do this for every valid old row, i.e. every row that has k previous rows. That is, every new row will consist of prev_len + 1 old rows that were horizontally appended next to each other. Hence, the resulting data frame will have prev_len fewer rows than the old data frame and its number of columns will be prev_len + 1 * number_of_columns_in_old_data_frame. Please see the example below with prev_len=2. Thanks a lot in advance!
Given data frame:
x1 x2 y
0 166 9 -2.426679
1 192 6 -0.428913
2 198 1 1.265936
3 117 0 -0.866740
4 183 1 -0.678886
Desired data frame:
00_x1 00_x2 00_y 01_x1 01_x2 01_y 02_x1 02_x2 02_y
0 166.0 9.0 -2.426679 192.0 6.0 -0.428913 198.0 1.0 1.265936
1 192.0 6.0 -0.428913 198.0 1.0 1.265936 117.0 0.0 -0.866740
2 198.0 1.0 1.265936 117.0 0.0 -0.866740 183.0 1.0 -0.678886
My solution:
import numpy as np
import pandas as pd
import random
# given data ----------------------------------------------------------
np.random.seed(seed=123)
df = pd.DataFrame({'x1': np.random.randint(100, 200, 5),
'x2': np.random.randint(0,10,5),
'y': np.random.randn(5)})
print(df)
# desired data -------------------------------------------------------
prev_len = 2
lag = []
for i in range(prev_len + 1):
lag += [i] * len(df.columns.to_list())
col = df.columns.to_list() * (prev_len + 1)
colnames = ["{:02}_{}".format(lag_, col_) for lag_, col_ in zip(lag, col)]
df_new = pd.DataFrame(columns = colnames)
for i_new, i_old in zip(range(df.shape[0] - prev_len), range(prev_len, df.shape[0])):
obs = pd.Series()
print(i_old)
for j in range(i_old - 2, i_old + 1):
obs = obs.append(df.iloc[j, :])
df_new.loc[i_new] = obs.to_list()
print(df_new)