Pandas 计算给定多个条件的多列总和

Pandas Calculate Sum of Multiple Columns Given Multiple Conditions

我有一个宽 table 格式如下(最多 10 人):

person1_status | person2_status | person3_status | person1_type | person_2 type | person3_type 
       0       |        1       |        0       |        7     |        4      |        6  

其中 status 可以是 0 或 1(前 3 列)。

其中 type 可以是 4-7 之间的#。这里的值对应另一个table,根据类型指定一个值。所以...

Type | Value
 4   |   10
 5   |   20
 6   |   30
 7   |   40

我需要计算两列,'A' 和 'B',其中:

  1. A 是每个人的类型(在该行中)的值的 sum,其中 状态 = 0。
  2. B 是每个人的类型(在该行中)的值的 sum,其中 状态 = 1.

例如,结果列 'A' 和 'B' 将如下所示:

A  | B
70 | 10

对此的解释:

'A' 的值为 70,因为 person1 和 person3 的 "status" 为 0,对应的类型为 7 和 6(对应值 30 和 40)。

同样,应该有另一列 'B' 的值为“10”,因为只有 person2 的状态为“1”且其类型为“4”(对应值为 10)。

这可能是一个愚蠢的问题,但我如何以矢量化的方式做到这一点?我不想使用 for 循环或任何东西,因为它会降低效率...

我希望这是有道理的...有人可以帮助我吗?我想我在想办法解决这个问题时已经脑残了。

对于更简单的计算列,我只是 np.where 但我有点卡在这里,因为我需要在给定特定条件的情况下计算多个列的值的总和,同时从分开 table...

希望有意义

使用 filter 方法过滤其中出现字符串的列名称。

为查找值创建数据框other_table并将索引设置为类型列。

df_status = df.filter(like = 'status')
df_type = df.filter(like = 'type')
df_type_lookup = df_type.applymap(lambda x: other_table.loc[x]).values

df['A'] = np.sum((df_status == 0).values * df_type_lookup, 1)
df['B'] = np.sum((df_status == 1).values * df_type_lookup, 1)

完整示例如下:

创建虚假数据

df = pd.DataFrame({'person_1_status':np.random.randint(0, 2,1000) , 
                   'person_2_status':np.random.randint(0, 2,1000), 
                   'person_3_status':np.random.randint(0, 2,1000), 
                   'person_1_type':np.random.randint(4, 8,1000), 
                   'person_2_type':np.random.randint(4, 8,1000),
                   'person_3_type':np.random.randint(4, 8,1000)},
                 columns= ['person_1_status', 'person_2_status', 'person_3_status',
                           'person_1_type', 'person_2_type', 'person_3_type'])

 person_1_status  person_2_status  person_3_status  person_1_type  \
0                1                0                0              7   
1                0                1                0              6   
2                1                0                1              7   
3                0                0                0              7   
4                0                0                1              4   

   person_3_type  person_3_type  
0              5              5  
1              7              7  
2              7              7  
3              7              7  
4              7              7 

制作other_table

other_table = pd.Series({4:10, 5:20, 6:30, 7:40})

4    10
5    20
6    30
7    40
dtype: int64

将状态和类型列过滤到它们自己的数据框中

df_status = df.filter(like = 'status')
df_type = df.filter(like = 'type')

进行查找table

df_type_lookup = df_type.applymap(lambda x: other_table.loc[x]).values

跨行应用矩阵乘法和求和。

df['A'] = np.sum((df_status == 0).values * df_type_lookup, 1)
df['B'] = np.sum((df_status == 1).values * df_type_lookup, 1)

输出

 person_1_status  person_2_status  person_3_status  person_1_type  \
0                0                0                1              7   
1                0                1                0              4   
2                0                1                1              7   
3                0                1                0              6   
4                0                0                1              5   

   person_2_type  person_3_type   A   B  
0              7              5  80  20  
1              6              4  20  30  
2              5              5  40  40  
3              6              4  40  30  
4              7              5  60  20  

考虑数据帧df

mux = pd.MultiIndex.from_product([['status', 'type'], ['p%i' % i for i in range(1, 6)]])
data = np.concatenate([np.random.choice((0, 1), (10, 5)), np.random.rand(10, 5)], axis=1)
df = pd.DataFrame(data, columns=mux)
df

我们可以为type == 1

这样做的结构方式
df.status.mul(df.type).sum(1)

0    0.935290
1    1.252478
2    1.354461
3    1.399357
4    2.102277
5    1.589710
6    0.434147
7    2.553792
8    1.205599
9    1.022305
dtype: float64

type == 0

df.status.rsub(1).mul(df.type).sum(1)

0    1.867986
1    1.068045
2    0.653943
3    2.239459
4    0.214523
5    0.734449
6    1.291228
7    0.614539
8    0.849644
9    1.109086
dtype: float64

您可以使用以下代码获取此格式的列

df.columns = df.columns.str.split('_', expand=True)
df = df.swaplevel(0, 1, 1)