Groupby and shift in pandas dataframe

Question:

Suppose I have a data frame

             Sym    C    O    R
01.01.2020   AAPL   100  115  0.2
01.01.2020   AA     200  205  0.4
02.01.2020   AAPL   101  116  0.3
02.01.2020   AA     201  206  0.2
02.01.2020   MM     298  300  0.5
03.01.2020   AAPL   110  105  0.3
03.01.2020   AA     203  204  0.1
03.01.2020   MM     301  303  0.2
04.01.2020   AAPL   108  113  0.3
04.01.2020   AA     200  201  0.4
04.01.2020   MM     302  300  0.3

How can I make a new data frame which will make the new columns for each previous date and be shifted for 3 periods?

I would expect

             Sym    C_1    O_1    R_1  C_2  O_2  R_2  C_3  O_3  R_3    
01.01.2020   AAPL   NaN    NaN ...                              NaN
01.01.2020   AA     NaN    NaN ...                              NaN
02.01.2020   AAPL   100    115    0.2  NaN  NaN  NaN  NaN  NaN  NaN   
02.01.2020   AA     200    205    0.4  NaN  NaN  NaN  NaN  NaN  NaN                                                                                                
02.01.2020   MM     NaN    NaN ...                              NaN                                        
03.01.2020   AAPL   101    116   0.3   100  115  0.2  NaN  NaN  NaN                                       
03.01.2020   AA     201    206   0.2   200  205  0.4  NaN  NaN  NaN                                  
03.01.2020   MM     298    300   0.5   NaN  NaN  ..             NaN                                      
04.01.2020   AAPL   101    116   0.3   100  115  0.2  110  105  0.3    
04.01.2020   AA     203    204   0.1   201  206  0.2  200  205  0.4                               
04.01.2020   MM     301    303   0.2   298  300  0.5  Nan  NaN  NaN                                

The answer provided in Use pandas.shift() within a group does not give what I expect. I tried also:

def shift_data (df):
    df= df.shift(3)
    return df

data.groupby('Sym',  group_keys=False).apply(shift_data) #
Asked By: Beginner_01

||

Answers:

Combine groupby.shift and pandas.concat:

N = 3
out = pd.concat([df[['Sym']]] + 
                [df.groupby('Sym').shift(i).add_suffix(f'_{i}')
                 for i in range(1, N+1)], axis=1)

Output:

             Sym    C_1    O_1  R_1    C_2    O_2  R_2    C_3    O_3  R_3
01.01.2020  AAPL    NaN    NaN  NaN    NaN    NaN  NaN    NaN    NaN  NaN
01.01.2020    AA    NaN    NaN  NaN    NaN    NaN  NaN    NaN    NaN  NaN
02.01.2020  AAPL  100.0  115.0  0.2    NaN    NaN  NaN    NaN    NaN  NaN
02.01.2020    AA  200.0  205.0  0.4    NaN    NaN  NaN    NaN    NaN  NaN
02.01.2020    MM    NaN    NaN  NaN    NaN    NaN  NaN    NaN    NaN  NaN
03.01.2020  AAPL  101.0  116.0  0.3  100.0  115.0  0.2    NaN    NaN  NaN
03.01.2020    AA  201.0  206.0  0.2  200.0  205.0  0.4    NaN    NaN  NaN
03.01.2020    MM  298.0  300.0  0.5    NaN    NaN  NaN    NaN    NaN  NaN
04.01.2020  AAPL  110.0  105.0  0.3  101.0  116.0  0.3  100.0  115.0  0.2
04.01.2020    AA  203.0  204.0  0.1  201.0  206.0  0.2  200.0  205.0  0.4
04.01.2020    MM  301.0  303.0  0.2  298.0  300.0  0.5    NaN    NaN  NaN
Answered By: mozway
for column in ['C','O','R']:    
    df[f'{column}_1']=df.groupby('Date')[column].transform(lambda x:x.shift(1))
    df[f'{column}_2']=df.groupby('Date')[column].transform(lambda x:x.shift(2))
    df[f'{column}_3']=df.groupby('Date')[column].transform(lambda x:x.shift(3))
Answered By: beridzeg45

I guess this approach works:

for i in range(3):
    for column_name in ['C', 'R', 'O']:    
        data[column_name + '_' + str(i + 1)] = data.groupby(['Sym'])[column_name].shift(i + 1)

but make sure your dataframe is sorted!

Answered By: Arya Sadeghi