如何使用scipy.minimize仅优化自定义函数指定参数最小化返回值
问题解决方法
scipy.optimize.minimize本身就支持固定部分参数、只优化指定参数的场景,不需要修改你原有的优化器函数,核心是做一层参数适配封装,同时处理days为整型的特殊要求。
核心实现逻辑
- 把所有不需要调整的固定入参提前打包,通过闭包方式绑定,不需要传入minimize
- 把所有待优化的参数(
weights列表的所有元素 +days)拼接成一维数组,作为minimize唯一接收的待优化变量 - 由于scipy大部分内置优化器针对连续浮点值设计,对整型参数
days,要么在目标函数内部做取整处理,要么直接选用支持混合整数优化的全局优化器
可直接复用的代码示例
首先修正你原函数里的明显笔误(形参名和调用名不一致、循环覆盖外层变量、未定义变量),再做优化适配:
import numpy as np import pandas as pd from scipy.optimize import minimize from typing import List, Callable # 修正笔误后的原目标计算函数 def optimizer( df_grouped, df: pd.DataFrame, weights: List[float], my_func: Callable, days: int, day_str: str, df_all: pd.DataFrame ): all_scores = {} # 原代码未定义df_day,这里按常规时间切片逻辑补全,可根据你的实际业务调整 df_day = df[df["date"] <= day_str].tail(days) for i, sub_df in enumerate(df_grouped): scores = my_func(df_day=df_day, df=sub_df, weights=weights) all_scores[i] = scores avg_vals = np.mean([df_all.loc[key]["val1"] for key in all_scores], axis=0) # 原代码未定义day_to_compare,这里按传入的目标日期补全 truth_vals = df_all.loc[day_str]["val1"] score = np.mean(abs(avg_vals - truth_vals), axis=0) return score # 封装适配minimize的目标函数,绑定固定参数 def build_target(fixed_params: dict): def calc_loss(x): # x为一维待优化数组:前N位对应weights元素,最后1位对应days weights = x[:-1] days = int(round(x[-1])) # 对连续优化结果做整数转换 return optimizer( df_grouped=fixed_params["df_grouped"], df=fixed_params["df"], weights=weights, my_func=fixed_params["my_func"], days=days, day_str=fixed_params["day_str"], df_all=fixed_params["df_all"] ) return calc_loss if __name__ == "__main__": # 1. 填入所有固定参数的实际值 fixed_params = { "df_grouped": your_actual_df_grouped, "df": your_actual_df, "my_func": your_actual_my_func, "day_str": your_target_day_str, "df_all": your_actual_df_all } # 2. 设置待优化参数初始值:[w1,w2,w3,w4, initial_days] x0 = [1, 10, 30, 40, 7] # 3. 设置参数边界(根据业务规则调整,示例为权重非负、days在1-30区间) bounds = [ (0, None), (0, None), (0, None), (0, None), (1, 30) ] # 4. 初始化目标函数执行优化 target_func = build_target(fixed_params) res = minimize( fun=target_func, x0=x0, bounds=bounds, method="L-BFGS-B" ) # 解析最优结果 best_weights = res.x[:-1] best_days = int(round(res.x[-1])) best_score = res.fun print(f"最优权重:{best_weights}\n最优天数:{best_days}\n最小score:{best_score}")
关键注意点
- 参数边界可以根据实际业务调整,比如限制权重和为1、days不超过数据集最长时间跨度,避免优化出无意义的参数值
- 如果
days取值跨度大、对结果影响敏感,不建议用连续优化器加手动取整的方案,可以替换成scipy.optimize.differential_evolution,该方法支持通过integrality参数指定哪些维度是整数变量,不需要手动取整,全局寻优能力也更强 - 这类评分优化问题大多是非凸的,不要只跑一组初始值,建议多换几组初始权重和初始days尝试,避免陷入局部最优
内容的提问来源于stack exchange,提问作者Denver Dang
相关产品推荐
相关产品推荐

