Long time listener; First time caller :)
I have the following dataframe:
df = pd.DataFrame({'a':['a1','a1','a1','a2','a2','a3','a3','a3','a3'],
'cat1':['C','D','D','C','D','D','D','D','C'],
'cat2':['X','Y','X','Y','X','Y','X','Y','X'],
'is':[1,2,3,1,2,1,2,3,4],
'fs':[.1,.2,.3,.1,.2,.1,.2,.3,.4]})
giving:
a cat1 cat2 is fs
0 a1 C X 1 0.1
1 a1 D Y 2 0.2
2 a1 D X 3 0.3
3 a2 C Y 1 0.1
4 a2 D X 2 0.2
5 a3 D Y 1 0.1
6 a3 D X 2 0.2
7 a3 D Y 3 0.3
8 a3 C X 4 0.4
I am looking to group the dataframe in such a way that it gives the below output, where each row is first grouped by the value in column a, then the numeric columns of the dataframe are aggregated (sum, mean, etc) based on category -- cat1 and cat2.
a sum(is|cat1=C) sum(fs|cat1=C) sum(is|cat1=D) sum(fs|cat1=D) sum(is|cat2=X) sum(fs|cat2=X) sum(is|cat2=Y) sum(fs|cat2=Y)
0 a1 1 0.1 5 0.5 4 0.4 2 0.2
1 a2 1 0.1 2 0.2 2 0.2 1 0.1
2 a3 4 0.4 6 0.6 6 0.6 4 0.4
For example, in row 0 above, sum(is|cat1=D) is the sum of is values for a1 when cat1 = D. Hope this is clear enough. Happy to further clarify.
Here's the best I'm able to do so far:
output = []
aggregations = ['sum']
for category in ['cat1', 'cat2']:
num_data = df.select_dtypes('number')
grouped = df.groupby(['a', category]).agg({'is':'sum', 'fs':'sum'})
flattened = pd.DataFrame(grouped.to_records())
flattened.columns = ['a', category] + ['%s(%s|%s)' % (op, column, category)
for column in list(num_data.columns) for op in aggregations]
output.append(flattened)
output[0] looks something like this:
a cat1 sum(is|cat1) sum(fs|cat1)
0 a1 C 1 0.1
1 a1 D 5 0.5
2 a2 C 1 0.1
3 a2 D 2 0.2
4 a3 C 4 0.4
5 a3 D 6 0.6
which is obviously some ways off. I can't figure out how to further flatten it and rename the sum headers appropriately. Also, I don't know how to include cat2-based aggregation in the results.
Thanks!