Как объединить несколько строк в одном фрейме данных pandas по столбцу общего ключа (фиксированное ограничение длины)?

#python #pandas

#python #pandas

Вопрос:

Как вы можете объединить несколько строк в одном фрейме данных pandas по столбцу общего ключа, где мы допускаем фиксированное ограничение длины для любой объединенной строки строк (поскольку количество строк с заданным общим ключом в этом случае является переменным)?

Создайте фрейм данных подобной формы…

 key x1 x2 x3
-------------
1   a1 a2 a3
1   b1 b2 b3
2   c1 c2 c3
3   d1 d2 d3
3   e1 e2 e3
3   f1 f2 f3
3   g1 g2 g3
....
  

и хотел бы изменить это на что-то вроде

 key x11 x12 x13 x21 x22 x23 x31 x32 x33
-------------
1   a1  a2  a3  b1  b2  b3  NA  NA  NA
2   c1  c2  c3  NA  NA  NA  NA  NA  NA
3   d1  d2  d3  e1  e2  e3  f1  f2  f3
....
  

где столбец xjk — это k-я функция j-й строки, имеющая тот же ключ, что и другие строки, сгруппированные в этой же строке до (в данном случае вручную установлено значение …) 3 на группу (но может потребоваться изменить позже, и может быть значением, превышающим количество группируемых строк (например, здесь 5), в этом случае его следует просто заполнить NAs). Обратите внимание, что когда количество группируемых отдельных исходных строк меньше максимального предела, мы заполняем значения NA, а когда строк слишком много, мы группируем только до максимального предела строк и удаляем остальное из фрейма данных. Также обратите внимание, что иногда в отдельной строке могут отсутствовать значения.

Есть предложения о том, как это можно сделать?

Ответ №1:

Использование groupby и затем ravel для выравнивания всех значений внутри группы:

 lim = 5

df = df.set_index('key')
k = len(df.columns)

x = df.groupby(level=0).apply(
    lambda z: z.iloc[:lim].values.ravel().tolist()  
    [np.nan]*(lim*k-z.size))

x = pd.DataFrame(x.tolist(), x.index)

x.columns = [f'x{1 i//k}{1 i%k}' for i in x.columns]

print(x)
  

Вывод:

     x11 x12 x13  x21  x22  x23  x31  x32  x33  x41  x42  x43  x51  x52  x53
key                                                                        
1    a1  a2  a3   b1   b2   b3  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN
2    c1  c2  c3  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN
3    d1  d2  d3   e1   e2   e3   f1   f2   f3   g1   g2   g3  NaN  NaN  NaN
  

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

1. Спасибо. Примечание для других, использующих этот вопрос, обратите внимание, что форматирование строки последней строки для обозначения столбцов будет работать только в python 3.6 , если все еще необходимо использовать python 2.7 'x{}{}.format((1 i//len(x)), (1 i%len(x)))' .

2. Извините, вы правы, я пропустил это требование. Обновил мой ответ lim переменной, которая устанавливает это ограничение. В основном нам нужно взять первые lim строки в приложении с .iloc[:lim]

3. @lampShadesDrifter: И спасибо, это очень хороший момент о f-строках в python 3.6

4. Как ни странно, этот код, похоже, не работает для меня (с использованием python 2.7) тестовый фрейм данных, созданный так, чтобы быть похожим на тот, что в исходном вопросе. Получение меток столбцов: x11 x12 x13 x14 x15 x16 x17 x18 x19 . Я думаю, что последняя строка в данном коде должна быть чем-то вроде: x.columns = [f'x{1 i//len(df.columns)}{1 i%len(df.columns)}' for i in x.columns] . Затем это дало мне результаты, показанные в этом ответе.

5. Просматривая код и статистику по моим фактическим данным варианта использования, я не думаю, что этот ответ на самом деле работает для требования, что максимальное ограничение может быть значением, превышающим количество группируемых строк (что, как я теперь понимаю, не было явным в исходном вопросе и действительно лучше всего иллюстрировало примерный случай). Обратите внимание, в моем реальном варианте использования есть строки с ~ 33 столбцами в каждой, которые пытаются объединить (~ 7 отдельных строк на комбинацию).