优化等效Excel SUMIFS功能的Python脚本以缩短执行时间
问题背景
我正尝试复现Excel中的SUMIFS函数功能,对应公式近似为:accumulation1 =SUMIFS(value; $fin$1:$fin$5; ini$1)。该公式的作用是查找并累加end列表中与对应ini匹配的value值。
计算示例:id3的accumulation1取值逻辑为,查找ini=11对应endPoint的value值,即id1和id5的value之和(3+5=8)。
后续我需要新增累加列并重复该计算逻辑,总计要执行1004次,用于河网路径遍历取值计算。
示例数据
| id | ini | fin | value | accumulation1 | accumulation2 | sumOfAccumulation |
|---|---|---|---|---|---|---|
| 1 | 10 | 11 | 5 | 0 | 0 | 5 |
| 2 | 9 | 10 | 0 | 0 | 0 | 0 |
| 3 | 11 | 12 | 2 | 8 | 0 | 10 |
| 4 | 12 | 13 | 1 | 2 | 8 | 11 |
| 5 | 05 | 11 | 3 | 0 | 0 | 3 |
现有代码
connection = psycopg2.connect(dbname=DB_NAME,user=DB_USER, password=DB_PWD, host=DB_HOST, port=DB_PORT) cursor = connection.cursor(cursor_factory=psycopg2.extras.DictCursor) data = pdsql.read_sql_query("select id_bdcarth, id_nd_ini::int ini, id_nd_fin::int fin, v from tempturbi.tmp_somme_v19",connection) Endtest=1 #loop until Endtest = 0 : #create a new column accumulation for i in data.ini: acc=[] acc=data.v.loc[data.fin==i] # get values of the upstream segments acc=sum(acc) #save acc in accumulation Endtest=data.sum(accumulation) print("--- %s seconds ---" % (time.time() - start_time))
河网示意图

性能优化方案
- 替换逐行循环逻辑为pandas向量化操作:原代码中for循环遍历每个ini值、再逐行匹配fin的写法时间复杂度为O(n²),可以先按fin分组计算value的总和,再用map映射到ini列上,单次计算复杂度直接降到O(n),仅这一项优化就能把129秒的耗时压缩到秒级。示例代码:
# 预计算每个fin对应的value总和 fin_sum = data.groupby('fin')['v'].sum() # 直接映射得到当前轮次的accumulation列 data[f'accumulation_{step}'] = data['ini'].map(fin_sum).fillna(0)
- 避免重复创建列存储中间结果:如果不需要留存每一步的accumulation值,直接更新v列作为下一轮计算的输入即可,减少内存占用和写入开销。
- 数据库层面提前计算:如果数据量超过10万行,直接在PostgreSQL中用递归CTE完成河网的路径累加计算,比拉取到本地用pandas处理快3-10倍,递归CTE天然适配有向无环的河网遍历场景。
- 替换原生sum函数:原代码中用Python内置sum处理pandas序列,直接用pandas自带的
.sum()方法速度更快,因为底层是C实现。
内容的提问来源于stack exchange,提问作者SCH kiman
相关产品推荐
相关产品推荐

