跳转至

使用 np.polynomial.Polynomial 进行一元线性回归的一个注意事项

在使用 np.polynomial.Polynomial 进行一元线性回归时,未能得到预期的结果。经检查发现, Polynomial.fit() 会将数据缩放和偏移到 window 参数上后,再进行回归估计。如果需要得到未缩放和偏移的估计量,可以用 .convert().coef

image-20240612203358068

构造模拟数据

我们首先构造一个简单的模拟数据:

Python
import numpy as np

x = np.array([1, 2, 3, 4, 5])
y = np.array([2, 4, 6, 8, 10])

很显然,将 \(x\)\(y\) 进行一元线性回归后,得到的回归系数是 \(2\),截距是 \(0\)

使用 np.polyfit 进行回归

我们使用 np.polyfit 进行回归,得到的结果是符合预期的:

Python
np.polyfit(x, y, deg=1)
Text Only
array([2.00000000e+00, 4.69026356e-16])

使用 np.polynomial.Polynomial 进行回归

Python
np.polynomial.Polynomial.fit(x, y, deg=1).coef
Text Only
array([6., 4.])

得到的结果是 \(6\)\(4\),并不符合预期。

stackoverflow 的回答 指出,Polynomial.fit() 会将数据缩放和偏移到 window 参数上后,再进行回归估计。

我们可以查看一下,默认的 window 参数是 array([-1., 1.])

Python
np.polynomial.Polynomial.fit(x, y, deg=1).window
Text Only
array([-1.,  1.])

为了理解 \(6\)\(4\) 是如何得到的,下面我们手动对数据进行缩放和平移至 [-1., 1.]

缩放和平移的过程为:

\[ x' = \frac{(x - x_{min}) * (b - a)}{x_{max} - x_{min}} + a \]

其中:

  • \(x\) 是原始值。
  • \(x_{min}\)\(x_{max}\) 是原始范围的最小值和最大值。
  • \(a\)\(b\) 是目标范围的最小值和最大值。
  • \(x'\) 是缩放后的值。
Python
def scale_and_shift(x, target_min=-1, target_max=1):
    original_min = min(x)
    original_max = max(x)
    return np.array(
        [
            (i - original_min)
            * (target_max - target_min)
            / (original_max - original_min)
            + target_min
            for i in x
        ]
    )


x = np.array([1, 2, 3, 4, 5])
scaled_x = scale_and_shift(x)
scaled_x
Text Only
array([-1. , -0.5,  0. ,  0.5,  1. ])

可以看到,[1, 2, 3, 4, 5] 经过缩放平移后变成了 [-1. , -0.5, 0. , 0.5, 1. ]

我们再针对下面的数据,用 np.polyfit 进行回归:

Python
x = np.array([-1.0, -0.5, 0.0, 0.5, 1.0])
y = np.array([2, 4, 6, 8, 10])
np.polyfit(x, y, deg=1)
Text Only
array([4., 6.])

结果表明,将 [1, 2, 3, 4, 5] 经过缩放平移后变成 [-1. , -0.5, 0. , 0.5, 1. ],再与 \(y\) 进行回归,得到的回归系数是 \(4\),截距项是 \(6\)。这就是为什么之前使用 np.polynomial.Polynomial 进行回归会得到 array([6., 4.])

转换为未缩放平移的结果

如果我们希望得到未缩放平移时的回归结果,有三种实现方式。

.convert().coef

第一种是使用 .convert().coef

image-20240612205314542

Python
x = np.array([1, 2, 3, 4, 5])
y = np.array([2, 4, 6, 8, 10])
np.polynomial.Polynomial.fit(x, y, deg=1).convert().coef
Text Only
array([-1.77635684e-15,  2.00000000e+00])

window=(x.min(), x.max())

第二种是使用 window=(x.min(), x.max())

Python
x = np.array([1, 2, 3, 4, 5])
y = np.array([2, 4, 6, 8, 10])
np.polynomial.Polynomial.fit(x, y, deg=1, window=(x.min(), x.max())).coef
Text Only
array([4.49646661e-15, 2.00000000e+00])

domain=[]

第三种是使用 domain=[]

Python
x = np.array([1, 2, 3, 4, 5])
y = np.array([2, 4, 6, 8, 10])
np.polynomial.Polynomial.fit(x, y, deg=1, domain=[]).coef
Text Only
array([4.49646661e-15, 2.00000000e+00])

评论