如何用SciPy函数实现Goal Seek求解线性方程未知变量?
如何用SciPy替代循环遍历实现线性方程的单变量求解?
当然可以用SciPy来解决这个问题,而且效率会比你现在的循环遍历高很多!既然你的方程是线性的,SciPy的优化模块里有专门的单变量求解工具,完全能替代手动循环,还能保证结果的精度。
核心思路
你现在的需求是找到xp_bot使得abs(equN - N) < 1,本质上是求解线性方程equN - N = 0的根(因为方程是线性的,这个根就是唯一解)。SciPy的scipy.optimize.root_scalar函数专门处理单变量方程求根,比手动遍历效率高得多。
具体步骤
调整目标函数
你的ULS函数当前返回的是差值的绝对值,我们可以直接返回equN - N,这样求解器能更精准地找到等于0的点,后续再验证是否满足精度要求即可:def ULS(xp_bot): xp_top = 0.00014 xp_all = [] slope = (xp_bot - xp_top) / (Ln) for i in range(0, 100, 1): xp_calc = i * slope + xp_top xp_all.append(xp_calc) xp_all.append(xp_bot) xmi_all = [] for i in range(0, 100, 1): xmi_calc = (xp_all[i] + xp_all[i+1]) / 2 xmi_all.append(xmi_calc) xi_all = [] for i in range(0, 100, 1): xi_calc = xmi_all[i] + xni_all[i] xi_all.append(xi_calc) sic_all = [] for item in xi_all: if item >= 0: sic = item * Ecm sic_all.append(sic) else: sic = 0 sic_all.append(sic) fic_step = np.multiply(sic_all, a) fic = np.divide(fic_step, 1000) sis_all = [] for item in xi_all: sis = item * Es sis_all.append(sis) fis_step = np.multiply(sis_all, a_s) fis = np.divide(fis_step, 1000) M_conc = [] for i in range(0, 100): multi_c = np.divide(fic, 1000) M_conc = np.multiply(leverarm, multi_c) multi_s = np.divide(fis, 1000) M_steel = np.multiply(leverarm, multi_s) M_sls = sum(M_conc) + sum(M_steel) equN = sum(fic) + sum(fis) return equN - N # 改为返回差值,去掉绝对值使用SciPy求解
导入root_scalar函数,定义好所有依赖变量(比如Ln、xni_all、Ecm等),然后设置xp_bot的搜索范围并求解:import numpy as np from scipy.optimize import root_scalar # 先确保所有依赖变量已正确赋值(示例,根据你的实际情况修改) Ln = 1.0 xni_all = np.random.rand(100) # 替换为你的实际数组 Ecm = 30000 a = np.array([...]) # 长度为100的数组 Es = 200000 a_s = np.array([...]) # 长度为100的数组 leverarm = np.array([...]) # 长度为100的数组 N = 1000 # 你的目标N值 # 设置xp_bot的合理搜索范围(根据你的实际场景调整) result = root_scalar(ULS, bracket=[0, 0.001], method='bisect') # 验证结果 if result.converged: xp_bot_solution = result.root if abs(ULS(xp_bot_solution)) < 1: print(f"找到的xp_bot解为:{xp_bot_solution:.6f}") else: print("解不满足精度要求,请检查搜索范围或参数") else: print("求解失败,请确认函数逻辑或调整搜索区间")
额外提示
- 因为你的方程是线性的,
root_scalar会瞬间收敛,比手动循环高效无数倍,尤其是需要多次求解的场景。 - 如果不确定
xp_bot的范围,可以先通过少量循环大致确定一个合理区间,再传给bracket参数。 - 除了二分法,也可以使用
method='newton'(牛顿法),但需要提供函数的导数(线性函数的导数是常数,如果你能计算出来,求解速度会更快)。
内容的提问来源于stack exchange,提问作者sado




