Отмена поворота кадра данных путем разделения имен столбцов

У меня есть следующий фрейм данных:

Volume_brand1 Volume_productX_brand1 sum_brand1 sum_productX_brand1 Volume_productX_brand2 sum_productX_brand2 1000 100 10 50 2000 г. 200

и т. д...

Я хотел бы развернуть этот фрейм данных, чтобы он выглядел следующим образом:

бренд продукт объем количество бренд1 продуктX 100 50 бренд1 «не продукт Х» 1000 10 бренд2 продуктX 2000 г. 200

и т. д..

Я пробовал использовать функцию панд melt, но безуспешно. Поскольку каждый столбец должен быть отключен, в этом нет никакой ценности id_vars, любая помощь будет оценена по достоинству!

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
55
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

вы можете использовать stack и pivot_table,

import pandas as pd

data = {
    'volume_brand1': [1000],
    'volume_productX_brand1': [100],
    'amount_brand1': [10],
    'amount_productX_brand1': [50],
    'volume_productX_brand2': [2000],
    'amount_productX_brand2': [200]
}

df = pd.DataFrame(data)

df_stacked = df.stack()

df_stacked = df_stacked.reset_index()
df_stacked.columns = ['row', 'original_column', 'value']

df_stacked[['metric', 'product', 'brand']] = df_stacked['original_column'].str.extract(r'(volume|amount)_([^_]+)(?:_(.*))?')

df_stacked = df_stacked.drop(columns=['original_column', 'row'])

df_pivoted = df_stacked.pivot_table(index=['brand', 'product'], columns='metric', values='value').reset_index()

df_pivoted['brand'] = df_pivoted['brand'].ffill()
df_pivoted['product'] = df_pivoted['product'].fillna('not product X')

df_pivoted['volume'] = df_pivoted['volume'].astype(int)
df_pivoted['amount'] = df_pivoted['amount'].astype(int)

df_pivoted.columns.name = None
df_final = df_pivoted[['brand', 'product', 'volume', 'amount']]

print(df_final)

Выход,

    brand   product  volume  amount
0  brand1  productX   100    50
1  brand2  productX  2000   200

Вы можете использовать melt и pivot_table для преобразования:

# Assuming `df` is your original DataFrame

df_melted = df.melt()

df_melted['brand'] = df_melted['variable'].apply(lambda x: x.split('_')[-1])
df_melted['product'] = df_melted['variable'].apply(
    x: 'productX' if 'productX' in x else 'not product X'
)
df_melted['metric'] = df_melted['variable'].apply(
    lambda x: 'volume' if 'volume' in x else 'amount'
)

df_unpivoted = df_melted.pivot_table(
    index=['brand', 'product'], columns='metric', values='value', aggfunc='first'
).reset_index()
df_unpivoted = df_unpivoted.sort_values("volume").reset_index(drop=True)

print(df_unpivoted)

Результат:

metric   brand        product  amount  volume
0       brand1       productX      50     100
1       brand1  not product X      10    1000
2       brand2       productX     200    2000
Ответ принят как подходящий

Другое возможное решение:

  • Он переименовывает столбцы для создания согласованного шаблона с помощью str.replace , затем складывает фрейм данных, чтобы преобразовать его из широкого формата в длинный.

  • После суммирования столбец level_1 разбивается на metric, product и brand, и эти столбцы объединяются обратно в исходные данные.

  • Наконец, фрейм данных поворачивается, чтобы вернуть его в широкий формат, где volume и amount становятся отдельными столбцами, организованными brand и product.

df.columns = df.columns.str.replace(
    r'(volume|amount)_(brand)', r'\1_NotProductX_\2', regex=True)

d = df.stack().reset_index()

(pd.concat([
    d, d['level_1'].str.split('_', expand=True)], axis=1).iloc[:, [5, 4, 3, 2]]
 .set_axis(['brand', 'product', 'metric', 'value'], axis=1)
 .pivot(index=['brand', 'product'], columns='metric', values='value')
 .reset_index())

Выход:

metric   brand      product  amount  volume
0       brand1  NotProductX      10    1000
1       brand1     productX      50     100
2       brand2     productX     200    2000

pyjanitor предлагает два эффективных метода преобразования данных из широкой формы в длинную — Pivot_longer_spec и Pivot_longer.

Начнем с Pivot_longer_spec — это дает вам более детальный контроль над тем, как вы хотите изменить форму данных — вам нужно передать фрейм данных, который имеет столбец .name, который содержит имена столбцов, которые нужно изменить, и столбец .value, который содержит новые имена столбцов. Вы можете добавить дополнительные столбцы, если они не существуют в исходном фрейме данных:

# pip install pyjanitor
import pandas as pd
import janitor as jn
from janitor import pivot_longer_spec

# build your spec
product_x = np.where(df.columns.str.contains('productX'), 
                     'product_X', 
                     'not_product_X')
spec = {'.name':df.columns, 
         '.value':df.columns.str.split('_').str[0], 
         'brand': df.columns.str.split('_').str[-1], 
         'product':product_x}
spec = pd.DataFrame(spec)
# for this particular data, 
# we need to make it unique
grp = spec.groupby('.value', sort=False)
spec['uniq'] = grp.cumcount()
pivot_longer_spec(df=df,spec=spec).drop(columns='uniq')
    brand        product  volume  amount
0  brand1  not_product_X    1000      10
1  brand1      product_X     100      50
2  brand2      product_X    2000     200

Pivot_longer — это абстракция более высокого уровня, которая полезна для данных, которые имеют очевидные закономерности. Для ваших данных нам нужно внести некоторые изменения в столбцы перед использованием Pivot_longer:

dff = df.copy()
new_cols = [col 
            if 'productX' in col 
            else [col[0], 'notproductX', col[1]]  
            for col in dff.columns.str.split('_')]
new_cols = ["_".join(col) for col in new_cols]
dff.pivot_longer(index=None, 
                 names_to=('.value', 'product', 'brand'), 
                 names_sep='_')
       product   brand  volume  amount
0  notproductX  brand1    1000      10
1     productX  brand1     100      50
2     productX  brand2    2000     200

Другие вопросы по теме