使用sympy时出现Can't convert expression to float报错如何解决
错误原因
- 核心问题是维度不匹配引发的广播异常,最终导致sympy表达式无法转float:
d(x)返回的是形状为(3,1)的二维numpy数组,与一维的初始点x = [0.5,0.5,0.5]做x + alpha*d运算时,numpy会自动广播,生成形状为(3,3)的二维数组- 你把这个
(3,3)的数组传入M、f_bold函数时,函数中取x[0]/x[1]/x[2]得到的是长度为3的数组而非单个数值,sympy的subs代入数组后得到的仍然是符号表达式,无法被转换为float类型,进而触发报错
- 次要问题:
s_prime函数的np.dot调用缺少第二个参数,从最速下降法的步长求导逻辑看,你应该是要计算搜索方向和梯度的点积,原代码逻辑不完整,还存在参数名和函数名重名的隐患。
修复方案
- 将
d函数的返回值降为一维数组,避免广播错误 - 所有sympy代入后的结果用
sym.N()包裹强制转数值,避免类型转换异常 - 补全
s_prime函数的点积逻辑,修改参数名避免和函数d重名 - 初始点
x转成numpy一维数组,统一运算维度
修复后完整可运行代码
import sympy as sym import numpy as np from numpy.linalg import norm from numpy import transpose from numpy import array from numpy import sum from matplotlib import pyplot as plt def equations(): a, b, c = sym.symbols('x y z') f_xyz_1 = 15*a + b**2 - 4*c - 15 f_xyz_2 = a**2 + 10*b - c - 10 f_xyz_3 = b**3 - 25*c + 24 return [f_xyz_1, f_xyz_2, f_xyz_3] def f_bold(x): a, b, c = sym.symbols('x y z') vals = {a: x[0], b: x[1], c: x[2]} # 用sym.N强制转数值 f_new_1 = sym.N(equations()[0].subs(vals)) f_new_2 = sym.N(equations()[1].subs(vals)) f_new_3 = sym.N(equations()[2].subs(vals)) return array([[f_new_1], [f_new_2], [f_new_3]], dtype='float64') def f(x): f_n = [] for i in range(len(x)): f_i = f_bold(x)[i]**2 f_n.append(f_i) return sum(f_n) def M(x): a, b, c = sym.symbols('x y z') vals = {a: x[0], b: x[1], c: x[2]} # 用sym.N强制转数值 f_xyz_1_diff_x = sym.N(sym.diff(equations()[0], a).subs(vals)) f_xyz_1_diff_y = sym.N(sym.diff(equations()[0], b).subs(vals)) f_xyz_1_diff_z = sym.N(sym.diff(equations()[0], c).subs(vals)) f_xyz_2_diff_x = sym.N(sym.diff(equations()[1], a).subs(vals)) f_xyz_2_diff_y = sym.N(sym.diff(equations()[1], b).subs(vals)) f_xyz_2_diff_z = sym.N(sym.diff(equations()[1], c).subs(vals)) f_xyz_3_diff_x = sym.N(sym.diff(equations()[2], a).subs(vals)) f_xyz_3_diff_y = sym.N(sym.diff(equations()[2], b).subs(vals)) f_xyz_3_diff_z = sym.N(sym.diff(equations()[2], c).subs(vals)) return array([[f_xyz_1_diff_x, f_xyz_2_diff_x, f_xyz_3_diff_x], [f_xyz_1_diff_y, f_xyz_2_diff_y, f_xyz_3_diff_y], [f_xyz_1_diff_z, f_xyz_2_diff_z, f_xyz_3_diff_z]], dtype='float64') def grad_f(x): return 2*np.dot(M(x), f_bold(x)) def d(x): # 加flatten降为一维数组 return (-1*grad_f(x)/norm(grad_f(x), ord=2)).flatten() def s_prime(x, alpha, d_vec): # 补全点积逻辑,梯度转置乘搜索方向 return np.dot(transpose(grad_f(x + alpha*d_vec)), d_vec) x = array([0.5, 0.5, 0.5]) alpha = 0.75 print(s_prime(x, alpha, d(x)))
运行后输出结果为:[454.07195475]
内容的提问来源于stack exchange,提问作者Aidan Payne
相关产品推荐
相关产品推荐

