基于Scipy复现Excel单变量求解(牛顿-拉夫逊法)的比率优化问题
用Scipy牛顿-拉夫逊法复现Excel Goal Seek:调整儿童数量达成目标比率
咱们先拆解下你的问题:你想通过调整儿童数量X,让「(初始群体总数 - X)/X」这个比率不低于目标值Z,同时群体总数随X减少同步降低(对应你例子里的1000→923,X从100→76)。你的代码主要踩了两个坑:参数传递方式错了,而且没把目标比率融入牛顿法的核心逻辑里。
核心逻辑梳理
牛顿法是用来找函数的根(也就是f(x)=0的点),所以咱们得把你的目标转化为求根问题:
你要的是 (group - X)/X ≥ Z,那先找刚好等于Z的X值,也就是解方程:
(group - X)/X - Z = 0
找到这个根之后,只要X比这个根小,比率就会大于Z(因为X越小,分母越小、分子越大,比值自然更高),刚好满足你「不低于目标比率」的要求。
修正后的完整代码
from scipy import optimize # 输入参数(对应你的例子) initial_group = 1000 initial_kids = 100 target_ratio = 12 # 要求群体总数/儿童数量 ≥ 12 # 定义目标函数:求 (group - x)/x - target_ratio = 0 的根 def target_func(x, group, target_z): return (group - x)/x - target_z # 调用牛顿法:初始猜测用初始儿童数,用args传递额外参数 root = optimize.newton(target_func, x0=initial_kids, args=(initial_group, target_ratio)) print(f"刚好达到目标比率的儿童数量(精确值): {root:.2f}") # 处理结果:取小于等于精确值的最大整数(保证比率≥目标) optimal_kids = int(root) # 确保儿童数量为正 if optimal_kids <= 0: raise ValueError("目标比率设置过高,无法得到合理的儿童数量!") # 计算对应的群体总数和实际比率 new_group = initial_group - optimal_kids actual_ratio = new_group / optimal_kids print("\n调整结果:") print(f"调整后儿童数量: {optimal_kids}") print(f"调整后群体总数: {new_group}") print(f"实际比率: {actual_ratio:.2f}")
关键细节解释
- 参数传递:你之前直接把
1000放在optimize.newton的第三个参数,这是错的——第三个位置是用来传导数函数的(可选)。正确做法是用args参数把额外的initial_group和target_ratio传给目标函数。 - 目标函数设计:咱们把「比率等于Z」转化为
(group-x)/x - Z = 0,这样牛顿法就能精准找到刚好达标的X值。 - 结果取整:因为你需要比率不低于目标,所以把精确值向下取整(比如例子里精确值≈76.92,取76),这时候比率≈12.14,刚好满足≥12的要求;如果取77的话,比率≈11.99就不达标了。
运行结果(对应你的例子)
刚好达到目标比率的儿童数量(精确值): 76.92 调整结果: 调整后儿童数量: 76 调整后群体总数: 923 实际比率: 12.14
完全匹配你给出的示例结果~
内容的提问来源于stack exchange,提问作者June
相关产品推荐
相关产品推荐

