有条件地聚合数据,同时按站点分组

问题描述 投票:0回答:1

我正在处理一个大型案例级数据集,并且对 python 是全新的。数据集通常看起来像这样:

Site          Type          Value
A              Red            10
A              Blue           15
B              Red            35
B              Yellow          5
C              Blue           45
C              Red            25

我正在尝试使用 python 自动化我们的一些流程,其中涉及聚合数据并按站点对其进行分组。我需要的输出如下所示:

Site         RedType    BlueType   YellowType    Value0-20    Value20-40    Value40+
A               1           1          0              2            0           0
B               1           0          1              1            1           0
C               1           1          0              0            1           1

基于我对到目前为止所做的事情的有限理解,我相信我偶然发现的解决方案是为我需要的每一列创建一个包含字段的字典,并将其应用为按站点分组的一部分:

def my_agg(data):
    names = {
        'RedType': data[data['Type']=="Red"]['Id'].count(),
        'BlueType': data[data['Type']=="Blue"]['Id'].count(),
        'YellowType':data[data['Type']=="Yellow"]['Id'].count(),
        'Value0-20': data[data['Value']>=0]['Id'].count() and data[data['Value']<=20]['Id'].count()
        etc........
    return pd.Series(names)

df = data.groupby('Site').apply(my_agg)

我现在知道 and 运算符不适用于值字段,但到目前为止其余操作符都有效。有没有办法使用此方法有条件地计算值(计算两个不同值之间的每种情况)?不管怎样,我是否忽略了我可以这样做的其他方式?

python pandas dataframe group-by aggregate
1个回答
1
投票

使用

cut
计算值的 bin,然后使用
melt
类型/值列,最后使用
crosstab
进行计数并展平 MultiIndex:

tmp = (df.assign(Value=lambda d: pd.cut(d['Value'],
                                        bins=[0, 20, 40, np.inf],
                                        labels=['0-20', '20-40', '40+']))
         
          .melt('Site')
      )

out = pd.crosstab(tmp['Site'], [tmp['variable'], tmp['value']])

out.columns = out.columns.map(lambda x: f'{x[0]}_{x[1]}')

out = out.reset_index()

或者,使用循环和

concat
:

index = 'Site'

# the following command modifies the original input in place
df['Value'] = pd.cut(df['Value'],
                     bins=[0, 20, 40, np.inf],
                     labels=['0-20', '20-40', '40+'])

out = pd.concat([pd.crosstab(df[index], df[col]).add_prefix(f'{col}_')
                 for col in df.columns.difference([index])],
                axis=1).reset_index()

输出:

  Site  Type_Blue  Type_Red  Type_Yellow  Value_0-20  Value_20-40  Value_40+
0    A          1         1            0           2            0          0
1    B          0         1            1           1            1          0
2    C          1         1            0           0            1          1
© www.soinside.com 2019 - 2024. All rights reserved.