GR4J模型随机参数优化循环代码修正问题
原代码核心问题
- 循环逻辑完全失效:原代码用遍历数据长度的
for循环搭配多层嵌套if,判断条件写反(比如先判断1 < NSE即NSE大于1,属于不可能出现的有效值区间),导致参数更新分支根本无法正常触发 - 计算逻辑错误:参数更新分支中误将实测径流替换为降雨数据,导致指标计算完全失真;LMI公式笔误多写1个负号,计算结果错误
- 冗余代码过多:参数生成、模型运行、指标计算的相同逻辑重复编写6次,极易引入笔误
- 无效重复赋值:降雨、潜在蒸散等固定不变的输入数据,每次循环都重复赋值,浪费计算资源
修正后可直接运行的代码
import numpy as np # ---------- 固定输入数据,仅需赋值1次 ---------- rainfall = dataframe['RAINFALL'] potential_evap = dataframe['PE or ETP or Evapotrans (mm)'] true_flow = df_3['Flows (m3/s)'] # 实测径流,全程固定不变 true_flow_mean = np.mean(true_flow) # 实测径流均值提前计算,避免循环内重复运算 max_iter = 10000 # 最大迭代次数限制,防止程序无限卡死 iter_count = 0 best_params = None best_metrics = None best_sim_flow = None # ---------- 重复逻辑封装为简单函数,无复杂语法 ---------- def generate_random_params(): """生成指定取值范围内的GR4J随机参数与初始状态""" x1 = np.random.uniform(100, 1200) x2 = np.random.uniform(-5, 3) x3 = np.random.uniform(20, 300) x4 = np.random.uniform(1.1, 2.9) params = {'X1': x1, 'X2': x2, 'X3': x3, 'X4': x4} init_states = { 'production_store': 0.6 * params['X1'], 'routing_store': 0.7 * params['X3'] } return params, init_states def calc_eval_metrics(simulated, observed, obs_mean): """计算NSE、IA、LMI三项评价指标""" # 计算NSE nse = 1 - np.sum((simulated - observed)**2) / np.sum((observed - obs_mean)**2) # 计算IA ia = 1 - np.sum((observed - simulated)**2) / np.sum( (np.abs(simulated - obs_mean) + np.abs(observed - obs_mean))**2 ) # 计算LMI(修正原代码多写负号的笔误) lmi = 1 - np.sum(np.abs(simulated - observed)) / np.sum(np.abs(observed - obs_mean)) return nse, ia, lmi # ---------- 循环迭代寻优 ---------- while True: iter_count += 1 # 生成随机参数与初始状态 params, init_states = generate_random_params() # 运行GR4J模型得到模拟径流 sim_flow = gr4j(rainfall, potential_evap, params, init_states) # 计算三项评价指标 nse, ia, lmi = calc_eval_metrics(sim_flow, true_flow, true_flow_mean) # 每100次迭代打印进度,方便查看运行状态 if iter_count % 100 == 0: print(f"已迭代{iter_count}次,当前指标:NSE={nse:.3f}, IA={ia:.3f}, LMI={lmi:.3f}") # 判断是否满足终止条件:三个指标全部落在0.5~1区间 meet_threshold = (0.5 <= nse <= 1) and (0.5 <= ia <= 1) and (0.5 <= lmi <= 1) if meet_threshold: best_params = params best_metrics = (nse, ia, lmi) best_sim_flow = sim_flow print(f"\n找到符合要求的参数,共迭代{iter_count}次") print(f"参数值:X1={params['X1']:.2f}, X2={params['X2']:.2f}, X3={params['X3']:.2f}, X4={params['X4']:.2f}") print(f"指标值:NSE={nse:.3f}, IA={ia:.3f}, LMI={lmi:.3f}") break # 达到最大迭代次数则退出 if iter_count >= max_iter: print(f"\n达到最大迭代次数{max_iter}次,未找到满足阈值要求的参数,请检查参数范围或阈值设置") break
代码说明
- 没有使用复杂的类逻辑,仅将重复执行的代码块封装为两个简单函数,逻辑和原代码单段书写的逻辑完全一致,只是避免重复抄写引入笔误
- 采用
while循环实现迭代逻辑,每次循环重新生成随机参数、运行模型、计算指标,只有当三项指标同时满足阈值要求时才终止循环 - 保留了和原代码完全一致的参数取值范围、初始状态计算规则、GR4J模型调用方式、指标计算公式,仅修正了笔误
- 运行过程中会自动打印迭代进度,找到符合要求的参数后会直接输出最终参数与对应指标值
内容的提问来源于stack exchange,提问作者kiwi_kimchi
相关产品推荐
相关产品推荐

