不论是做统计分析,还是做机器学习相关的项目时,常常在最后通过绘制一些图表来表达自己得出的结论。
然而,绘图的意义远不止此。
因为,即使不同的原始样本的分布情况差别很大,它们的基本统计特性也能几乎一致。
这时如果不把原始样本的分布绘制出来看看,仅仅依赖基本的统计量来描述数据,可能会数据情况造成误判。
安斯库姆四重奏就是这样的一种数据集,它们的分布情况差别很大,基本统计特性却几乎一致。
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. 属性的平均值
统计各个数据集中属性x
和y
的平均值。
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
每个数据集的属性x
和y
的平均值都一样。
2.2. 属性的样本方差
统计各个数据集中属性x
和y
的样本方差。
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
各个数据集中属性x
和y
的样本方差几乎一致,差别很小。
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. 总结
安斯库姆四重奏 虽然是构造出的数据集,但是真实世界中难免不会有类似的情况。
它提醒我们要用更加严谨的态度对待数据分析的结果,不要仅仅依据基本的统计特性就得出结论,
还需要对数据进行可视化处理,以便更全面地了解数据的分布情况。
安斯库姆四重奏 数据传达给我们的核心信息是:在数据分析中,可视化是一个至关重要的步骤,它能帮助我们更好地理解和解释数据。