Python - Расчет процента от общей суммы в сводных таблицах

У меня есть фрейм данных, который я преобразовал в сводную таблицу с помощью метода pd.pivot_table и функции агрегирования суммы:

summary = pd.pivot_table(df, 
                         index=["Region"], 
                         columns=["Product"], 
                         values=['Price'],
                         aggfunc=[np.sum],
                         fill_value=0,
                         margins=True,
                         margins_name="Total"
                        )

Я получил такой вывод:

Образец сводной таблицы

Я хотел бы добавить еще одну сводную таблицу, которая отображает процент от общей суммы, рассчитанный в предыдущей сводной таблице для каждой из категорий. Все это должно составлять в сумме 100% и выглядеть следующим образом.

Сводная таблица с процентами от общего итога

Я пробовал следующий обходной путь, который нашел в stackoverflow:

total = df['Price'].sum()

table = pd.pivot_table(DF, 
                       index=["Region"],
                       columns=["Product"], 
                       values=['Price'],
                       aggfunc=[np.sum, 
                                (lambda x: sum(x)/total*100)
                               ],
                       fill_value=0,
                       margins=True,
                       margins_name="Total"
                      )

Это подсчитало проценты, но они в сумме составляют только 85% ...

Было бы здорово, если бы вам не приходилось вычислять общую сумму за пределами сводной таблицы, а просто иметь возможность вызывать общую сумму из первой опорной таблицы. Но даже если мне придется вычислять отдельно, как в приведенном выше коде, пока он составляет 100%, это все равно будет здорово.

Заранее спасибо!


person Tatiana    schedule 16.01.2018    source источник
comment
Не могли бы вы добавить текстовую версию таблицы.   -  person Bharath    schedule 16.01.2018
comment
Также покажите нам, как выглядят данные df, чем вывод сводной таблицы   -  person Bharath    schedule 16.01.2018
comment
Дарк, продажи были просто примером, чтобы показать, что я пытаюсь сделать. Я работаю с очень конфиденциальными данными, которыми не могу поделиться. Как новичок в Python, каждый раз, когда что-то идет не так, я думаю, что это мой код. Но ваш вопрос заставляет меня внимательнее присмотреться к своим данным. У меня было несколько пропущенных значений, в результате чего некоторые записи были исключены из сводных таблиц, но в сумме, рассчитанной отдельно, были включены все записи. Вот почему мои цифры не совпадали. Как только я исключил записи с недостающими значениями из общего расчета, все заработало. Спасибо, что заставили меня сначала подумать о целостности данных.   -  person Tatiana    schedule 24.01.2018


Ответы (1)


Сделать это очень просто:

    import numpy as np
    import pandas as pd

    # Create table
    table_1 = np.matrix([[100, 200, 650, 950],
                         [200, 250, 350, 800],
                         [400, 500, 200, 200],
                         [700, 950, 1200, 2850]])

    column_labels = ['A', 'B', 'C', 'Region Total']
    idx_labels = ['Region 1', 'Region 2', 'Region 3', 'Product Total']

    df = pd.DataFrame(table_1)
    df.columns = column_labels
    df.index = idx_labels
    df.index.name = 'Sales'

    # Create percentage table
    df_percentage = np.round(df*100/df.iloc[-1, -1], 1)

    print(df_percentage)

                      A     B     C  Region Total
    Sales                                        
    Region 1        3.5   7.0  22.8          33.3
    Region 2        7.0   8.8  12.3          28.1
    Region 3       14.0  17.5   7.0           7.0
    Product Total  24.6  33.3  42.1         100.0
person KRKirov    schedule 16.01.2018
comment
Спасибо, что поделились этим решением. Когда я пытаюсь преобразовать сводную таблицу в фрейм данных, используя те же столбцы и индекс, которые я использовал для создания сводной таблицы, я получаю сообщение об ошибке: Несоответствие длины: ожидаемая ось имеет 7 элементов, новые значения имеют 5 элементов ... Я проверил свои данные, а не конечно, что не так .. - person Tatiana; 24.01.2018
comment
Вы пытаетесь развернуть сводную таблицу? Я не уверен, зачем вам это нужно. Суть сообщения, которое я опубликовал, заключается в том, что после создания сводной таблицы (которая также относится к типу фрейма данных) гораздо эффективнее вычислять проценты путем деления всей сводной таблицы на итоговое значение продукта, чем для достижения этого другим поворотная операция. Поскольку ProductTotal является последним элементом таблицы, его координаты равны [-1, -1], и его легко указать в математических операциях. Итак, пока работает ваша первая опорная точка, с вами, вероятно, все в порядке. - person KRKirov; 24.01.2018
comment
Если вы посмотрите на код выше, большая его часть предназначена для создания таблицы. Расчет процентов - это одна короткая строка кода: df_percentage = np.round (df * 100 / df.iloc [-1, -1], 1). Поэтому, если бы вы разместили таблицу в виде текста, я бы отправил обратно только эту строку и команду печати. - person KRKirov; 24.01.2018
comment
:) Я понимаю. Я думал, что мне нужно сначала преобразовать сводную таблицу во фрейм данных, прежде чем я смогу использовать код из последней строки. Я не понимал, что сводная таблица уже была фреймом данных. Я попробовал код на своем столе, и он отлично сработал! Это именно то, что я пытался сделать, не подсчитывая итоги вне таблицы, поскольку они у меня уже были в таблице. Итак, правильно ли я понимаю, что могу использовать df.iloc [x, y] для поиска любого значения в таблице? И могу ли я ссылаться на значения по именам строк / столбцов вместо индексов? - person Tatiana; 26.01.2018
comment
Вы действительно можете использовать df.iloc [row_index, column_index], чтобы найти любое значение во фрейме данных. И помните о нулевой индексации. -1 - это специальная координата, означающая последний элемент. Вы можете использовать метки вместо числовых координат в функции df.loc [row_label, column_label]. Стоит проверить описание этих функций, чтобы также узнать, как выбирать не только отдельные ячейки, но и диапазоны, и знать, как возвращать значения в формате серии или фрейма данных. И, пожалуйста, по возможности размещайте данные как текст, а не изображения. Или в следующий раз вам может не помочь. - person KRKirov; 26.01.2018
comment
Идеально. Это сэкономило мне много работы. Извините за изображения. Обязательно отправлю текст в следующий раз. Спасибо за твою помощь! - person Tatiana; 29.01.2018