将字典传递给 `scipy.optimize.least_squares`
Passing a dictonary to `scipy.optimize.least_squares`
我有几个在外部库中定义的函数。我无法更改这些函数的参数或内容。以下面的函数为例(虽然原来的要复杂得多):
def func1(info: dict) -> float:
return 1 - (1.5 * info["b"] - info["a"])
def func2(info: dict) -> float:
return 1 - (np.exp(info["c"]) - info["a"])
我有一个初步猜测,我正在尝试应用 scipy.optimize.least_squares
来找到最佳值以最小化 func1
或 func2
(不是同时),即目标是这样的
import scipy
def func1(info: dict) -> float:
return 1 - (1.5 * info["b"] - info["a"])
def func2(info: dict) -> float:
return 1 - (np.exp(info["c"]) - info["a"])
initial_dict = {"a" : 5, "b" : 7}
result = scipy.optimize.least_squares(func1, initial_dict)
initial_dict["c"] = 3
result2 = scipy.optimize.least_squares(func1, initial_dict)
问题是 least_squares
只接受 floats
,而不接受 dicts
。我认为可以将 dict 的值转换为列表并编写一个“包装器”函数,将列表转换回 dict,即
def func1_wrapped(lst: list[float]) -> float:
a, b, c = lst
tmp_dict = {"a" : a, "b": b, "c": c}
return func1(tmp_dict)
result1 = scipy.optimize.least_squares(func1_wrapped,[5, 7, 3])
这样合理吗?有更好、更有效的方法吗?
一种可能的换行方式是
import scipy.optimize
import numpy as np
def dict_least_squares(fn, dict0, *args, **kwargs):
keys = list(dict0.keys());
result = scipy.optimize.least_squares(
lambda x: fn({k:v for k,v in zip(keys, x)}), # wrap the argument in a dict
[dict0[k] for k in keys], # unwrap the initial dictionary
*args, # pass position arguments
**kwargs # pass named arguments
)
# wrap the solution in a dictionary
try:
result.x = {k:v for k,v in zip(keys, result.x)}
except:
pass;
return result;
这通过转发任意位置参数 *args
或命名参数 **kwargs
.
来维护原始最小二乘函数的接口
使用示例
def func1(info: dict) -> float:
return 1 - (1.5 * info["b"] - info["a"])
initial_dict = {"a" : 5, "b" : 7}
dict_least_squares(func1, initial_dict)
给予
active_mask: array([0., 0.])
cost: 1.2378255801353088e-15
fun: array([4.97559158e-08])
grad: array([ 4.97559158e-08, -7.46338734e-08])
jac: array([[ 1. , -1.49999999]])
message: '`xtol` termination condition is satisfied.'
nfev: 37
njev: 16
optimality: 7.463387344664022e-08
status: 3
success: True
x: {'a': 6.384615399632931, 'b': 4.92307689991801}
然后
def func2(info: dict) -> float:
return 1 - (np.exp(info["c"]) - info["a"])
initial_dict["c"] = 3
dict_least_squares(func2, initial_dict)
给予
active_mask: array([0., 0., 0.])
cost: 4.3463374554994224e-17
fun: array([-9.32345157e-09])
grad: array([-9.32345157e-09, 0.00000000e+00, 2.12348517e-11])
jac: array([[ 1. , 0. , -0.00227757]])
message: '`gtol` termination condition is satisfied.'
nfev: 41
njev: 20
optimality: 9.323451566345398e-09
status: 1
success: True
x: {'a': -0.9977224357504928, 'b': 7.0, 'c': -6.0846446250890684}
我有几个在外部库中定义的函数。我无法更改这些函数的参数或内容。以下面的函数为例(虽然原来的要复杂得多):
def func1(info: dict) -> float:
return 1 - (1.5 * info["b"] - info["a"])
def func2(info: dict) -> float:
return 1 - (np.exp(info["c"]) - info["a"])
我有一个初步猜测,我正在尝试应用 scipy.optimize.least_squares
来找到最佳值以最小化 func1
或 func2
(不是同时),即目标是这样的
import scipy
def func1(info: dict) -> float:
return 1 - (1.5 * info["b"] - info["a"])
def func2(info: dict) -> float:
return 1 - (np.exp(info["c"]) - info["a"])
initial_dict = {"a" : 5, "b" : 7}
result = scipy.optimize.least_squares(func1, initial_dict)
initial_dict["c"] = 3
result2 = scipy.optimize.least_squares(func1, initial_dict)
问题是 least_squares
只接受 floats
,而不接受 dicts
。我认为可以将 dict 的值转换为列表并编写一个“包装器”函数,将列表转换回 dict,即
def func1_wrapped(lst: list[float]) -> float:
a, b, c = lst
tmp_dict = {"a" : a, "b": b, "c": c}
return func1(tmp_dict)
result1 = scipy.optimize.least_squares(func1_wrapped,[5, 7, 3])
这样合理吗?有更好、更有效的方法吗?
一种可能的换行方式是
import scipy.optimize
import numpy as np
def dict_least_squares(fn, dict0, *args, **kwargs):
keys = list(dict0.keys());
result = scipy.optimize.least_squares(
lambda x: fn({k:v for k,v in zip(keys, x)}), # wrap the argument in a dict
[dict0[k] for k in keys], # unwrap the initial dictionary
*args, # pass position arguments
**kwargs # pass named arguments
)
# wrap the solution in a dictionary
try:
result.x = {k:v for k,v in zip(keys, result.x)}
except:
pass;
return result;
这通过转发任意位置参数 *args
或命名参数 **kwargs
.
使用示例
def func1(info: dict) -> float:
return 1 - (1.5 * info["b"] - info["a"])
initial_dict = {"a" : 5, "b" : 7}
dict_least_squares(func1, initial_dict)
给予
active_mask: array([0., 0.])
cost: 1.2378255801353088e-15
fun: array([4.97559158e-08])
grad: array([ 4.97559158e-08, -7.46338734e-08])
jac: array([[ 1. , -1.49999999]])
message: '`xtol` termination condition is satisfied.'
nfev: 37
njev: 16
optimality: 7.463387344664022e-08
status: 3
success: True
x: {'a': 6.384615399632931, 'b': 4.92307689991801}
然后
def func2(info: dict) -> float:
return 1 - (np.exp(info["c"]) - info["a"])
initial_dict["c"] = 3
dict_least_squares(func2, initial_dict)
给予
active_mask: array([0., 0., 0.])
cost: 4.3463374554994224e-17
fun: array([-9.32345157e-09])
grad: array([-9.32345157e-09, 0.00000000e+00, 2.12348517e-11])
jac: array([[ 1. , 0. , -0.00227757]])
message: '`gtol` termination condition is satisfied.'
nfev: 41
njev: 20
optimality: 9.323451566345398e-09
status: 1
success: True
x: {'a': -0.9977224357504928, 'b': 7.0, 'c': -6.0846446250890684}