数据分析——第三章模型建立和评估--建模

第三章 模型搭建和评估–建模

经过前面的两章的知识点的学习,我可以对数数据的本身进行处理,比如数据本身的增删查补,还可以做必要的清洗工作。那么下面我们就要开始使用我们前面处理好的数据了。这一章我们要做的就是使用数据,我们做数据分析的目的也就是,运用我们的数据以及结合我的业务来得到某些我们需要知道的结果。那么分析的第一步就是建模,搭建一个预测模型或者其他模型;我们从这个模型的到结果之后,我们要分析我的模型是不是足够的可靠,那我就需要评估这个模型。今天我们学习建模,下一节我们学习评估。

我们拥有的泰坦尼克号的数据集,那么我们这次的目的就是,完成泰坦尼克号存活预测这个任务。

1
2
3
4
5
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from IPython.display import Image
1
%matplotlib inline
1
2
3
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
plt.rcParams['figure.figsize'] = (10, 6) # 设置输出图片大小

载入这些库,如果缺少某些库,请安装他们

【思考】这些库的作用是什么呢?你需要查一查

1
2
3
4
5
6
#思考题回答
'''
Image 是 IPython.display 模块的一部分,用于在 Jupyter Notebook 或 IPython 环境中直接显示图像。支持从本地路径或网络 URL 加载图像,并控制显示格式(如宽度、高度、格式类型)
seaborn 是一个基于 Matplotlib 的高级数据可视化库,专注于统计图形的绘制(如分布图、相关性图、分类图等),能快速生成美观且信息丰富的图表
'''

'\nImage 是 IPython.display 模块的一部分,用于在 Jupyter Notebook 或 IPython 环境中直接显示图像。支持从本地路径或网络 URL 加载图像,并控制显示格式(如宽度、高度、格式类型)\nseaborn 是一个基于 Matplotlib 的高级数据可视化库,专注于统计图形的绘制(如分布图、相关性图、分类图等),能快速生成美观且信息丰富的图表\n'
1
%matplotlib inline

载入我们提供清洗之后的数据(clear_data.csv),大家也将原始数据载入(train.csv),说说他们有什么不同

1
2
3
#写入代码
train = pd.read_csv('train.csv')
train.shape
(891, 12)
1
2
#写入代码
train.head()
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th… female 38.0 1 0 PC 17599 71.2833 C85 C
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S
1
2
3
4
#写入代码
data = pd.read_csv('clear_data.csv')

data.head()
PassengerId Pclass Age SibSp Parch Fare Sex_female Sex_male Embarked_C Embarked_Q Embarked_S
0 0 3 22.0 1 0 7.2500 0 1 0 0 1
1 1 1 38.0 1 0 71.2833 1 0 1 0 0
2 2 3 26.0 0 0 7.9250 1 0 0 0 1
3 3 1 35.0 1 0 53.1000 1 0 0 0 1
4 4 3 35.0 0 0 8.0500 0 1 0 0 1

模型搭建

  • 处理完前面的数据我们就得到建模数据,下一步是选择合适模型
  • 在进行模型选择之前我们需要先知道数据集最终是进行监督学习还是无监督学习
  • 模型的选择一方面是通过我们的任务来决定的。
  • 除了根据我们任务来选择模型外,还可以根据数据样本量以及特征的稀疏性来决定
  • 刚开始我们总是先尝试使用一个基本的模型来作为其baseline,进而再训练其他模型做对比,最终选择泛化能力或性能比较好的模型

这里我的建模,并不是从零开始,自己一个人完成完成所有代码的编译。我们这里使用一个机器学习最常用的一个库(sklearn)来完成我们的模型的搭建

下面给出sklearn的算法选择路径,供大家参考

1
2
# sklearn模型算法选择路径图
Image('sklearn.png')
第三章模型建立和评估–建模-课程_17_0

【思考】数据集哪些差异会导致模型在拟合数据是发生变化

1
2
3
#思考回答


任务一:切割训练集和测试集

这里使用留出法划分数据集

  • 将数据集分为自变量和因变量
  • 按比例切割训练集和测试集(一般测试集的比例有30%、25%、20%、15%和10%)
  • 使用分层抽样
  • 设置随机种子以便结果能复现

【思考】 * 划分数据集的方法有哪些? * 为什么使用分层抽样,这样的好处有什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 划分数据集的方法有哪些?
# 1. **留出法 (Hold-out Cross Validation)**:
# * 直接将数据集D划分为两个互斥的集合:训练集S和测试集T。
# * 例如,70%的数据用于训练,30%用于测试。
# * 优点:简单、计算开销小。
# * 缺点:划分具有随机性,单次划分的结果可能不够稳定和准确,尤其是在数据集较小时。训练集和测试集的样本比例会影响评估结果。

