千巷猫影
为了拟合y = A + B log x,只需对y(log x)拟合y。>>> x = numpy.array([1, 7, 20, 50, 79])>>> y = numpy.array([10, 19, 30, 35, 51])>>> numpy.polyfit(numpy.log(x), y, 1)array([ 8.46295607, 6.61867463])# y ≈ 8.46 log(x) + 6.62为了拟合y = Ae Bx,取两边的对数给出log y = log A + Bx。所以适合(log y)对抗x。注意,拟合(log y)就好像它是线性的一样会强调y的小值,导致大y的偏差很大。这是因为polyfit(线性回归)的工作原理是最小化Σ 我(Δ Ý)2 =Σ 我(ÿ 我 - Ŷ 我)2。当ÿ 我 =登录ÿ 我,残基Δ Ŷ 我 =Δ(日志Ý 我)≈Δ ÿ 我 / | Ÿ 我 |。即便如此polyfit对于大y做出了一个非常糟糕的决定,“除以| | y |” 因素将弥补它,导致polyfit有利于小的价值。这可以通过给每个条目赋予与y成比例的“权重”来减轻。polyfit通过w关键字参数支持加权最小二乘法。>>> x = numpy.array([10, 19, 30, 35, 51])>>> y = numpy.array([1, 7, 20, 50, 79])>>> numpy.polyfit(x, numpy.log(y), 1)array([ 0.10502711, -0.40116352])# y ≈ exp(-0.401) * exp(0.105 * x) = 0.670 * exp(0.105 * x)# (^ biased towards small values)>>> numpy.polyfit(x, numpy.log(y), 1, w=numpy.sqrt(y))array([ 0.06009446, 1.41648096])# y ≈ exp(1.42) * exp(0.0601 * x) = 4.12 * exp(0.0601 * x)# (^ not so biased)请注意,Excel,LibreOffice和大多数科学计算器通常使用指数回归/趋势线的未加权(偏差)公式。如果您希望结果与这些平台兼容,请不要包括权重,即使它提供了更好的结果。现在,如果你可以使用scipy,你可以使用scipy.optimize.curve_fit适合任何模型而不进行转换。对于y = A + B log x,结果与转换方法相同:>>> x = numpy.array([1, 7, 20, 50, 79])>>> y = numpy.array([10, 19, 30, 35, 51])>>> scipy.optimize.curve_fit(lambda t,a,b: a+b*numpy.log(t), x, y)(array([ 6.61867467, 8.46295606]),
array([[ 28.15948002, -7.89609542],
[ -7.89609542, 2.9857172 ]]))# y ≈ 6.62 + 8.46 log(x)然而,对于y = Ae Bx,我们可以得到更好的拟合,因为它直接计算Δ(log y)。但我们需要提供初始化猜测,以便curve_fit达到所需的局部最小值。>>> x = numpy.array([10, 19, 30, 35, 51])>>> y = numpy.array([1, 7, 20, 50, 79])>>> scipy.optimize.curve_fit(lambda t,a,b: a*numpy.exp(b*t), x, y)(array([ 5.60728326e-21, 9.99993501e-01]),
array([[ 4.14809412e-27, -1.45078961e-08],
[ -1.45078961e-08, 5.07411462e+10]]))# oops, definitely wrong.>>> scipy.optimize.curve_fit(lambda t,a,b: a*numpy.exp(b*t), x, y, p0=(4, 0.1))(array([ 4.88003249, 0.05531256]),
array([[ 1.01261314e+01, -4.31940132e-02],
[ -4.31940132e-02, 1.91188656e-04]]))# y ≈ 4.88 exp(0.0553 x). much better.