Search code examples
pythonpython-3.xpandasdataframepandas-melt

Melt four (or more) dataframe columns into two rows


I am trying to convert a dataframe of structure:

ID ID2 ID3 R_u L_u R_sd L_sd
1  F   G1   x   y   z    t
2  M   G2   x   y   z    t

into

ID ID2 ID3 Side u sd
1  F   G1   R    x z
1  F   G1   L    y t 
2  M   G2   R    x z
2  M   G2   L    y t 

I used pandas.melt function

df_melt = df(id_vars=[('ID')], value_vars=['R_u', 'L_u'], 
                                  var_name='Side', value_name = 'u')

but I couldn't find a way for more than four or six number of columns simultaneously. I guess I can start with melt and then feed each row using lambda but I feel like I can do this automatically.

Any possible solution, please?


Solution

  • Good use case for janitor's pivot_longer:

    # pip install janitor
    import janitor
    
    out = df.pivot_longer(index="ID*", names_to=['Side', '.value'], names_sep='_',
                          sort_by_appearance=True # optional
                          )
    

    Output:

       ID ID2 ID3 Side  u sd
    0   1   F  G1    R  x  z
    1   1   F  G1    L  y  t
    2   2   M  G2    R  x  z
    3   2   M  G2    L  y  t
    

    With pure pandas, using reshaping and a MultiIndex:

    cols = list(df.filter(like='ID'))
    
    out = (df.set_index(cols)
             .pipe(lambda d: d.set_axis(d.columns.str.split('_', expand=True), axis=1))
             .rename_axis(columns=('Side', None))
             .stack(0).reset_index()
          )
    

    Output:

       ID ID2 ID3 Side sd  u
    0   1   F  G1    L  t  y
    1   1   F  G1    R  z  x
    2   2   M  G2    L  t  y
    3   2   M  G2    R  z  x