Python-Pandas:优化DataFrame逐行计算速度并解决SettingWithCopyWarning
储能计算器优化方案
一、先解决SettingWithCopy警告
- 避免直接对DataFrame切片生成的视图赋值,比如不要用
df_sub = total_profile[['col1', 'col2']]后修改df_sub,改用df_sub = total_profile[['col1', 'col2']].copy()创建独立副本。 - 所有赋值操作统一使用
.loc明确指定索引,比如把total_profile['battery_charge'][i] = x改为total_profile.loc[total_profile.index[i], 'battery_charge'] = x,确保操作的是原DataFrame的真实数据而非视图。
二、循环提速:用Numba加速逐行计算
由于计算依赖前一行的储能状态,属于有状态迭代计算,普通Python循环在大DataFrame上效率极低,用Numba的JIT编译可将循环速度提升几十倍,轻松实现耗时降低90%的目标。
步骤1:提取输入数组
将DataFrame中需要参与计算的列转换为numpy数组,Numba对numpy数组的处理效率远高于原生DataFrame:
import numba import numpy as np import pandas as pd # 假设你的DataFrame包含以下核心列 solar = total_profile['solar_generation'].values load = total_profile['load_demand'].values max_capacity = total_profile['battery_capacity'].values # 若容量固定,可直接设为标量 initial_charge = 0.0 # 初始储能电量 # 预先分配输出数组内存,避免动态扩容耗时 battery_charge = np.zeros_like(solar) excess_solar = np.zeros_like(solar)
步骤2:编写Numba加速函数
@numba.jit(nopython=True) # nopython模式是Numba最快的运行模式 def calculate_storage(solar, load, max_capacity, initial_charge): n = len(solar) charge = np.zeros(n) excess = np.zeros(n) current_charge = initial_charge for i in range(n): net = solar[i] - load[i] if net > 0: # 有多余太阳能,存入储能(受剩余容量限制) possible_charge = min(net, max_capacity[i] - current_charge) charge[i] = current_charge + possible_charge excess[i] = net - possible_charge else: # 无多余太阳能,维持或消耗储能(可根据实际逻辑调整) charge[i] = current_charge + net excess[i] = 0 current_charge = charge[i] return charge, excess
步骤3:运行计算并回写DataFrame
# 执行加速计算 battery_charge, excess_solar = calculate_storage(solar, load, max_capacity, initial_charge) # 用.loc回写结果,彻底规避警告 total_profile.loc[:, 'battery_charge'] = battery_charge total_profile.loc[:, 'excess_solar'] = excess_solar
三、备选方案:用pandas expanding.apply(适合简单逻辑)
如果计算逻辑相对简单,也可以用expanding.apply结合状态变量实现,效率虽略低于Numba,但远快于普通循环:
def storage_step(state, row): current_charge, max_cap = state net = row['solar_generation'] - row['load_demand'] if net > 0: add = min(net, max_cap - current_charge) new_charge = current_charge + add excess = net - add else: new_charge = current_charge + net excess = 0 return new_charge, excess # 初始化状态 initial_state = (0.0, total_profile['battery_capacity'].iloc[0]) # 逐行迭代计算 results = total_profile.expanding().apply(lambda x: storage_step(initial_state, x.iloc[-1]), axis=1) # 拆分结果并回写DataFrame total_profile[['battery_charge', 'excess_solar']] = pd.DataFrame(results.tolist(), index=total_profile.index)
关键注意事项
- Numba的
nopython=True模式要求函数内仅使用Numba支持的语法和对象,因此要避免在函数内操作pandas对象,统一用numpy数组。 - 若储能有充放电效率、最低容量限制等额外逻辑,可直接在Numba函数内修改,不影响加速效果。
- 所有DataFrame赋值操作坚持用
.loc,彻底消除SettingWithCopy警告。
内容的提问来源于stack exchange,提问作者Janne Hirvonen
相关产品推荐
相关产品推荐

