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

Python Pandas:基于cond关联ID的时间维度分组求和优化问询

高效实现面板数据的条件关联时间维度求和

问题背景

现有如下面板数据集,包含ID、时间、数值及条件字段:

import pandas as pd
import numpy as np

df = pd.DataFrame({'id' : [1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4], 
                   'time' : [1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5],
                   'value' : [0,1,0,1,1,0,0,1,0,1,1,0,0,1,1,1,0,1,1,1]
                   }) 
cond = np.array([['A','B'],['A','C'],['C','D'],['D','E']])
df['cond'] = pd.Series(list(np.repeat(cond, repeats=[5,5,5,5], axis=0)))

需求说明

需新增一列cond_sum_by_time,按time维度对value列求和,但仅计算与当前ID的cond字段有至少一个共同元素的其他ID的value值。例如:

  • id=1的cond为[A,B],仅关联id=2(cond含A)
  • id=2的cond为[A,C],关联id=1(含A)和id=3(含C)

现有方案痛点

原始循环实现方案在大规模数据集(约20000个ID,每个ID240个时间周期)上运行耗时极长,需采用向量化/矩阵化的高效实现方式。

高效实现方案

步骤1:构建ID间的条件关联关系

先提取每个ID对应的唯一条件集合,再通过条件元素映射快速构建ID间的关联关系:

# 提取每个ID对应的唯一cond集合
id_cond = df.groupby('id')['cond'].first().apply(set)
ids = id_cond.index
n = len(ids)

# 构建条件元素到ID的映射,快速关联相关ID
from collections import defaultdict
cond_to_ids = defaultdict(list)
for idx, cond_set in id_cond.items():
    for elem in cond_set:
        cond_to_ids[elem].append(idx)

# 生成每个ID的关联ID集合(排除自身)
id_assoc = defaultdict(set)
for elem, related_ids in cond_to_ids.items():
    for id1 in related_ids:
        id_assoc[id1].update(related_ids)
for id1 in id_assoc:
    id_assoc[id1].discard(id1)

# 转换为关联矩阵(用于后续矩阵运算)
id_to_idx = {id_val: i for i, id_val in enumerate(ids)}
assoc_matrix = np.zeros((n, n), dtype=int)
for id1, related_ids in id_assoc.items():
    i = id_to_idx[id1]
    for id2 in related_ids:
        j = id_to_idx[id2]
        assoc_matrix[i, j] = 1

assoc_df = pd.DataFrame(assoc_matrix, index=ids, columns=ids)

步骤2:转换为时间×ID的宽表

将value按time和id转成宽表,每行对应一个时间点,每列对应一个ID的数值:

value_wide = df.pivot(index='time', columns='id', values='value')

步骤3:计算条件求和值

利用矩阵乘法,一次性计算所有时间点、所有ID的符合条件的求和值:

# 矩阵乘法:关联矩阵 × 宽表,得到每个时间点下各ID的求和结果
cond_sum_wide = value_wide @ assoc_df.T

步骤4:转回长表并合并到原数据集

将宽表结果转成长格式,与原数据集合并得到最终结果:

# 转换为长表格式
cond_sum_long = cond_sum_wide.unstack().reset_index(name='cond_sum_by_time')
cond_sum_long.columns = ['id', 'time', 'cond_sum_by_time']

# 合并到原始数据
result_df = pd.merge(df, cond_sum_long, on=['id', 'time'], how='left')

验证结果

输出结果与预期完全一致:

print(result_df)

输出:

id  time  value    cond  cond_sum_by_time
0    1     1      0  [A, B]                 0
1    1     2      1  [A, B]                 1
2    1     3      0  [A, B]                 1
3    1     4      1  [A, B]                 1
4    1     5      1  [A, B]                 2
5    2     1      0  [A, C]                 1
6    2     2      0  [A, C]                 1
7    2     3      1  [A, C]                 1
8    2     4      0  [A, C]                 2
9    2     5      1  [A, C]                 3
10   3     1      1  [C, D]                 2
11   3     2      0  [C, D]                 0
12   3     3      0  [C, D]                 2
13   3     4      1  [C, D]                 2
14   3     5      1  [C, D]                 3
15   4     1      1  [D, E]                 2
16   4     2      0  [D, E]                 0
17   4     3      1  [D, E]                 1
18   4     4      1  [D, E]                 2
19   4     5      1  [D, E]                 2

性能说明

该方案通过向量化运算替代循环,时间复杂度主要来自关联矩阵构建和矩阵乘法:

  • 关联矩阵构建采用条件元素映射,避免了O(n²)的全量遍历,在条件元素数量远小于ID数量时效率极高
  • 矩阵乘法利用numpy的优化实现,速度远快于Python循环,适合处理大规模时间序列数据

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 02:57:33