Преобразовать pandas групповой результат с промежуточными итогами в относительные значения - PullRequest
3 голосов
/ 21 января 2020

Я нашел хорошее решение для вставки промежуточных итогов в pandas групповой фрейм данных. Однако теперь я хотел бы изменить результат, чтобы показывать относительные значения по отношению к промежуточным итоговым значениям вместо абсолютных значений.

Это код для отображения группы:

import pandas as pd
import numpy as np

df = pd.DataFrame(
    {
        "Category": np.random.choice(["Group A", "Group B"], 50),
        "Product": np.random.choice(["Product 1", "Product 2"], 50),
        "Units_Sold": np.random.randint(1, 100, size=(50)),
        "Date": np.random.choice(
            pd.date_range("1/1/2011", "03/31/2011", freq="D"), 50, replace=False
        ),
    }
)

iList = ["Category", "Product"]

pvt = pd.concat(
    [df.assign(**{x: "" for x in iList[i:]}).groupby(iList).sum() for i in range(1, 3)]
).sort_index()

print(pvt)

что приводит к

                    Units_Sold
Category Product              
Group A                   1170
         Product 1         434
         Product 2         736
Group B                    980
         Product 1         437
         Product 2         543

Я пробовал что-то вроде

pvt.transform(lambda x: (round(x / x['Group A', ''],2)*100).astype(int).astype(str)+"%")

, но очевидно, что это только вычисляет значения относительно первой строки.

Что я смотрю for is

                    Units_Sold
Category Product              
Group A                   100%
         Product 1         37%
         Product 2         63%
Group B                   100%
         Product 1         45%
         Product 2         55%

Большое спасибо!

1 Ответ

4 голосов
/ 21 января 2020

Используйте GroupBy.apply на первом уровне MultiIndex с лямбда-функцией:

f = lambda x: (x / x.iloc[0]).mul(100).round(2).astype(int).astype(str)+"%"
df = pvt.groupby(level=0).apply(f)
print (df)
                   Units_Sold
Category Product             
Group A                  100%
         Product 1        49%
         Product 2        50%
Group B                  100%
         Product 1        52%
         Product 2        47%

Или используйте GroupBy.transform с GroupBy.first:

df = (pvt.div(pvt.groupby(level=0).transform('first'))
         .mul(100)
         .round(2)
         .astype(int)
         .astype(str)+"%")
print (df)

                   Units_Sold
Category Product             
Group A                  100%
         Product 1        43%
         Product 2        56%
Group B                  100%
         Product 1        58%
         Product 2        41%
...