如何实现通用单缺失变量方程求解函数?无需重复改写方程
问题
是否无需以不同方式重写方程,即可求解任意单个缺失变量?
我写了一个solve_drag函数来解决阻力公式fd = 0.5 * p * v² * cd * a的变量求解问题——传入4个已知变量,用scipy.optimize.fsolve算出缺失的那个,但这个实现太冗余了,每个缺失变量都要写单独的lambda和判断,根本没法适配其他函数。想问问能不能做一个通用函数,只要传入待求解的函数和已知变量,就能返回缺失变量的值?
附当前的solve_drag实现:
def solve_drag(fd = None, p = None, v = None, cd = None, a = None): """Takes 4 inputs out of the 5 listed and returns what the other must equal.""" def drag(fd, p, v, cd, a): return (0.5 * p * v**2 * cd * a) - fd if fd == None: return scipy.optimize.fsolve(drag, 25, args=(p, v, cd, a)) elif p == None: return scipy.optimize.fsolve(lambda p, v, cd, a, fd: drag(fd, p, v, cd, a), 1, args=(v, cd, a, fd)) elif v == None: return scipy.optimize.fsolve(lambda v, cd, a, fd, p: drag(fd, p, v, cd, a), 1, args=(cd, a, fd, p)) elif cd == None: return scipy.optimize.fsolve(lambda cd, a, fd, p, v: drag(fd, p, v, cd, a), 1, args=(a, fd, p, v)) elif a == None: return scipy.optimize.fsolve(lambda a, fd, p, v, cd: drag(fd, p, v, cd, a), 1, args=(fd, p, v, cd))
解决方案
完全可以做一个通用函数来解决这个问题,核心思路很简单:
- 先找出哪个参数是缺失的(也就是传了
None的那个) - 动态生成一个适配
fsolve的目标函数,把缺失参数当成待优化的变量,剩下的已知参数固定死 - 最后调用
fsolve算出结果
下面是具体的实现代码:
import scipy.optimize def solve_single_missing(func, **kwargs): """ 通用单缺失变量求解工具 参数: func: 要解的方程函数,参数名要和kwargs里的键对应上 **kwargs: 所有参数的键值对,只能有一个参数的值是None(就是要解的那个变量) 返回: 缺失变量的计算结果 """ # 先确定哪个参数缺了,同时整理已知参数 missing_param = None known_args = [] # 获取原函数的参数顺序 param_names = func.__code__.co_varnames[:func.__code__.co_argcount] for name in param_names: val = kwargs.get(name) if val is None: if missing_param is not None: raise ValueError("只能留一个参数为None,多了没法解") missing_param = name else: known_args.append(val) if not missing_param: raise ValueError("得留一个参数为None啊,不然解啥?") # 构造给fsolve用的目标函数:把缺失参数当变量,其他参数按原顺序传入 def target(x): full_params = [] known_idx = 0 for name in param_names: if name == missing_param: full_params.append(x[0]) else: full_params.append(known_args[known_idx]) known_idx += 1 return func(*full_params) # 默认初始猜测值用1,也可以改成让用户传入 guess = [1.0] result = scipy.optimize.fsolve(target, guess) return result[0]
用你的阻力公式测试
先把原始的阻力方程写成独立函数:
def drag(fd, p, v, cd, a): return 0.5 * p * v**2 * cd * a - fd
然后随便缺哪个变量都能解:
# 求缺失的fd solve_single_missing(drag, p=1.225, v=20, cd=0.47, a=0.05, fd=None) # 求缺失的速度v solve_single_missing(drag, fd=5.76, p=1.225, cd=0.47, a=0.05, v=None)
注意点
- 这个函数依赖原函数的参数顺序,所以
kwargs里的键必须和func的参数名完全一致 - 如果某些方程需要特定的初始猜测值,可以给
solve_single_missing加个initial_guess参数来调整 - 函数会自动校验参数数量,多缺或者不缺都会报错,避免混乱
内容的提问来源于stack exchange,提问作者Lucas Lewis-Price
相关产品推荐
相关产品推荐