# 2. **交叉验证法 (Cross Validation)**:
# * **k折交叉验证 (k-Fold Cross Validation)**:
# * 将数据集D划分为k个大小相似的互斥子集 D1, D2, ..., Dk。
# * 每次用k-1个子集的并集作为训练集,余下的那个子集作为测试集。
# * 这样可以获得k组训练/测试集,从而可进行k次训练和测试,最终返回的是这k个测试结果的均值。
# * 常用的k值为5或10。
# * 优点:比留出法更稳定,更充分地利用了数据。
# * 缺点:计算开销是k倍。
# * **留一法 (Leave-One-Out Cross Validation, LOOCV)**:
# * k折交叉验证的特例,当k等于样本数N时。
# * 每次只留下一个样本作为测试集,其余N-1个样本作为训练集。
# * 优点:评估结果通常被认为比较准确,因为几乎所有数据都用于训练。
# * 缺点:计算开销非常大,尤其是在数据集很大时。

# 3. **自助法 (Bootstrapping)**:
# * 以自助采样法为基础。给定包含m个样本的数据集D,对它进行采样产生数据集D':每次随机从D中挑选一个样本,将其拷贝放入D',然后再将该样本放回初始数据集D中,使得该样本在下次采样时仍有可能被采到。这个过程重复执行m次后,我们就得到了包含m个样本的数据集D'。
# * 可以证明,初始数据集D中约有36.8%的样本未出现在采样数据集D'中。于是我们可将D'用作训练集,D\D'用作测试集。
# * 优点:在数据集较小、难以有效划分训练/测试集时很有用;能从初始数据集中产生多个不同的训练集。
# * 缺点:自助法产生的数据集改变了初始数据集的分布,会引入估计偏差。

# 为什么使用分层抽样,这样的好处有什么?
# **分层抽样 (Stratified Sampling)** 是一种抽样技术,它将总体(数据集)划分为若干个互不重叠的子群(称为“层”),然后从每个层中独立地进行简单随机抽样。在划分训练集和测试集时,特别是对于分类任务,通常是根据目标变量的类别进行分层。

# **好处:**
# 1. **保持类别比例一致性**:
# * 确保训练集和测试集中的各个类别的样本比例与原始数据集中各个类别的样本比例大致相同。
# * 这对于类别不平衡的数据集尤为重要。如果进行纯随机抽样,可能会导致训练集或测试集中某些少数类别的样本过少,甚至没有,从而影响模型的训练效果和评估的可靠性。
# 2. **提高模型的泛化能力和评估的准确性**:
# * 由于训练集和测试集都较好地代表了原始数据的类别分布,模型在训练时能学习到各个类别的特征,评估时也能更准确地反映模型在所有类别上的表现。
# * 避免了因随机划分导致训练集和测试集在类别分布上产生较大差异,从而使得模型评估结果更加稳定和可信。
# 3. **减少抽样误差**:
# * 相比于简单随机抽样,分层抽样通常能得到更具代表性的样本,从而减少因抽样带来的误差,使得基于样本的推断更加精确。

任务提示1

  • 切割数据集是为了后续能评估模型泛化能力
  • sklearn中切割数据集的方法为train_test_split
  • 查看函数文档可以在jupyter noteboo里面使用train_test_split?后回车即可看到
  • 分层和随机种子在参数里寻找

要从clear_data.csv和train.csv中提取train_test_split()所需的参数

1
2
3
4
5
6
7
#写入代码
from sklearn.model_selection import train_test_split
# 一般先取出X和y后再切割,有些情况会使用到未切割的,这时候X和y就可以用,x是清洗好的数据,y是我们要预测的存活数据'Survived'
X = data
y = train['Survived']
# 对数据集进行切割
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=0)
1
2
3
4
#写入代码

X_train.shape, X_test.shape

((668, 11), (223, 11))

【思考】 * 什么情况下切割数据集的时候不用进行随机选取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#思考回答
# 在以下情况下切割数据集时可能不需要或不适合进行随机选取:

# 1. **时间序列数据 (Time Series Data)**:
# * 对于时间序列数据,数据的顺序至关重要,因为它包含了时间依赖性。随机打乱顺序会破坏这种依赖关系。
# * 通常的做法是按时间顺序划分,例如,将较早的数据作为训练集,较晚的数据作为测试集(或验证集)。这更符合实际应用中用过去预测未来的场景。
# * 例如,用前几年的股票数据训练模型,用最近一年的数据测试模型。

# 2. **数据已经预先排序或具有特定结构**:
# * 如果数据集已经按照某种对分析有意义的顺序排列(例如,按地理区域、按实验批次等),并且你希望测试集来自与训练集不同的、特定的部分,那么可能需要按顺序或按特定规则划分,而不是随机划分。
# * 例如,在一个全国性的调查数据中,你可能想用某些省份的数据做训练,用另一些省份的数据做测试,以检验模型的地域泛化能力。

