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

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

然而,绘图的意义远不止此。

因为,即使不同的原始样本的分布情况差别很大,它们的基本统计特性也能几乎一致。

这时如果不把原始样本的分布绘制出来看看,仅仅依赖基本的统计量来描述数据,可能会数据情况造成误判。

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

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

安斯库姆四重奏 是统计学家弗朗西斯·安斯库姆(Francis Anscombe)于1973年构造的数据集。

它为我们揭示了数据分析中的一个重要问题:仅仅依赖基本的统计量(如均值、方差等)来描述数据集是不够的,还需要考虑数据的分布情况。

数据集内容如下:

python 复制代码
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]),
    },
]

它们的分布情况如下:

python 复制代码
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的平均值。

python 复制代码
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的样本方差。

python 复制代码
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个数据集进行线性回归,看看各自的回归的曲线和 <math xmlns="http://www.w3.org/1998/Math/MathML"> R 2 R^2 </math>R2分数。
R² 分数 (也叫决定系数),是用于衡量模型的拟合优度的一个指标。

python 复制代码
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()

虽然数据分布差别很大,但是线性回归的曲线和 <math xmlns="http://www.w3.org/1998/Math/MathML"> R 2 R^2 </math>R2分数却出奇的一致。

3. 总结

安斯库姆四重奏 虽然是构造出的数据集,但是真实世界中难免不会有类似的情况。

它提醒我们要用更加严谨的态度对待数据分析的结果,不要仅仅依据基本的统计特性就得出结论,

还需要对数据进行可视化处理,以便更全面地了解数据的分布情况。

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

相关推荐
nita张18 分钟前
战略定位实战:案例分享与经验总结
大数据·人工智能·python
MadPrinter1 小时前
Python 异步爬虫实战:FindQC 商品数据爬取系统完整教程
爬虫·python·算法·自动化
清水白石0081 小时前
Python 函数式编程实战:从零构建函数组合系统
开发语言·python
喵手2 小时前
Python爬虫实战:数据质量治理实战 - 构建企业级规则引擎与异常检测系统!
爬虫·python·爬虫实战·异常检测·零基础python爬虫教学·数据质量治理·企业级规则引擎
头发够用的程序员2 小时前
Python 魔法方法 vs C++ 运算符重载全方位深度对比
开发语言·c++·python
加成BUFF2 小时前
基于DeepSeek+Python开发软件并打包为exe(VSCode+Anaconda Prompt实操)
vscode·python·prompt·conda·anaconda
52Hz1182 小时前
力扣46.全排列、78.子集、17.电话号码的字母组合
python·leetcode
子午2 小时前
【宠物识别系统】Python+深度学习+人工智能+算法模型+图像识别+TensorFlow+2026计算机毕设项目
人工智能·python·深度学习
好家伙VCC2 小时前
# 发散创新:用Python+Pandas构建高效BI数据清洗流水线在现代数据分析领域,**BI(商业智能)工具的核心竞
java·python·数据分析·pandas
七夜zippoe3 小时前
TensorFlow 2.x深度实战:从Keras API到自定义训练循环
人工智能·python·tensorflow·keras