Панды — процент от общего числа в сводной таблице

Раньше я достаточно быстро решал подобные задачи в 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 06.04.2024 11:57

Привет @gtomer, я только что отредактировал свой пост, получив ожидаемый результат. Спасибо

Maximuluss 06.04.2024 12:49

@ouroboros1, где в вашем коде встречается виза/(виза+MC)?

Maximuluss 06.04.2024 13:27

@Maximuluss: см. редактирование моего ответа: Visa/(Visa + MasterCard) делается установкой normalize.

ouroboros1 07.04.2024 13:49
Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
4
4
168
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Как я понимаю из вашего объяснения, вы хотите проверить процент оплаты 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

Для решения того, что я понимаю виза - мастер сравните.

Шаги для этого решения:

    1. используйте group_by для группировки по месяцу, городу и карте и рассчитайте общий объем продаж за каждый месяц по городу и типу карты.

    2. использовал pivot_table, чтобы получить желаемую таблицу.

    3. Рассчитайте процент продаж 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

Второй работает!

Maximuluss 06.04.2024 12:59

Вы можете использовать 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

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

При использовании pandas для чтения файла Excel любые ячейки, использующие поиск в другой таблице, читаются как NaN, есть ли обходной путь?
Pandas: сортировка многоуровневых столбцов
Как читать несколько файлов Excel, конвертировать их в отдельные файлы CSV без жесткого кодирования имени файла и пути в Python
Snowflake-connector-python[pandas] write_pandas создает повторяющиеся записи в таблице
Динамически создавать столбцы в зависимости от структуры строки в Python
Постройте график для каждой подгруппы группы
Как выбрать первое N количество групп на основе значений столбца условно и сгруппировать по двум столбцам?
Как условно выбрать первые N групп на основе значений столбца?
Как проанализировать текстовый файл с заголовками, состоящими из нескольких строк в Python
Создайте Dataframe из серии и, в частности, как переименовать столбец в нем (пример: с помощью NA/NaN)