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

Python循环执行过慢问题求助(附完整代码)

优化Python循环性能:处理23000行CSV的高效方案

嘿,我看了你这段代码,慢的根源其实很明确——你在循环里反复调用DataFrame.append(),这玩意儿每次都会创建一个全新的DataFrame对象,23000次下来内存开销和时间成本简直爆炸!咱们来一步步优化,让速度直接起飞:

核心优化点1:彻底抛弃循环中的DataFrame.append()

append()是性能杀手,尤其是在大规模循环里。我们改用列表收集数据,最后一次性转成DataFrame,这能把速度提升几十倍甚至上百倍。

优化后的目标循环代码

# 先准备空列表收集所有数据字典
data_list = []
for i in range(A_size):
    # 这里建议用.iloc[i]来定位行,比直接用[i]更稳定
    lat = A['Latitude'].iloc[i]
    lon = A['Longitude'].iloc[i]
    x1 = float(fn_CalcParcelID(lat, ParcelSize)) / 100000
    x2 = float(fn_CalcParcelID(lon, ParcelSize)) / 100000
    
    data_list.append({
        'Lat': x1,
        'Lon': x2,
        'PSC': A['PSC'].iloc[i],
        'UARFCN': UARFCN,
        'SC_Avg_EcNo': A['EcNo'].iloc[i],
        'SC_Avg_RSCP': A['RSCP'].iloc[i]
    })

# 最后一次性生成DataFrame,只创建一次对象
B1 = pd.DataFrame(data_list)
B1.to_csv('B1.csv', index=False)  # index=False可以减少文件体积和写入时间

核心优化点2:矢量化处理ParcelID计算(彻底干掉循环)

既然用了pandas,就要发挥它的矢量化优势!把fn_CalcParcelID改成支持整个Series的函数,完全不用逐行循环:

矢量化版本的ParcelID函数

import numpy as np

def fn_CalcParcelID_vec(Pos_series, ParcelUnitSize):
    # 用numpy.where实现矢量化条件判断,比逐行快N倍
    result = np.where(
        Pos_series == 500,
        50000000,
        np.where(
            Pos_series < 0,
            (Pos_series * 100000).astype(int) - ParcelUnitSize + ((Pos_series * 100000).astype(int) % ParcelUnitSize),
            (Pos_series * 100000).astype(int) - ((Pos_series * 100000).astype(int) % ParcelUnitSize)
        )
    )
    return result.astype(int)

# 直接对整个列计算,完全不需要循环!
A['Parcel_Lat'] = fn_CalcParcelID_vec(A['Latitude'], ParcelSize) / 100000
A['Parcel_Lon'] = fn_CalcParcelID_vec(A['Longitude'], ParcelSize) / 100000

# 直接构造B1,一行代码搞定
B1 = pd.DataFrame({
    'Lat': A['Parcel_Lat'],
    'Lon': A['Parcel_Lon'],
    'PSC': A['PSC'],
    'UARFCN': UARFCN,
    'SC_Avg_EcNo': A['EcNo'],
    'SC_Avg_RSCP': A['RSCP']
})
B1.to_csv('B1.csv', index=False)

这个版本的速度会比循环快几个数量级,因为numpy的矢量化操作是用C语言实现的,远快于Python层面的逐行循环。

额外优化:拆分Top1-Top9的代码也可以提速

你前面拆分A1到A9的循环同样存在append的性能问题,用pandas的melt和pivot可以彻底替代手动循环:

# 把宽表转成窄表,自动拆分所有Top1-Top9的数据
id_vars = ['Latitude', 'Longitude']
# 定义需要转换的列名模板
value_vars = []
for n in range(1, 10):
    value_vars.extend([
        f'PSC: Top #{n} (UARFCN #01)',
        f'Sc Aggr Ec/Io (dB): Top #{n} (UARFCN #01)',
        f'Sc Aggr Ec (dBm): Top #{n} (UARFCN #01)'
    ])

# 用melt展开数据
melted = scanner.melt(id_vars=id_vars, value_vars=value_vars, var_name='Metric', value_name='Value')
# 提取Top编号和指标类型
melted['Top'] = melted['Metric'].str.extract(r'Top #(\d+)')
melted['Metric_Type'] = melted['Metric'].str.replace(r': Top #\d+ \(UARFCN #01\)', '', regex=True)
melted['Metric_Type'] = melted['Metric_Type'].map({
    'PSC': 'PSC',
    'Sc Aggr Ec/Io (dB)': 'EcNo',
    'Sc Aggr Ec (dBm)': 'RSCP'
})

# 透视回宽表,得到每个样本的PSC/EcNo/RSCP
pivoted = melted.pivot_table(
    index=['Latitude', 'Longitude', 'Top'],
    columns='Metric_Type',
    values='Value',
    aggfunc='first'
).reset_index()

# 过滤掉PSC为-1的行
pivoted = pivoted[pivoted['PSC'] != -1]
# 合并所有Top数据,去重
A = pivoted.drop('Top', axis=1)
A = A[~A.apply(frozenset, axis=1).duplicated()]
A.to_csv('table_data_pilot.csv', index=False)

总结优化思路

  1. 避免循环中修改DataFrame:append/concat在循环里会不断复制数据,改用列表或矢量化操作
  2. 优先用矢量化函数:pandas/numpy的内置函数都是C级别的速度,远快于Python循环
  3. 宽表转窄表用melt/pivot:替代手动拆分列的循环,代码更简洁且高效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 14:59:13