有没有一种方法可以将scipy.optimize.mimize与2D np数组作为x0使用



我是python提供的优化技术的新手,我找不到如何调整optimize.mimize以满足我的需求。

我想做的是通过改变利率来最小化给定债券组的市场价格和模型价格之间的平方差之和(因此利率将是我的x0(。这个总和是通过price_eval计算的,它以几个列表或嵌套列表作为参数,例如每个债券的现金流金额的嵌套列表。为了更清楚地说明后者——如果我有3个债券,它们有3、2和4个未来现金流,比如a、b、c;d、 e;h;i;jk,其中一个自变量将是列表CF_list=[[a,b,c],[d,e],[h;i;j;kl]]。

这里有一个函数:

def price_eval(rates_list, ttm_list, price_list, CF_list, CF_time_list, N_cf_list):
price_model_list = []
sum_squares = 0
for i in range(0, len(price_list)):

price = 0
number_cf_per_bond = N_cf_list[i]

for j in range(0, number_cf_per_bond):

price += (CF_list[i][j]) / math.pow(1+rates_list[i][j],CF_time_list[i][j])

diff = price_model_list[i] - price_list[i]
sum_squares += math.pow(diff,2)
return sum_squares

我试图将求解器定义为

res = scipy.optimize.minimize(price_eval, rates_guess, args=(ttm_list, price_list, CF_list, CF_time_list, N_cf_list))

其中,我提供嵌套列表rates_guess作为求解器rates_list[I][j]的初始猜测(无论我是否将其更改为numpy数组,都不会产生相同的结果(。整个问题可能来自这样一个事实,即scipy.optimize.miminime只将一维数组作为x0,而在我的情况下,由于每个债券每个现金流存储的数据,x0需要是二维的。我收到一个错误

...
grad[k] = (f(*((xk + d,) + args)) - f0) / d[k]
TypeError: can only concatenate list (not "float") to list

所以,我的问题是,是否有人知道如何解决这个问题?或者,是否有可能以某种方式调整解算器,我可以提供一个嵌套列表/2D np数组作为x0,该数组应该以相同格式用新值返回?如果没有,我还能做什么?

非常感谢您的帮助!

rates_listrates_guess都需要是1d数组/列表。我通常处理这个问题的方法是使用函数将你喜欢的结构扁平化为一个列表,并将其"膨胀"回所需的形状。例如,你可以有这样的

def to_flat(nested_list):
'''
flatten a list of lists
'''
flat_list = []
for l in nested_list:
for e in l:
flat_list.append(e)
return flat_list
# test
rates_nested_list = [[1,1,1],[2,2],[3,3,3,3]]
rates_flat_list = to_flat(rates_nested_list)
print('flat: ',rates_flat_list)
def from_flat(flat_list, list_to_copy_shape_from):
''' 
here the second argument is a nested list in the desired shape -- values not relevant only shape
'''
nested_list = []
idx = 0
for l in list_to_copy_shape_from:
nested_list.append([])
for e in l:
nested_list[-1].append(flat_list[idx])
idx += 1
return nested_list
# test
template = [[0,0,0],[0,0],[0,0,0,0]]
rates_nested_list2 = from_flat(rates_flat_list, template)
print('nested:',rates_nested_list2)

检查输出:

flat:  [1, 1, 1, 2, 2, 3, 3, 3, 3]
nested: [[1, 1, 1], [2, 2], [3, 3, 3, 3]]

现在,在您的price_eval函数中,优化器会给您一个平坦的费率列表,您需要对其进行"膨胀",因此您的代码看起来像这样的

def price_eval(rates_flat_list, ttm_list, price_list, CF_list, CF_time_list, N_cf_list):
# create a nested list of rates from a flat one, using CF_list as a template
rates_flat_list = from_flat(rates_flat_list,CF_list)
price_model_list = []
sum_squares = 0
for i in range(0, len(price_list)):

price = 0
number_cf_per_bond = N_cf_list[i]

for j in range(0, number_cf_per_bond):

price += (CF_list[i][j]) / math.pow(1+rates_list[i][j],CF_time_list[i][j])
# !!! I think your code is missing the following line !!!
price_model_list.append(price)
diff = price_model_list[i] - price_list[i]
sum_squares += math.pow(diff,2)
return sum_squares

现在,当您调用优化器时,作为x0,您需要传递一个扁平列表,因此假设rates_guess是一个嵌套列表,您将调用

res = scipy.optimize.minimize(price_eval, x0 = to_flat(rates_guess), args=(ttm_list, price_list, CF_list, CF_time_list, N_cf_list))

最后,当你得到res时,它将有一个平面列表的解决方案,所以你可能想再次调用上的from_flat

最后,由于您无论如何都在进行最小二乘拟合,您可能希望使用scipy.optimize.least_squares而不是最小化——它具有几乎相同的输入,但在拟合时应该更好

最新更新