Раньше я достаточно быстро решал подобные задачи в DAX, но, будучи новичком в пандах, я на некоторое время застрял на этом:
Я пытаюсь вывести сводную таблицу, показывающую% продаж виз в месяц (столбцы) и по городам (строки).
Вот результат, который я ищу:
Jan Feb
London 50.055991 56.435644
Paris 15.119760 67.170191
Я пробовал различные сводные таблицы и функции группировки, которые приблизили меня к тому, что мне нужно, и в то же время так далеко от того, что мне нужно. Я просто привык создавать в Excel «показатели», которые можно добавлять в сводную таблицу как обычное измерение или факт.
Воспроизводимый ввод:
data = {'Month': {0: 'Jan',
1: 'Jan',
2: 'Jan',
3: 'Jan',
4: 'Feb',
5: 'Feb',
6: 'Feb',
7: 'Feb',
8: 'Feb'},
'City': {0: 'Paris',
1: 'Paris',
2: 'London',
3: 'London',
4: 'Paris',
5: 'Paris',
6: 'London',
7: 'London',
8: 'Paris'},
'Card': {0: 'Visa',
1: 'MasterCard',
2: 'Visa',
3: 'MasterCard',
4: 'Visa',
5: 'MasterCard',
6: 'Visa',
7: 'MasterCard',
8: 'Visa'},
' Amount ': {0: ' $101 ',
1: ' $567 ',
2: ' $447 ',
3: ' $446 ',
4: ' $926 ',
5: ' $652 ',
6: ' $114 ',
7: ' $88 ',
8: ' $408 '}}
df = pd.DataFrame.from_dict(data)
df
Привет @gtomer, я только что отредактировал свой пост, получив ожидаемый результат. Спасибо
@ouroboros1, где в вашем коде встречается виза/(виза+MC)?
@Maximuluss: см. редактирование моего ответа: Visa/(Visa + MasterCard)
делается установкой normalize
.
Как я понимаю из вашего объяснения, вы хотите проверить процент оплаты Visa для каждого города или сравнить с процентом сравнения Visa - Mastercard.
Для первого. Во-первых, преобразуйте столбец Amount
в числовой. Итак, для этого я удаляю знак «$» из ваших данных. После этого отфильтруйте df для транзакций Visa. Затем используйте group_by
для обозначения месяца и города и рассчитайте общий объем продаж Visa за каждый месяц. Наконец, поверните таблицу так, чтобы Month
было столбцами, а City
— строками. В последней части удалена метка месяца из таблицы с помощью pivot_table.columns.name = None
.
df = pd.DataFrame.from_dict(data)
df['Amount'] = df['Amount'].str.replace('$', '',regex=True).str.strip().astype(float)
visa_df = df[df['Card'] == 'Visa']
grouped = visa_df.groupby(['Month', 'City']).agg({'Amount': 'sum'})
grouped['% of Visa Sales'] = grouped.groupby('Month', group_keys=False).apply(lambda x: x / x.sum() * 100)
grouped.reset_index(inplace=True)
pivot_table = grouped.pivot(index='City', columns='Month', values='% of Visa Sales')
pivot_table.columns.name = None
Вывод такой:
Feb Jan
City
London 7.872928 81.569343
Paris 92.127072 18.430657
Для решения того, что я понимаю виза - мастер сравните.
Шаги для этого решения:
используйте group_by
для группировки по месяцу, городу и карте и рассчитайте
общий объем продаж за каждый месяц по городу и типу карты.
использовал pivot_table
, чтобы получить желаемую таблицу.
Рассчитайте процент продаж Visa по сравнению с общим объемом продаж. для каждого города в течение каждого месяца и выберите только нужные столбцы
Окончательный код такой.
df = pd.DataFrame.from_dict(data)
df['Amount'] = df['Amount'].str.replace('$', '',regex=True).str.strip().astype(float)
visa_master_df = df[df['Card'].isin(['Visa', 'MasterCard'])]
grouped = visa_master_df.groupby(['Month', 'City', 'Card']).agg({'Amount': 'sum'}).reset_index()
print(grouped)
pivot_table = grouped.pivot_table(index=['City'], columns=['Month', 'Card'], values='Amount', fill_value=0)
for month in ['Jan', 'Feb']:
pivot_table[('% of Visa Sales', month)] = (pivot_table[(month, 'Visa')] / (pivot_table[(month, 'Visa')] + pivot_table[(month, 'MasterCard')])) * 100
result = pivot_table[[('% of Visa Sales', 'Jan'), ('% of Visa Sales', 'Feb')]].round(2)
result.columns = ['Jan', 'Feb']
print(result)
Вывод такой
Jan Feb
City
London 50.06 56.44
Paris 15.12 67.17
Второй работает!
Вы можете использовать pd.crosstab для этого, связав df.stack , чтобы переместить уровень столбца «Город» в индекс, и df.loc , чтобы выбрать только «Visa» (и столбцы в желаемом order) и df.mul для умножения на 100.
# first turn your `' Amount ' column into `integers`
df[' Amount '] = df[' Amount '].str.replace('$', '').astype(int)
out = (
pd.crosstab(
index=df['Card'],
columns=[df['City'], df['Month']],
values=df[' Amount '],
aggfunc='sum',
normalize='columns'
)
.stack(level='City', future_stack=True)
.loc['Visa', ['Jan','Feb']]
.mul(100)
)
Выход
out
Month Jan Feb
City
London 50.055991 56.435644
Paris 15.119760 67.170191
Редактировать. в ответ на вопрос ОП: где Visa/(Visa + MasterCard)
происходит с pd.crosstab
?
Согласно документации, установка normalize
«[делит] все значения на сумму значений». В этом конкретном случае мы передаем «столбцы» для нормализации каждой комбинации «Город» и «Месяц».
То есть промежуточный результат без normalize
будет:
(
pd.crosstab(
index=df['Card'],
columns=[df['City'], df['Month']],
values=df[' Amount '],
aggfunc='sum'
)
)
City London Paris
Month Feb Jan Feb Jan
Card
MasterCard 88 446 652 567
Visa 114 447 1334 101
С normalize='columns'
:
City London Paris
Month Feb Jan Feb Jan
Card
MasterCard 0.435644 0.49944 0.328298 0.848802
Visa 0.564356 0.50056 0.671702 0.151198
Например, для Visa
(строка) и ('London', 'Feb')
(столбец) мы получаем 114/(88+114) = 0.564356
. Остальная часть приведенного выше кода меняет только форму/представление результата.
Использование Pivot_table , Pipe для вычисления соотношения и unstack для изменения формы:
df['Amount'] = pd.to_numeric(df['Amount'].str.strip(' $'))
out = (df
.pivot_table(index=['Month', 'City'], columns='Card',
values='Amount', aggfunc='sum')
.pipe(lambda x: x['Visa']/x.sum(axis=1)*100)
.unstack('Month')
)
Выход:
Month Feb Jan
City
London 56.435644 50.055991
Paris 67.170191 15.119760
Чтобы отсортировать месяцы:
from calendar import month_abbr
months = {m:i for i, m in enumerate(month_abbr)}
df['Amount'] = pd.to_numeric(df['Amount'].str.strip(' $'))
out = (df
.pivot_table(index=['Month', 'City'], columns='Card',
values='Amount', aggfunc='sum')
.pipe(lambda x: x['Visa']/x.sum(axis=1)*100)
.unstack('Month').sort_index(axis=1, key=lambda x: x.map(months))
)
Выход:
Month Jan Feb
City
London 50.055991 56.435644
Paris 15.119760 67.170191
Пожалуйста, опубликуйте желаемый пример вывода