likes
comments
collection
share

安斯科姆四重奏(统计分析中可视化的重要性)

作者站长头像
站长
· 阅读数 2

不论是做统计分析,还是做机器学习相关的项目时,常常在最后通过绘制一些图表来表达自己得出的结论。

然而,绘图的意义远不止此。因为,即使不同的原始样本的分布情况差别很大,它们的基本统计特性也能几乎一致。这时如果不把原始样本的分布绘制出来看看,仅仅依赖基本的统计量来描述数据,可能会数据情况造成误判。

安斯库姆四重奏就是这样的一种数据集,它们的分布情况差别很大,基本统计特性却几乎一致。

1. 安斯科姆四重奏数据集

安斯库姆四重奏是统计学家弗朗西斯·安斯库姆(Francis Anscombe)于1973年构造的数据集。它为我们揭示了数据分析中的一个重要问题:仅仅依赖基本的统计量(如均值、方差等)来描述数据集是不够的,还需要考虑数据的分布情况。

数据集内容如下:

import numpy as np

anscombes = [
    {
        "x": np.array([10, 8, 13, 9, 11, 14, 6, 4, 12, 7, 5]),
        "y": np.array([8.04, 6.95, 7.58, 8.81, 8.33, 9.96, 7.24, 4.26, 10.84, 4.82, 5.68]),
    },
    {
        "x": np.array([10, 8, 13, 9, 11, 14, 6, 4, 12, 7, 5]),
        "y": np.array([9.14, 8.14, 8.74, 8.77, 9.26, 8.1, 6.13, 3.1, 9.13, 7.26, 4.74]),
    },
    {
        "x": np.array([10, 8, 13, 9, 11, 14, 6, 4, 12, 7, 5]),
        "y": np.array([7.46, 6.77, 12.74, 7.11, 7.81, 8.84, 6.08, 5.39, 8.15, 6.42, 5.73]),
    },
    {
        "x": np.array([8, 8, 8, 8, 8, 8, 8, 19, 8, 8, 8]),
        "y": np.array([6.58, 5.76, 7.71, 8.84, 8.47, 7.04, 5.25, 12.5, 5.56, 7.91, 6.89]),
    },
]

它们的分布情况如下:

import matplotlib.pyplot as plt

fig, axes = plt.subplots(2, 2, sharex="all", sharey="all")
fig.set_size_inches(8, 6)
axes[0][0].scatter(anscombes[0]["x"], anscombes[0]["y"])
axes[0][1].scatter(anscombes[1]["x"], anscombes[1]["y"])
axes[1][0].scatter(anscombes[2]["x"], anscombes[2]["y"])
axes[1][1].scatter(anscombes[3]["x"], anscombes[3]["y"])


plt.show()

安斯科姆四重奏(统计分析中可视化的重要性)

2. 不同的数据,相同的指标

接下来,看看安斯库姆四重奏中4个数据集各自的统计特性。

2.1. 属性的平均值

统计各个数据集中属性xy的平均值。

print(
    "x的平均值:{}, {}, {}, {}".format(
        np.mean(anscombes[0]["x"]),
        np.mean(anscombes[1]["x"]),
        np.mean(anscombes[2]["x"]),
        np.mean(anscombes[3]["x"]),
    )
)

print(
    "y的平均值:{:.2f}, {:.2f}, {:.2f}, {:.2f}".format(
        np.mean(anscombes[0]["y"]),
        np.mean(anscombes[1]["y"]),
        np.mean(anscombes[2]["y"]),
        np.mean(anscombes[3]["y"]),
    )
)

# 运行结果
x的平均值:9.0, 9.0, 9.0, 9.0
y的平均值:7.50, 7.50, 7.50, 7.50

每个数据集的属性xy的平均值都一样

2.2. 属性的样本方差

统计各个数据集中属性xy的样本方差。

