回归模型

简而言之,这类模型认为两个变量之间的潜在关系是完全线性的;这条直线就是我们想要识别的“信号”。然而,我们无法清晰地看到这条线。我们看到的是散布在线周围的点。在每个点中,信号都被“随机噪声”污染了。因此,我们的推断目标是:将信号从噪声中分离出来。

更详细地说,回归模型规定散点图中的点按照以下方式随机生成:

  • $x$ 和 $y$ 之间的关系是完全线性的。我们看不到这条“真实直线”,但它客观存在。
  • 散点图的创建方式为:取直线上的点,将其垂直推离直线(向上或向下),具体如下:
    • 对于每个 $x$,找到真实直线上的对应点(即信号),然后生成噪声或误差。
    • 误差是从一个均值为 0 的正态分布的误差总体中有放回地随机抽取的。
    • 创建一个点,其横坐标为 $x$,纵坐标为“真实直线在 $x$ 处的高度加上误差”。
  • 最后,从散点图中擦去真实直线,只显示所创建的点。
[In ]:
from datascience import *
path_data = '../../../assets/data/'
import numpy as np
import matplotlib
matplotlib.use('Agg')
%matplotlib inline
import matplotlib.pyplot as plots
plots.style.use('fivethirtyeight')
[In ]:
def standard_units(any_numbers):
    "Convert any array of numbers to standard units."
    return (any_numbers - np.mean(any_numbers))/np.std(any_numbers)  

def correlation(t, x, y):
    return np.mean(standard_units(t.column(x))*standard_units(t.column(y)))

def slope(table, x, y):
    r = correlation(table, x, y)
    return r * np.std(table.column(y))/np.std(table.column(x))

def intercept(table, x, y):
    a = slope(table, x, y)
    return np.mean(table.column(y)) - a * np.mean(table.column(x))

def fit(table, x, y):
    a = slope(table, x, y)
    b = intercept(table, x, y)
    return a * table.column(x) + b

def scatter_fit(table, x, y):
    plots.scatter(table.column(x), table.column(y), s=20)
    plots.plot(table.column(x), fit(table, x, y), lw=2, color='gold')
    plots.xlabel(x)
    plots.ylabel(y)

基于这个散点图,我们应该如何估计真实直线?我们能够穿过散点图的最佳直线就是回归线。因此,回归线是真实直线的一个自然估计。

下面的模拟显示了回归线与真实直线的接近程度。第一个面板显示了散点图如何从真实直线生成。第二个面板显示了我们所看到的散点图。第三个面板显示了穿过该图的回归线。第四个面板同时显示了回归线和真实直线。

要运行模拟,请调用函数 draw_and_compare,需要三个参数:真实直线的斜率、真实直线的截距和样本量。

运行模拟几次,使用真实直线的不同斜率和截距值以及不同的样本量。由于所有点都是根据模型生成的,你会看到如果样本量足够大,回归线是真实直线的一个良好估计。

[In ]:
def draw_and_compare(true_slope, true_int, sample_size):
    x = np.random.normal(50, 5, sample_size)
    xlims = np.array([np.min(x), np.max(x)])
    eps = np.random.normal(0, 6, sample_size)
    y = (true_slope*x + true_int) + eps
    tyche = Table().with_columns(
        'x', x,
        'y', y
    )

    plots.figure(figsize=(6, 16))
    plots.subplot(4, 1, 1)
    plots.scatter(tyche['x'], tyche['y'], s=20)
    plots.plot(xlims, true_slope*xlims + true_int, lw=2, color='green')
    plots.title('True Line, and Points Created')

    plots.subplot(4, 1, 2)
    plots.scatter(tyche['x'],tyche['y'], s=20)
    plots.title('What We Get to See')

    plots.subplot(4, 1, 3)
    scatter_fit(tyche, 'x', 'y')
    plots.xlabel("")
    plots.ylabel("")
    plots.title('Regression Line: Estimate of True Line')

    plots.subplot(4, 1, 4)
    scatter_fit(tyche, 'x', 'y')
    plots.ylabel("")
    xlims = np.array([np.min(tyche['x']), np.max(tyche['x'])])
    plots.plot(xlims, true_slope*xlims + true_int, lw=2, color='green')
    plots.title("Regression Line and True Line")
[In ]:
# The true line,
# the points created,
# and our estimate of the true line.
# Arguments: true slope, true intercept, number of points

draw_and_compare(4, -5, 10)
Four graphs are shown. The first graph is titled 'True Line, and Points Created' and has a green line with a positive slope and data points in light blue. The second plot is titled 'What We Get to See' with the blue data points shown. The third plot is titled 'Regression Line: Estimate of True Line' and the light blue data points remain along with a gold line that is much like the green line of the first graph, but slightly different. The fourth graph is titled 'Regression Line and True Line' and shows the data points, the yellow line, and the green line. The lines are very similar, but slightly different.

当然,在现实中,我们永远看不到真实直线。模拟所表明的是:如果回归模型看起来合理,并且我们有一个大样本,那么回归线就是对真实直线的一个良好近似。