# 3. **数据集非常大且分布均匀**:
# * 当数据集非常庞大,并且可以合理假设数据是独立同分布 (i.i.d.) 且分布均匀时,简单地按顺序取一部分作为训练集,另一部分作为测试集,其效果可能与随机选取相差不大。随机选取的计算开销在这种情况下可能显得不必要。
# * 然而,即使在这种情况下,随机选取通常仍然是更稳妥的做法,以避免潜在的未知偏差。

# 4. **特定的交叉验证策略**:
# * 某些交叉验证方法本身就定义了非随机的划分方式。例如,在k折交叉验证中,虽然整体上数据被分成了k折,但每一折的选择是确定的(通常是按顺序分割)。留一法交叉验证更是每次只留一个特定的样本作为测试集。

# 5. **当需要完全复现特定的、非随机的划分结果时**:
# * 如果之前的研究或实验使用了某种特定的非随机划分方式,为了比较或复现结果,也需要采用相同的划分方式。

# 6. **流式数据或在线学习场景**:
# * 在数据持续不断流入的场景中,模型可能需要用新到达的数据进行测试或持续训练。这种情况下,测试集自然是最新的一部分数据,而不是从历史数据中随机抽取的。



任务二:模型创建

  • 创建基于线性模型的分类模型(逻辑回归)
  • 创建基于树的分类模型(决策树、随机森林)
  • 分别使用这些模型进行训练,分别的到训练集和测试集的得分
  • 查看模型的参数,并更改参数值,观察模型变化

提示

  • 逻辑回归不是回归模型而是分类模型,不要与LinearRegression混淆
  • 随机森林其实是决策树集成为了降低决策树过拟合的情况
  • 线性模型所在的模块为sklearn.linear_model
  • 树模型所在的模块为sklearn.ensemble
1
2
3
4
5
#写入代码

from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier

1
2
3
4
5
6
#写入代码
# 默认参数逻辑回归模型
lr = LogisticRegression()
lr.fit(X_train, y_train)


/root/.pyenv/versions/3.11.1/lib/python3.11/site-packages/sklearn/linear_model/_logistic.py:465: ConvergenceWarning: lbfgs failed to converge (status=1):
STOP: TOTAL NO. OF ITERATIONS REACHED LIMIT.

Increase the number of iterations (max_iter) or scale the data as shown in:
    https://scikit-learn.org/stable/modules/preprocessing.html
