Search code examples
pythonpandassortingdataframecolumnsorting

Pandas reverse column values groupwise


I want to reverse a column values in my dataframe, but only on a individual "groupby" level. Below you can find a minimal demonstration example, where I want to "flip" values that belong the same letter A,B or C:

df = pd.DataFrame({"group":["A","A","A","B","B","B","B","C","C"],
                   "value": [1,3,2,4,4,2,3,2,5]})

  group  value
0     A      1
1     A      3
2     A      2
3     B      4
4     B      4
5     B      2
6     B      3
7     C      2
8     C      5

My desired output looks like this: (column is added instead of replaced only for the brevity purposes)

  group  value  value_desired
0     A      1              2
1     A      3              3
2     A      2              1
3     B      4              3
4     B      4              2
5     B      2              4
6     B      3              4
7     C      2              5
8     C      5              2

As always, when I don't see a proper vector-style approach, I end messing with loops just for the sake of final output, but my current code hurts me very much:

for i in list(set(df["group"].values.tolist())):
    reversed_group = df.loc[df["group"]==i,"value"].values.tolist()[::-1]
    df.loc[df["group"]==i,"value_desired"] = reversed_group

Pandas gurus, please show me the way :)


Solution

  • You can use transform

    In [900]: df.groupby('group')['value'].transform(lambda x: x[::-1])
    Out[900]:
    0    2
    1    3
    2    1
    3    3
    4    2
    5    4
    6    4
    7    5
    8    2
    Name: value, dtype: int64
    

    Details

    In [901]: df['value_desired'] = df.groupby('group')['value'].transform(lambda x: x[::-1])
    
    In [902]: df
    Out[902]:
      group  value  value_desired
    0     A      1              2
    1     A      3              3
    2     A      2              1
    3     B      4              3
    4     B      4              2
    5     B      2              4
    6     B      3              4
    7     C      2              5
    8     C      5              2