Групповое транспонирование Pandas

#python #pandas #pandas-groupby

#python #pandas #pandas-groupby

Вопрос:

У меня есть файл из SAP, который был не самым красивым при работе с данными. Итак, используя series.str.contains() и логические маски, мне удалось сузить круг до фрейма данных, который выглядит следующим образом:

        0        1
0    SUB      123
1    CAT      SKU
2   CODE  1000123
3   CODE  1000234
4    SUB      456
5    CAT      LIQ
6  CODE1  1000345
7  CODE1  1000534
8  CODE1  1000433
  

Я ищу способ, с помощью которого я мог бы разделить каждую из них SUB на новую запись, как показано ниже:

 print(expected_df)

   SUB  CAT       CODE      CODE1
0  123  SKU  1000123.0        NaN
1  123  SKU  1000234.0        NaN
2  456  LIQ        NaN  1000345.0
3  456  LIQ        NaN  1000534.0
4  456  LIQ        NaN  1000433.0
  

Кажется, я просто не могу пройти этот шаг. Однако эта строка:

 df[0].eq('SUB').cumsum()
  

помогает разделить группы и при необходимости может использоваться как вспомогательный ряд.

Любая помощь в транспонировании данных, как показано, была бы действительно оценена.

Спасибо.

Комментарии:

1. Всегда ли есть один CAT на SUB ?

2. @Jondiedoop спасибо, что взглянули, да, на каждый сабвуфер есть только CAT. По сути, это похоже на категорию. 🙂

Ответ №1:

Вы можете попробовать использовать df.pivot , за которым следуют .ffill(),bfill() для конкретных строк группы столбцов «SUB».

 df1 = df.pivot(columns='0')
df1.columns = df1.columns.map(lambda x: x[1])
df1.SUB = df1.SUB.ffill()
df1.groupby('SUB').ffill().groupby('SUB').bfill().drop_duplicates()
#5.89 ms ± 1.84 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)

# as time constraints, without use of lambda operation
#df1.groupby(df1.SUB.ffill()).apply(lambda x: x.ffill().bfill()).drop_duplicates()
#16 ms ± 1.06 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
  

Выход:

     SUB CAT CODE    CODE1   SUB
2   123 SKU 1000123 NaN     123
3   123 SKU 1000234 NaN      123
6   456 LIQ NaN     1000345 456
7   456 LIQ NaN     1000534 456
8   456 LIQ NaN     1000433 456
  

Ответ №2:

IIUC,

 df.set_index('col1').groupby(df.col1.eq('SUB').cumsum().values).apply(lambda s: pd.DataFrame({
    'SUB': s.loc['SUB'].item(),
    'CAT': s.loc['CAT'].item(),
     s.index[2]: s.loc[s.index[2]].col2.tolist()
})).reset_index(drop=True)
  

Выводит

     SUB CAT CODE    CODE1
0   123 SKU 1000123 NaN
1   123 SKU 1000234 NaN
2   456 LIQ NaN     1000345
3   456 LIQ NaN     1000534
4   456 LIQ NaN     1000433
  

Однако это похоже на проблему XY. Может быть, стоит взглянуть на то, как вы в конечном итоге получили это df в первую очередь

Ответ №3:

IIUC

 l=[y.set_index('0').T.set_index(['SUB','CAT']).stack() for x , y in df.groupby(df['0'].eq('SUB').cumsum())]
s=pd.concat(l).to_frame('v')
s.assign(key=s.groupby(level=[0,1,2]).cumcount()).set_index('key',append=True).unstack(2)
                   v         
0               CODE    CODE1
SUB CAT key                  
123 SKU 0    1000123      NaN
        1    1000234      NaN
456 LIQ 0        NaN  1000345
        1        NaN  1000534
        2        NaN  1000433