#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’.