问题描述
我是 python 提供的优化技术的新手,我找不到如何根据我的需要调整 scipy 中的 optimize.minimize 的方法。
我想要做的是通过改变利率来最小化市场价格与给定债券模型价格之间的平方差之和(因此利率将是我的 x0)。这个总和是通过 price_eval 计算的,它需要几个列表或嵌套列表作为参数,例如每个债券的现金流量嵌套列表。为了让后者更清楚——如果我有 3 种债券,它们有 3、2 和 4 种未来现金流量,比如 a、b、c; d,e; h;i;j;k 分别,其中一个参数是列表 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,N_cf_list))
我提供嵌套列表 rate_guess 作为解算器 rate_list[i][j] 的初始猜测(我是否将其更改为 numpy 数组并不重要,给出相同的结果)。整个问题可能来自这样一个事实,即 scipy.optimize.minimize 仅将一维数组作为 x0,而在我的情况下,由于每个债券每个现金流存储的数据,x0 需要是二维的。我收到一个错误
...
grad[k] = (f(*((xk + d,) + args)) - f0) / d[k]
TypeError: can only concatenate list (not "float") to list
所以,我的问题是是否有人知道如何解决这个问题?或者是否有可能以某种方式调整求解器,我可以提供嵌套列表/2D np 数组作为 x0,应该以相同的格式返回新值?如果没有,我还能做什么?
非常感谢您的帮助!
解决方法
mid = len(a)//2
和 rates_list
都需要是一维数组/列表。我通常处理这个问题的方法是让函数将您喜欢的结构展平成一个列表,然后将它“膨胀”回所需的形状。所以你可以有,例如,像这样的东西
rates_guess
检查输出:
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]]
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]]
rates_nested_list2 = from_flat(rates_flat_list,template)
print('nested:',rates_nested_list2)
现在,在您的 flat: [1,2,3]
nested: [[1,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,N_cf_list))
时,它会有一个解决方案作为一个平面列表,所以你可能想再次调用 res
最后,由于无论如何您都在进行最小二乘拟合,因此您可能希望使用 from_flat
而不是最小化 - 它具有几乎相同的输入,但应该更好地拟合