I have a df
df = pd.DataFrame({'group':['A','A','A','A','A',
'B','B','B','B','B',
'C','C','C','C','C'],
'category': ['zero','first', 'second', 'first second', 'total',
'zero', 'first', 'second', 'first second', 'total',
'zero','first', 'second', 'first second', 'total'],
'sales': [50,100,75,175,225,
5,10,15,25,30,
1000,2000,3000,3000,4000]})
I am trying to calculate the % of each category inside a group, the problem is that category first second and total is a sum of previous categories and should not be taken in to calculations.
I tried:
df['%'] = (df['sales'] / df.groupby(['group'])['sales'].transform('sum')) * 100
But now total is only 36% where it should be 100% and then then whole percentages are wrong.
If I isolate the groups like so:
my_df['%_v2'] =(my_df['sales'] / my_df[my_df.category.isin(['zero', 'first', 'second'])].groupby(['group'])['sales'].transform('sum')) * 100
Then zero, first, second % are correct, but I get nan in first second and total:
Instead of nan I would like to get the percentages of (175/225) * 100 for first second and 225/225 for total.
CodePudding user response:
Idea is replace not matched values by NaN in Series.where:
s = (df['sales'].where(df.category.isin(['zero', 'first', 'second']))
.groupby(df['group'])
.transform('sum'))
df['%'] = df['sales'].div(s).mul(100)
print (df)
group category sales %
0 A zero 50 22.222222
1 A first 100 44.444444
2 A second 75 33.333333
3 A first second 175 77.777778
4 A total 225 100.000000
5 B zero 5 16.666667
6 B first 10 33.333333
7 B second 15 50.000000
8 B first second 25 83.333333
9 B total 30 100.000000
10 C zero 1000 16.666667
11 C first 2000 33.333333
12 C second 3000 50.000000
13 C first second 3000 50.000000
14 C total 4000 100.000000

