Как преобразовать группы столбцов в строки в Панд?

#python #python-3.x #pandas #dataframe

Вопрос:

Допустим, у меня есть фрейм данных следующего вида:

Имя Время работы в 1-м часу Время, потраченное впустую за 1 час Время работы во 2-м часу Время, потраченное впустую за 2 часа
фу 45 15 40 20
бар 35 25 55 5
баз 50 10 45 15

Я хочу использовать расплав в столбцах 1-го часа и столбцах 2-го часа, чтобы это выглядело так:

Имя Номер часа Время, отработанное в отделе кадров Время, потраченное впустую в отдел кадров
фу 1 45 15
фу 2 40 20
бар 1 35 25
бар 2 55 5
баз 1 50 10
баз 2 45 15

Как бы я сгруппировал «Время, затраченное в 1-й час» и «Время, потраченное впустую в 1-й час» вместе, чтобы я мог объединить их в один ряд?

Ответ №1:

Вы можете использовать:

 df1 = df.set_index('Name')
df1.columns = df1.columns.str.split('in', expand=True)

df2 = (df1.stack()
          .sort_index(axis=1, ascending=False)
          .rename_axis(index=['Name', 'Hour number'])
          .add_suffix('in the hr')
          .reset_index()
      )

df2['Hour number'] = df2['Hour number'].str.extract(r'(d )')
 

Результат:

 print(df2)

  Name Hour number  Time worked in the hr  Time wasted in the hr
0  foo           1                     45                     15
1  foo           2                     40                     20
2  bar           1                     35                     25
3  bar           2                     55                      5
4  baz           1                     50                     10
5  baz           2                     45                     15
 

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

1. Спасибо! Я не уверен, что должна делать последняя строка, что должен делать str.extract в этом случае?

2. @crysoar Последняя строка предназначена для извлечения номера часа из текста 1st и 2nd т. Д. Если вы выполните приведенные выше коды шаг за шагом без последней строки, вы увидите промежуточный результат Hour number удержания 1st hr , 2nd hr . Нам нужно навести порядок и получить только номер.

Ответ №2:

Что-то вроде:

 import numpy as np
df = df.set_index('Name')
df.columns = pd.MultiIndex.from_arrays([np.repeat([1,2], len(df.columns)//2), np.tile(['worked', 'wasted'], len(df.columns)//2)])
df.stack(level=0)
 

nb. Я не мог проверить код

Ответ №3:

Вы можете выполнить всю обработку текста в столбцах перед изменением формы; чем меньше строк для работы, тем лучше/быстрее может быть ваш код:

Установить Name в качестве индекса:

 df = df.set_index('Name')
 

Извлеките числа и установите expand=False , чтобы они оставались в качестве индекса:

  numbers = df.columns.str.extract(r"(d)", expand=False).rename("Hour Number")
 

Замените цифры на the :

 no_numbers = df.columns.str.replace("d.{2}", "the", regex=True)
 

Создайте столбец с несколькими индексами:

 df.columns = pd.MultiIndex.from_arrays([numbers, no_numbers])
 

Сложите столбцы в стопку и сбросьте индекс:

 df.stack('Hour Number').reset_index()

  Name Hour Number  Time wasted in the hr  Time worked in the hr
0  foo           1                     15                     45
1  foo           2                     20                     40
2  bar           1                     25                     35
3  bar           2                      5                     55
4  baz           1                     10                     50
5  baz           2                     15                     45