You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python中无循环对DataFrame按个体计算加权平均值

问题描述

现有如下DataFrame:

Individual      stop        x           y           z         time
0    23              1           20          27          4         21
1    23              2           23          24          13        63
2    1756            2           5           41          73        12
3    1756            3           7           42          72        6
4    1756            4           4.5         39          72        45
5    1756            4           3           50          73        98
6    2153            2           121         12          6         33
7    2153            3           122.5       2           6         0
8    3276            1           54          33          -12       0
9    5609            1           -2          44          -32       56
10   5609            2           8           44          -32       23
11   5609            5           102         -23         16        76

需按Individual分组,计算x、y、z列以time为权重的加权平均值,生成如下格式的新DataFrame:

Individual          bar_x       bar_y       bar_z  
0    23                  22.5        24.75       10.75
2    1756                3.72        45.96       72.68 
6    2153                121         12          6  
9    5609                50.48       11.15       24.16

此前通过循环实现,但DataFrame数据量增大时运行极慢,求基于pandas的高效解决方案。

高效解决方案

推荐使用pandas的向量化分组操作实现,避免循环带来的性能损耗,以下是两种高效实现方式:

方法一:分组聚合计算(简洁易读)

import pandas as pd

# 构造原始DataFrame(实际场景可直接读取数据)
df = pd.DataFrame({
    'Individual': [23,23,1756,1756,1756,1756,2153,2153,3276,5609,5609,5609],
    'stop': [1,2,2,3,4,4,2,3,1,1,2,5],
    'x': [20,23,5,7,4.5,3,121,122.5,54,-2,8,102],
    'y': [27,24,41,42,39,50,12,2,33,44,44,-23],
    'z': [4,13,73,72,72,73,6,6,-12,-32,-32,16],
    'time': [21,63,12,6,45,98,33,0,0,56,23,76]
})

# 按Individual分组计算加权平均,过滤time总和为0的无效分组
result = df.groupby('Individual').apply(
    lambda g: pd.Series({
        'bar_x': (g['x'] * g['time']).sum() / g['time'].sum() if g['time'].sum() != 0 else None,
        'bar_y': (g['y'] * g['time']).sum() / g['time'].sum() if g['time'].sum() != 0 else None,
        'bar_z': (g['z'] * g['time']).sum() / g['time'].sum() if g['time'].sum() != 0 else None
    })
).dropna().reset_index().round(2)

print(result)

方法二:预计算加权列(性能最优,适合大数据量)

这种方式完全基于pandas的向量化操作,避免apply的逐组处理逻辑,在数据量较大时性能提升更显著:

import pandas as pd

df = pd.DataFrame({
    'Individual': [23,23,1756,1756,1756,1756,2153,2153,3276,5609,5609,5609],
    'stop': [1,2,2,3,4,4,2,3,1,1,2,5],
    'x': [20,23,5,7,4.5,3,121,122.5,54,-2,8,102],
    'y': [27,24,41,42,39,50,12,2,33,44,44,-23],
    'z': [4,13,73,72,72,73,6,6,-12,-32,-32,16],
    'time': [21,63,12,6,45,98,33,0,0,56,23,76]
})

# 预计算各列的加权值
df['x_weighted'] = df['x'] * df['time']
df['y_weighted'] = df['y'] * df['time']
df['z_weighted'] = df['z'] * df['time']

# 分组求和
grouped = df.groupby('Individual').agg(
    x_weighted_sum=('x_weighted', 'sum'),
    y_weighted_sum=('y_weighted', 'sum'),
    z_weighted_sum=('z_weighted', 'sum'),
    time_sum=('time', 'sum')
)

# 计算加权平均并过滤无效分组
result = grouped[grouped['time_sum'] != 0].assign(
    bar_x=lambda x: x['x_weighted_sum'] / x['time_sum'],
    bar_y=lambda x: x['y_weighted_sum'] / x['time_sum'],
    bar_z=lambda x: x['z_weighted_sum'] / x['time_sum']
)[['bar_x', 'bar_y', 'bar_z']].reset_index().round(2)

print(result)

两种方法最终输出结果均与目标格式一致,且性能远优于循环实现。

内容的提问来源于stack exchange,提问作者Aleksander

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 05:40:31