print(
    "x的样本方差:{}, {}, {}, {}".format(
        np.var(anscombes[0]["x"], ddof=1),
        np.var(anscombes[1]["x"], ddof=1),
        np.var(anscombes[2]["x"], ddof=1),
        np.var(anscombes[3]["x"], ddof=1),
    )
)

print(
    "y的样本方差:{:.2f}, {:.2f}, {:.2f}, {:.2f}".format(
        np.var(anscombes[0]["y"], ddof=1),
        np.var(anscombes[1]["y"], ddof=1),
        np.var(anscombes[2]["y"], ddof=1),
        np.var(anscombes[3]["y"], ddof=1),
    )
)

# 运行结果
x的样本方差:11.0, 11.0, 11.0, 11.0
y的样本方差:4.13, 4.13, 4.12, 4.12

各个数据集中属性xy的样本方差几乎一致,差别很小

2.3. 线性回归及R2分数

最后,分别对4个数据集进行线性回归,看看各自的回归的曲线和R2R^2R2分数。R² 分数(也叫决定系数),是用于衡量模型的拟合优度的一个指标。

from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score

fig, axes = plt.subplots(2, 2, sharex="all", sharey="all")
fig.set_size_inches(8, 6)
axes[0][0].scatter(anscombes[0]["x"], anscombes[0]["y"])
axes[0][1].scatter(anscombes[1]["x"], anscombes[1]["y"])
axes[1][0].scatter(anscombes[2]["x"], anscombes[2]["y"])
axes[1][1].scatter(anscombes[3]["x"], anscombes[3]["y"])

reg_x = np.array([0, 20])

reg = LinearRegression()
sample_x = [[x] for x in anscombes[0]["x"]]
reg.fit(sample_x, anscombes[0]["y"])
# print(reg.coef_, reg.intercept_)
reg_y = reg.coef_ * reg_x + reg.intercept_
axes[0][0].plot(reg_x, reg_y, color="r")
r2 = r2_score(anscombes[0]["y"], reg.predict(sample_x))
axes[0][0].set_title("R2系数: {:.2f}".format(r2))

sample_x = [[x] for x in anscombes[1]["x"]]
reg.fit(sample_x, anscombes[1]["y"])
# print(reg.coef_, reg.intercept_)
reg_y = reg.coef_ * reg_x + reg.intercept_
axes[0][1].plot(reg_x, reg_y, color="r")
r2 = r2_score(anscombes[1]["y"], reg.predict(sample_x))
axes[0][1].set_title("R2系数: {:.2f}".format(r2))

sample_x = [[x] for x in anscombes[2]["x"]]
reg.fit(sample_x, anscombes[2]["y"])
# print(reg.coef_, reg.intercept_)
reg_y = reg.coef_ * reg_x + reg.intercept_
axes[1][0].plot(reg_x, reg_y, color="r")
r2 = r2_score(anscombes[2]["y"], reg.predict(sample_x))
axes[1][0].set_title("R2系数: {:.2f}".format(r2))

sample_x = [[x] for x in anscombes[3]["x"]]
reg.fit(sample_x, anscombes[3]["y"])
# print(reg.coef_, reg.intercept_)
reg_y = reg.coef_ * reg_x + reg.intercept_
axes[1][1].plot(reg_x, reg_y, color="r")
r2 = r2_score(anscombes[3]["y"], reg.predict(sample_x))
axes[1][1].set_title("R2系数: {:.2f}".format(r2))

plt.show()

安斯科姆四重奏(统计分析中可视化的重要性)虽然数据分布差别很大,但是线性回归的曲线和R2R^2R2分数却出奇的一致。

3. 总结

安斯库姆四重奏虽然是构造出的数据集,但是真实世界中难免不会有类似的情况。它提醒我们要用更加严谨的态度对待数据分析的结果,不要仅仅依据基本的统计特性就得出结论,还需要对数据进行可视化处理,以便更全面地了解数据的分布情况。

安斯库姆四重奏数据传达给我们的核心信息是:在数据分析中,可视化是一个至关重要的步骤,它能帮助我们更好地理解和解释数据。