How to group and sum rows by ID and subtract from group of rows with same ID? [python]

Viewed 39

I have the following dataframe:

    ID_A   ID_B   ID_C   Value   ID_B_Value_Sum  
-----------------------------------------------
0     22      5      1      54             208         
1     23      5      2      34             208
2     24      6      1      44             268 
3     25      6      1      64             268
4     26      5      2      35             208
5     27      7      3      45             229
6     28      7      2      66             229
7     29      8      1      76             161
8     30      8      2      25             161
9     31      6      2      27             268
10    32      5      3      14             208 
11    33      5      3      17             208
12    34      6      2      43             268
13    35      6      2      53             268
14    36      8      1      22             161
15    37      7      3      65             229
16    38      7      1      53             229 
17    39      8      2      23             161
18    40      8      3      15             161
19    41      6      3      37             268
20    42      5      2      54             208

Each row contains a unique "ID_A", while different rows can have the same "ID_B" and "ID_C". Each row corresponds to its own "Value", where this "Value" can be the same between different rows. The "ID_B_Value_Sum" column contains the sums of all values from the "Value" column for all rows containing the same "ID_B". Calculating this sum is straightforward with python and pandas.

What I want to do is, for each row, take the "ID_B_Value_Sum" column, but subtract all values corresponding to rows containing the same "ID_C", exclusive of the target row. For example, taking "ID_B" = 6, we see the sum of all the "Value" values from this "ID_B" = 6 group = 268, as shown in all corresponding rows in the "ID_B_Value_Sum" column. Now, two of the rows in this group contain "ID_C" = 1, three rows in this group contain "ID_C" = 2, and one row in this group contain "ID_C" = 3. Starting with row 2, with "ID_C" = 1, this means taking the corresponding "ID_B_Value_Sum" value and subtracting the "Value" values from all other rows containing both "ID_B" = 6 and "ID_C = 1", exclusive of the target row. And so for row 2 I take 268 - 64 = 204. And for another example, for row 4, this means 208 - 34 - 54 = 120. And another example, for row 7, this means 161 - 22 = 139. These new values will go in a new "Value_Sum_New" column for each row.

And so I want to produce the following output dataframe:

    ID_A   ID_B   ID_C   Value   ID_B_Value_Sum  Value_Sum_New
---------------------------------------------------------------
0     22      5      1      54         208                  XX   
1     23      5      2      34         208                  XX
2     24      6      1      44         268                 204
3     25      6      1      64         268                  XX
4     26      5      2      35         208                 120
5     27      7      3      45         229                  XX
6     28      7      2      66         229                  XX
7     29      8      1      76         161                 139
8     30      8      2      25         161                  XX
9     31      6      2      27         268                  XX
10    32      5      3      14         208                  XX 
11    33      5      3      17         208                  XX
12    34      6      2      43         268                  XX
13    35      6      2      53         268                  XX
14    36      8      1      22         161                  XX
15    37      7      3      65         229                  XX
16    38      7      1      53         229                  XX
17    39      8      2      23         161                  XX
18    40      8      3      15         161                  XX
19    41      6      3      37         268                  XX
20    42      5      2      54         208                  XX

What I am having trouble with conceptualizing is how to, for each row, group together all columns with the same "ID_B" and then group together all of those rows and sub-group all rows with the same "ID_C" and subtract their sum from the "Value" of the target row, but still including the "Value" from the target row, to create the final "Value_Sum_New". It seems like so many actions and sub-actions to take and I am confused with how to approach this in a simple and streamlined manner, as I am confused with how to organize and order the workflow. How might I approach calculating this sum in python?

1 Answers

IIUC, you need:

df['Value_Sum_New'] = (df['ID_B_Value_Sum']
                       - df.groupby(['ID_B', 'ID_C'])['Value'].transform('sum')
                       + df['Value']
                      )

output:

    ID_A  ID_B  ID_C  Value  ID_B_Value_Sum  Value_Sum_New
0     22     5     1     54             208            208
1     23     5     2     34             208            119
2     24     6     1     44             268            204
3     25     6     1     64             268            224
4     26     5     2     35             208            120
5     27     7     3     45             229            164
6     28     7     2     66             229            229
7     29     8     1     76             161            139
8     30     8     2     25             161            138
9     31     6     2     27             268            172
10    32     5     3     14             208            191
11    33     5     3     17             208            194
12    34     6     2     43             268            188
13    35     6     2     53             268            198
14    36     8     1     22             161             85
15    37     7     3     65             229            184
16    38     7     1     53             229            229
17    39     8     2     23             161            136
18    40     8     3     15             161            161
19    41     6     3     37             268            268
20    42     5     2     54             208            139

explanation

As you said, computing a sum per group is easy in pandas. You can actually compute ID_B_Value_Sum with:

df['ID_B_Value_Sum'] = df.groupby('ID_B')['Value'].transform('sum')

Now we do the same for groups of ID_B + ID_C, we subtract it from ID_B_Value_Sum, and as we want to exclude only the other rows in the group, we add back the row Value itself.

Related