Объединение и выравнивание столбцов на основе 2 столбцов

#python #pandas #reshape

#python #панды #изменение формы

Вопрос:

У меня есть df, как показано ниже:

 ID  P1   P2   P3_1_A  P3_2_B   P4_1_A  P4_2_B
1   110  111   1        0       1       1
2   111  112   0        0       1       0
3   110  112   0        1       0       0
4   112  111   1        1       1       1
 

Итак, P1 и P2 имеют 3 различных значения 110 , 111 и 112 .

Число столбцов P3 и P4 всегда равно (2 в приведенном выше случае), но может варьироваться от данных к данным.

Мне нужен результирующий фрейм данных, в котором все значения P3 выровнены по P1, а все значения P4 — по P2, а столбцы переименованы и выглядят следующим образом

 ID   P     P_A   P_B
1    110    1     0
1    111    1     1
2    111    0     0
2    112    1     0
3    110    0     1
3    112    0     0
4    112    1     1
4    111    1     1
 

Я знаю, как объединить P1 и P2 и добраться до столбца P, но не понимаю, как выровнять P3 и P4 до P1 и P2 и добраться до P_1 и P_2

Ответ №1:

Вы можете переименовывать столбцы для _ подстрок, поэтому возможно преобразование ID в индекс и разделение всех значений на MultiIndex и последнее изменение формы на DataFrame.stack :

 df1 = df.rename(columns={'P1':'P3_','P2':'P4_'}).set_index('ID')
df1.columns = df1.columns.str.split('_', expand=True, n=1)
df1 = df1.stack(0).add_prefix('P').reset_index(level=1, drop=True).reset_index()
print (df1)
   ID    P  P1_A  P2_B
0   1  110     1     0
1   1  111     1     1
2   2  111     0     0
3   2  112     1     0
4   3  110     0     1
5   3  112     0     0
6   4  112     1     1
7   4  111     1     1
 

РЕДАКТИРОВАТЬ: для более общего решения возможно извлечь имена столбцов без двойного _ и передать set_index :

 print (df)
   ID   P1   P2  P3_1_A  P3_2_B  P4_1_A  P4_2_B  A
0   1  110  111       1       0       1       1  9
1   2  111  112       0       0       1       0  7
2   3  110  112       0       1       0       0  8
3   4  112  111       1       1       1       1  7

df1 = df.rename(columns={'P1':'P3__','P2':'P4__'})

cols = df1.columns[df1.columns.str.count('_') != 2]
df1 = df1.set_index(cols.tolist())
df1.columns = df1.columns.str.split('_', expand=True, n=1)
df1 = df1.stack(0).add_prefix('P').reset_index(level=-1, drop=True).reset_index()
print (df1)
   A  ID  P1_A  P2_B   P_
0  9   1     1     0  110
1  9   1     1     1  111
2  7   2     0     0  111
3  7   2     1     0  112
4  8   3     0     1  110
5  8   3     0     0  112
6  7   4     1     1  112
7  7   4     1     1  111
 

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

1. Мой плохой, мои столбцы переименованы по-другому, и, следовательно, вышеупомянутое не работает … не могли бы вы проверить обновленный вопрос

2. @RahulAgarwal — добавлено n=1 в df1.columns.str.split('_', expand=True, n=1) , можете ли вы протестировать?

3. Все получилось отлично .. еще один запрос… допустим, если в df есть еще несколько столбцов, скажем C1, C2 … и я бы хотел, чтобы C1, C2 просто дублировали. Как изменится решение

4. @RahulAgarwal — Затем измените .set_index('ID') на .set_index(['ID','C1','C2'])

5. если бы было еще около 50 столбцов, это было бы сложно … любым другим способом!!

Ответ №2:

Вы можете использовать функцию pivot_longer из pyjanitor; на данный момент вам необходимо установить последнюю версию разработки с github :

Столбцы имеют шаблоны (некоторые заканчиваются числом (1 или 2), в то время как другие заканчиваются либо ‘A’, либо ‘B’). Мы можем воспользоваться этим шаблоном и изменить форму данных. Мы передаем список новых имен столбцов names_to и передаем список регулярных выражений, которые соответствуют шаблонам names_pattern :

  # install the latest dev version of pyjanitor
 # pip install git https://github.com/ericmjl/pyjanitor.git

 import janitor

df.pivot_longer(
    index="ID",
    names_to=("P", "P_A", "P_B"),
    names_pattern=("^Pd$", ".*A$", ".*B$"),
    sort_by_appearance=True,
)

   ID   P   P_A P_B
0   1   110 1   0
1   1   111 1   1
2   2   111 0   0
3   2   112 1   0
4   3   110 0   1
5   3   112 0   0
6   4   112 1   1
7   4   111 1   1
 

В приведенном выше коде новый P столбец принимает все значения из предыдущего фрейма данных, в котором были столбцы P1 или P2 (они заканчиваются числами), P_A принимает столбцы, которые заканчиваются на ‘A’, в то время P_B как принимает столбцы, которые заканчиваются на ‘B’.