Please also refer to the documentation for alternative solver options:
    https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression
  n_iter_i = _check_optimize_result(
1
2
3
4
5
6
#写入代码
# 查看训练集和测试集score值
print("Training set score: {:.2f}".format(lr.score(X_train, y_train)))
print("Testing set score: {:.2f}".format(lr.score(X_test, y_test)))


Training set score: 0.80
Testing set score: 0.79
1
2
3
4
5
6
7
#写入代码
# 调整参数后的逻辑回归模型
lr2 = LogisticRegression(C=100)
lr2.fit(X_train, y_train)
print("Training set score: {:.2f}".format(lr2.score(X_train, y_train)))
print("Testing set score: {:.2f}".format(lr2.score(X_test, y_test)))

Training set score: 0.79
Testing set score: 0.78


/root/.pyenv/versions/3.11.1/lib/python3.11/site-packages/sklearn/linear_model/_logistic.py:465: ConvergenceWarning: lbfgs failed to converge (status=1):
STOP: TOTAL NO. OF ITERATIONS REACHED LIMIT.

Increase the number of iterations (max_iter) or scale the data as shown in:
    https://scikit-learn.org/stable/modules/preprocessing.html
Please also refer to the documentation for alternative solver options:
    https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression
  n_iter_i = _check_optimize_result(
1
2
3
4
5
# 默认参数的随机森林分类模型
rfc = RandomForestClassifier()
rfc.fit(X_train, y_train)
print("Training set score: {:.2f}".format(rfc.score(X_train, y_train)))
print("Testing set score: {:.2f}".format(rfc.score(X_test, y_test)))
Training set score: 1.00
Testing set score: 0.82

【思考】 * 为什么线性模型可以进行分类任务,背后是怎么的数学关系 * 对于多分类问题,线性模型是怎么进行分类的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#思考回答
# 为什么线性模型可以进行分类任务,背后是怎么的数学关系
# 线性模型(如逻辑回归 Logistic Regression,或者支持向量机 SVM 的线性核)之所以能用于分类任务,是因为它们通过以下方式将线性组合的输入特征映射到类别预测:
# 1. **线性组合**:首先,模型计算输入特征的线性组合,形式通常为 `z = w_1*x_1 + w_2*x_2 + ... + w_n*x_n + b`,或者用向量表示为 `z = w^T * x + b`。
# * `x` 是输入特征向量。
# * `w` 是模型学习到的权重(或系数)。
# * `b` 是偏置项(或截距)。
# 这个 `z` 值可以看作是样本点到决策边界的某种度量。
# 2. **决策函数/激活函数**:然后,这个线性组合的结果 `z` 会被传递给一个决策函数或激活函数,该函数将其转换为类别预测或类别概率。
# * **对于逻辑回归 (Logistic Regression)**:
# * 它使用 Sigmoid (Logistic) 函数:`p = 1 / (1 + e^(-z))`。
# * Sigmoid 函数将任意实数值 `z` 映射到 (0, 1) 区间,这个输出 `p` 可以解释为样本属于正类(通常是类别1)的概率。
# * 通过设定一个阈值(通常是0.5),如果 `p > 0.5` (即 `z > 0`),则预测为正类;否则预测为负类。
# * 因此,决策边界是 `z = 0`,即 `w^T * x + b = 0`,这是一个超平面。
# * **对于线性支持向量机 (Linear SVM)**:
# * 它直接使用 `z` 的符号来决定类别。如果 `z > 0`,预测为一类;如果 `z < 0`,预测为另一类。
# * SVM 的目标是找到一个能最大化两类样本之间间隔(margin)的决策边界(超平面)。
# 总结来说,线性模型通过学习一个线性决策边界(直线、平面或超平面)来分隔不同类别的样本。它们首先计算一个线性得分,然后通过一个非线性函数(如Sigmoid)或直接根据得分的符号来做出分类决策。

# 对于多分类问题,线性模型是怎么进行分类的
# 当类别数量大于两个时(即多分类问题),线性模型通常采用以下两种主要策略之一将问题转化为多个二分类问题:
# 1. **一对余 (One-vs-Rest, OvR) 或 一对所有 (One-vs-All, OvA)**:
# * **原理**:如果有个 `K` 个类别,OvR 策略会训练 `K` 个独立的二分类器。
# * 第 `i` 个分类器 (`i` 从 1 到 `K`) 会将类别 `i` 的样本视为正类,而将所有其他 `K-1` 个类别的样本视为负类。
# * **预测**:对于一个新的样本,它会被输入到所有 `K` 个分类器中。每个分类器都会输出一个分数或概率,表示该样本属于其对应“正类”的置信度。最终,样本被分配给那个给出最高置信度分数的类别。
# * **优点**:直观,实现相对简单,计算效率较高(只需要训练K个分类器)。
# * **缺点**:当类别数量很多时,每个二分类器的负类可能包含非常多样化的样本,可能导致类别不平衡问题。

# 2. **一对一 (One-vs-One, OvO)**:
# * **原理**:如果有个 `K` 个类别,OvO 策略会为每一对类别 `(i, j)` 训练一个二分类器,其中 `i != j`。总共需要训练 `K * (K-1) / 2` 个分类器。
# * 每个分类器只负责区分两个特定的类别。
# * **预测**:对于一个新的样本,它会被输入到所有 `K * (K-1) / 2` 个分类器中。每个分类器都会对样本属于其两个类别中的哪一个进行投票。最终,样本被分配给获得最多投票的类别。
# * **优点**:每个分类器只需要处理两个类别的数据,通常训练速度更快,且对于某些对类别不平衡不敏感的算法(如SVM)可能表现更好。
# * **缺点**:当类别数量 `K` 很大时,需要训练的分类器数量会急剧增加,导致计算成本和存储成本较高。

# **在 scikit-learn 中**:
# * `LogisticRegression` 默认使用 OvR 策略进行多分类 (可以通过 `multi_class` 参数设置为 `'multinomial'` 来使用 Softmax 回归,这是一种直接处理多分类的方法,但其基础仍然是线性的)。
# * `LinearSVC` (线性支持向量机) 默认使用 OvR 策略。


任务三:输出模型预测结果

  • 输出模型预测分类标签
  • 输出不同分类标签的预测概率

提示3

  • 一般监督模型在sklearn里面有个predict能输出预测标签,predict_proba则可以输出标签概率
1
2
#写入代码
pred = lr.predict(X_train)
1
2
#写入代码
pred[:10]
array([0, 1, 1, 1, 0, 0, 1, 0, 1, 1])
1
2
#写入代码
pred_proba = lr.predict_proba(X_train)
1
2
#写入代码
pred_proba[:10]
array([[0.60887905, 0.39112095],
       [0.17668722, 0.82331278],
       [0.40624596, 0.59375404],
       [0.18896449, 0.81103551],
       [0.87984221, 0.12015779],
       [0.91385758, 0.08614242],
       [0.13282516, 0.86717484],
       [0.90555878, 0.09444122],
       [0.05280619, 0.94719381],
       [0.10934565, 0.89065435]])

【思考】 * 预测标签的概率对我们有什么帮助

1
2
3
4
#思考回答