Search code examples
pythondataframegroup-byrolling-computation

roll/rotate a groupby Dataframe including the index


I want to rotate a Dataframe according to its groups and I need the Index to rotate with the rows as well. I want to do that, to then use a find_peaks function to get the peaks that are on the edges, because for me the data is kind a like a loop. Following is a df example with randome number values, where the df.groupby('Value a') is made.

idx ValueA ValueB
1 a 0.123
2 a 0.253
3 a 0.456
4 a 0.789
5 a 0.147
6 b 0.258
7 b 0.369
8 b 0.321
9 b 0.654
10 b 0.987

And this is how it should look like afterwards:

idx ValueA ValueB
4 a 0.789
5 a 0.147
1 a 0.123
2 a 0.253
3 a 0.456
9 b 0.654
10 b 0.987
6 b 0.258
7 b 0.369
8 b 0.321

I tried:

def roll_frame(df, shift):
    return pd.DataFrame(np.roll(df, shift, axis=0), index=df.index, columns=df.columns)

df_new = df.groupby('Value a').apply(roll_frame, 2)

The Value is shifted correctly, but not the Index. To erase the double Index, I used:

df_new.reset_index(level=0, drop=True, inplace=True)

which resulted in this:

idx ValueA ValueB
1 a 0.789
2 a 0.147
3 a 0.123
4 a 0.253
5 a 0.456
6 b 0.654
7 b 0.987
8 b 0.258
9 b 0.369
10 b 0.321

Solution

  • The easiest way I can think of would be to np.roll() the index as well:

    def roll_frame(df, shift):
        return pd.DataFrame(
            np.roll(df, shift, axis=0), index=np.roll(df.index, shift), columns=df.columns
        )
    
    
    df_new = df.groupby("ValueA").apply(roll_frame, 2)
    print(df_new)
    

    Prints:

              ValueA ValueB
    ValueA                 
    a      4       a  0.789
           5       a  0.147
           1       a  0.123
           2       a  0.253
           3       a  0.456
    b      9       b  0.654
           10      b  0.987
           6       b  0.258
           7       b  0.369
           8       b  0.321