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
相关产品推荐
相关产品推荐

