Skip to content

机器学习

一、机器学习概述

1. 人工智能三大概念

  • 人工智能:像人一样的思考,像人一样的行动,像人一样理性的思考,像人一样的理性行动
  • 机器学习:仿智,基于数据总结出规律,通过数据预测结果
  • 深度学习:仿生,搭建神经网络,输入层,隐藏层,输出层(收集信号|激活函数)
  • 三者的关系:机器学习是实现人工智能的一种途径,深度学习是机器学习的一种方法

2. 机器学习的应用领域和发展史

2.1 应用领域

  • 图像识别(人类看到的内容)
  • 在自然语言处理(人类交流的内容)
  • 数据分析数据挖掘

2.2 发展史

  • 20世纪50-70,符号主义,专家系统占主导
  • 20世纪80-2000,统计主义,机器学习
  • 21世纪初,神经网络,深度学习流派
  • 2017至今,transformer架构(bert|gpt)
  • 2022,AIGC

3. 机器学习常用术语

  • 样本:一行数据
  • 特征:一列数据
  • 标签:有未知参数的一列数据
  • 数据集:多个样本
    • 训练集
    • 测试集
    • 划分比例 - 8:2或7:3

4. 机器学习算法分类

  1. 有监督学习:有特征,有标签 - 预测
    • 标签值连续:分类问题 - 算法:KNN,决策树,随机森林
    • 标签值不连续:回归问题 - 算法:线性回归
  2. 无监督学习:有特征,无标签 - 聚类 - 算法:KMeans
  3. 半监督:有特征,有少量标签 - 减少专家标注成本
  4. 强化学习:环境,状态,行动,奖励 - 决策

5. 机器学习建模流程

  1. 准备数据

  2. 数据预处理

  3. 特征工程

    3.1 特征提取:原始数据中提取与任务相关的特征,构成特征向量

    3.2 特征预处理:量纲问题

    3.3 特征降维:将原始数据的维度降低,一般会对原始数据产生影响

    3.4 特征选择:选择其中一个与任务相关的特征集合子集

    3.5 特征组合:把多个的特征合并成一个特征

  4. 模型训练

  5. 模型预测

  6. 模型评估

6. 模型拟合问题

  1. 过拟合:在训练集上表现很好,在测试集上表现很差 - 特征过多
  2. 欠拟合:在训练集和测试集上都表现很差 - 特征过少
  3. 恰好拟合
  4. 泛化:具体的、个别的扩大为一般的能力

7. 机器学习开发环境

  • 安装:pip install scikit-learn
  • 使用:from sklearn.linear_model import LinearRegression

二、线性回归

1. 线性回归简介

1.1 概念

利用 回归方程(函数) 对 一个或多个自变量(特征值)和因变量(目标值)之间 关系进行建模的一种分析方式。y = W的转置@ X

1.2 分类

一元线性回归、多元线性回归

2. 线性回归求解

2.1 线性回归API

python
from sklearn.linear_model import LinearRegression
# 获取数据
x = [[160], [166], [172], [174], [180]]  # 身高
y = [56.3, 60.6, 65.1, 68.5, 75]  # 体重

# 模型训练
# 创建模型(实例化)
model = LinearRegression()
# 训练模型(拟合)
model.fit(x, y)  # 通过特征 + 标签训练模型

# 模型预测
x_pre = [[176]]  # 预测的特征
y_pre = model.predict(x_pre)  # 预测的标签
# 查看预测结果
print(y_pre)
# 查看预测权重(斜率)和偏置(截距)
print(f'权重:{model.coef_}, 偏置:{model.intercept_}')

2.2 损失函数

2.2.1 误差

用预测值y – 真实值y就是误差

2.2.2 损失函数
  • 衡量每个样本预测值与真实值效果的函数,也叫代价函数、成本函数、目标函数
  • 分类:
    • 最小二乘
    • 均方误差
    • 均方根误差
    • 平均绝对误差
2.2.3 导数
  • 导数:函数上某一个点求切线就是导数。瞬时速度变化率
  • 偏导数:U是关于x、y、z的函数,记为u(x, y, z),只在x分量上求导,则为求偏导
  • 利用导数求极值:导数为0的位置即为极值点

2.3 正规方程法

  • 一元线性方程:损失函数的导数 = 0,求解
  • 多元线性方程:损失函数的偏导 = 0,求解
  • 注:不一定有解,如果矩阵不可逆,那就没法求解,所以需要梯度下降法

2.4 梯度下降法

2.4.1 梯度

概念:梯度是一个向量,有方向(变化率最快的上升方向),有大小(损失函数的导数/偏导数)

2.4.2 梯度下降法

公式:w新 = w旧 - a(学习率)*梯度

w和梯度可以是向量:(w_1, w_2, … w_n) = (w_1, w_2, … w_n) - a * (梯度1,梯度2… 梯度n)

学习率:俗称步长,学习率太小学的慢;学习率太大,梯度下降中抖动、震荡、易错过最优解。一般在0.001~0.01

分类:全梯度下降算法FGD,随机梯度下降算法SGD,小批量梯度下降算法mini-batch,随机平均梯度下降算法SAG

3. 回归模型评估方法

  • 均方误差MSE: $$ MSE = \frac{1}{n}\sum_{i=1}^{n}\left(y_i - \hat{y}_i\right)^2 $$

  • 平均绝对误差MAE: $$ MAE = \frac{1}{n}\sum_{i=1}^{n}\left|y_i - \hat{y}_i\right| $$

  • 均方根误差RMSE: $$ RMSE = \sqrt{\frac{1}{n}\sum_{i=1}^{n}\left(y_i - \hat{y}_i\right)^2} $$

  • (MAE\RMSE) 比较接近,RMSE一般大于MAE,如果过于大,是异常的表现,MSE放大误差

4. 线性回归案例 - 波士顿房价预测

python
# from sklearn.datasets import load_boston
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split  # 划分训练集测试集
from sklearn.preprocessing import StandardScaler  # 数据标准化
from sklearn.linear_model import SGDRegressor  # 正规方程法
from sklearn.metrics import mean_squared_error, mean_absolute_error, root_mean_squared_error  # 损失函数

# 1. 准备数据(包,离线)
# 1.1 数据需要实例化
# boston = load_boston()
data_url = "http://lib.stat.cmu.edu/datasets/boston"
raw_df = pd.read_csv(data_url, sep=r"\s+", skiprows=22, header=None)
data = np.hstack([raw_df.values[::2, :], raw_df.values[1::2, :2]])
target = raw_df.values[1::2, 2]

# 2. 数据预处理(划分训练集和测试集)
x_train, x_test, y_train, y_test = train_test_split(data, target, test_size=0.2)

# 3. 特征工程(标准化)
transfer = StandardScaler()
# x_train 需要转标准化,训练一次transfer,此时transfer才有标准
x_train = transfer.fit_transform(x_train)  # 以x_train为标准
x_test = transfer.transform(x_test)

# 4. 模型训练(梯度下降法)
model = SGDRegressor()  # 自适应
# model = SGDRegressor(max_iter=1000)  # 最大迭代次数
# model = SGDRegressor(learning_rate='constant', eta0=0.01) # 固定学习率
model.fit(x_train, y_train)

# 5. 模型预测
y_predict = model.predict(x_test)

# 6. 模型评估  y_predict和y_test
print(mean_squared_error(y_test, y_predict))
print(mean_absolute_error(y_test, y_predict))
print(root_mean_squared_error(y_test, y_predict))

5. 欠拟合与过拟合分析

5.1 欠拟合

在训练集上表现不好,在测试集上表现不好

解决方法:添加特征项

5.2 过拟合

在训练集上表现好,在测试集上表现不好

解决方法:

  • L1正则化Lasso:权重可能更新到0从而放弃当前的特征 $$ J(w) = \text{MSE}(w) + \alpha \sum_{i=1}^{n} |w_i| $$ α 叫做惩罚系数,该值越大则权重调整的幅度就越大,即:表示对特征权重惩罚力度就越大

  • L2正则化Ridge:权重不断靠近0,但是不会等于0(重点) $$ J(w) = \text{MSE}(w) + \alpha \sum_{i=1}^{n} w_i^2 $$ α 叫做惩罚系数,该值越大则权重调整的幅度就越大,即:表示对特征权重惩罚力度就越大

5.3 正好拟合

三、KNN算法

1. KNN算法简介

  1. 算法思想:如果一个样本在特征空间中的 k 个最相似的样本中的大多数属于某一个类别,则该样本也属于这个类别
  2. 分类问题:基于最近的K个样本进行标签的投票,票数多的就代表我的标签
  3. 回归问题:基于最近的K个样本进行标签的统计,求平均值代表我的标签
  4. K值:K值过小 - 过拟合 K值过大 - 欠拟合

2. API实现

2.1 分类(KNeighborsClassifier)

python
from sklearn.neighbors import KNeighborsClassifier

# 获取数据
# 特征
x = [[39, 0, 31], [3, 2, 65], [2, 3, 55], [9, 38, 2], [8, 34, 17], [5, 2, 57], [39, 0, 31], [21, 17, 5], [45, 2, 9]]
# 标签
y = ['喜剧片', '动作片', '动作片', '爱情片', '爱情片', '动作片', '喜剧片', '喜剧片', '喜剧片']

# 训练模型
model = KNeighborsClassifier(n_neighbors=5)  # k默认是5
model.fit(x, y)

# 预测
print(model.predict([[23, 3, 17]]))

2.2 回归(KNeighborsRegressor)

python
from sklearn.neighbors import KNeighborsRegressor

# 获取数据
# 特征
x = [[39, 0, 31], [3, 2, 65], [2, 3, 55], [9, 38, 2], [8, 34, 17], [5, 2, 57], [39, 0, 31], [21, 17, 5], [45, 2, 9]]
# 标签(电影评分,连续的值)
y = [5.5, 4.3, 5.9, 4.5, 6.5, 5.4, 5.5, 4.9, 6.1]

# 训练模型
model = KNeighborsRegressor(n_neighbors=3)  # k默认是5
model.fit(x, y)

# 预测
print(model.predict([[23, 3, 17]]))

3. 特征预处理

3.1 归一化

3.1.1 公式

$$ X' = \frac{x - \min}{\max - \min} $$

符号含义
X归一化后的值(0~1之间)
x原始数据值
min数据集中的最小值
max数据集中的最大值
3.1.2 缺点

最大值最小值的异常会影响当前特征

3.1.3 API
python
from sklearn.preprocessing import MinMaxScaler

data = [[90, 2, 10, 40], [60, 4, 15, 45], [75, 3, 13, 46]]
scaler = MinMaxScaler()
# 没有标准,需要fit+ transform
new_data = scaler.fit_transform(data)
print(new_data)

3.2 标准化

3.2.1 公式

$$ X' = \frac{x - \text{mean}}{\sigma} $$

$$ \text{mean} = \frac{1}{n} \sum_{i=1}^{n} x_i = \frac{x_1 + x_2 + \cdots + x_n}{n} $$

$$ \sigma = \sqrt{\frac{1}{n} \sum_{i=1}^{n} (x_i - \text{mean})^2} = \sqrt{\frac{(x_1 - \text{mean})^2 + (x_2 - \text{mean})^2 + \cdots + (x_n - \text{mean})^2}{n}} $$

符号含义
X标准化后的值
x原始数据值
mean数据集的均值(平均值)
σ数据集的标准差
3.2.3 API
python
from sklearn.preprocessing import StandardScaler

l1 = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
scaler = StandardScaler()
# 没有标准,需要fit+ transform
new_data = scaler.fit_transform(l1)
print(new_data)

4. 鸢尾花案例

python
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import StandardScaler

# 1. 获取数据
iris = load_iris()


# 查看数据
def get_data():
    print(iris.data)
    print(iris.target)
    print(iris.feature_names)
    print(iris.target_names)


# 绘制数据图形
def draw_data():
    # 绘制三次,准备颜色列表
    colors = ['r', 'g', 'b']
    # 特征数据添加说明
    df = pd.DataFrame(iris.data, columns=iris.feature_names)
    # 数据添加标签
    df['target'] = iris.target
    plt.figure(figsize=(10, 10))
    for i in range(len(colors)):
        plt.scatter(df.query(f'target == {i}')[iris.feature_names[0]],
                    df.query(f'target == {i}')[iris.feature_names[3]],
                    c=colors[i],
                    label=iris.target_names[i],
                    s=100)
    plt.legend()
    plt.xlabel(iris.feature_names[0])
    plt.ylabel(iris.feature_names[3])
    plt.show()


def predict():
    # 2. 数据预处理
    x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.2,
                                                        random_state=3)  # random_state 是随机种子
    # 3. 特征工程 (根据数据,可以不做)
    scaler = StandardScaler()
    x_train = scaler.fit_transform(x_train)  # 以x_train为标准,第一次需要fit+ transform
    x_test = scaler.transform(x_test)  # 第二次不需要fit
    # 4. 模型训练
    model = KNeighborsClassifier(n_neighbors=5)  # k默认是5
    model.fit(x_train, y_train)
    # 4.1 模型评估,model自身评分(正确率)
    print(model.score(x_test, y_test))  # 注:参数为x的测试集和y的测试集
    print(model.predict_proba(x_test))  # 预测概率的投票结果显示

    # 4.2 模型测试(验证) + 评估
    y_pre = model.predict(x_test)
    print(accuracy_score(y_test, y_pre))  # 注:参数为y的测试集(真实结果)和y的预测结果

    # 4.3 模型预测(自己准备数据)
    text_xdata = [[4.8, 3.3, 1.1, 0.1]]
    text_ydata = [0]
    # 准备的数据也要标准化
    text_xdata = scaler.transform(text_xdata)
    y_text_pre = model.predict(text_xdata)
    print(y_text_pre)  # 准备的数据是按照0的特征准备的,所以预测结果大海率也是0


if __name__ == '__main__':
    # get_data()
    # draw_data()
    predict()

5. 交叉验证和网格搜索

5.1 交叉验证

交叉验证:是一种数据集的分割方法,将训练集划分为 n 份,拿一份做验证集、其他n-1份做训练集

cv: 划分的折数,分了几次就要训练几次,最后取平均数

5.2 网格搜索

网格搜索:模型调参的工具,将若干参数传递给网格搜索对象,它自动帮我们完成不同超参数的组合、模型训练、模型评估,最终返回一组最优的超参数。一般与交叉验证一起使用。

5.3 API

python
from sklearn.model_selection import GridSearchCV
# 训练模型
model = KNeighborsClassifier()
# 交叉验证和网格搜索
# estimator:估计器模型
# param_grid:估计器参数,字典类型
# cv:指定几折交叉验证
new_model = GridSearchCV(estimator=model, param_grid={'n_neighbors': [1, 3, 5, 7, 9]}, cv=4)
new_model.fit(x_train, y_train)
# 交叉验证和网格搜索的结果分析
print('best_score_', new_model.best_score_)  # 最高分
print('best_params_', new_model.best_params_)  # 最优超参
print('best_estimator_', new_model.best_estimator_)  # 最优模型
print('cv_results_', new_model.cv_results_)  # cv结果

6. 分类问题评估

6.1 混淆矩阵

预测为正例预测为反例
真实为正例TP(正确正例)FN(正例-猜对正(TP))
真实为反例FP(反例-猜对反(TN))TN(正确反例)

6.2 分类评估方法

  • 准确率:猜对的样本/总的样本数量
  • 精确率:猜对的正样本/预测的正样本 - TP/(TP+FP)
  • 召回率:猜对的正样本/真实的正样本 - TP/(TP+FN)
  • F1-Score: 2*精确率*召回率/(精确率+召回率) - 用于平衡精确率和召回率

6.3 API

python
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix

# 输出混淆矩阵,指定标签顺序为['恶','良']-[正例,反例]
print('混淆矩阵', confusion_matrix(y_true, y_pre1, labels=['恶性', '良性']))

# 输出准确率
print('准确率:', accuracy_score(y_true, y_pre1))

# 输出精确率(以'恶'为正类)
print('精确率:', precision_score(y_true, y_pre1, pos_label='恶性'))

# 输出召回率(以'恶'为正类)
print('召回率:', recall_score(y_true, y_pre1, pos_label='恶性'))

# 输出F1-score(以'恶'为正类)
print('F1-score:', f1_score(y_true, y_pre1, pos_label='恶性'))

四、决策树

1. 决策树简介

  • 决策树是一种树形结构,树中每个内部节点表示一个特征上的判断,每个分支代表一个判断结果的输出,每个叶子节点代表一种分类结果
  • 决策树的建立过程
    • 特征选择:选取有较强分类能力的特征。
    • 决策树生成:根据选择的特征生成决策树。
    • 决策树也易过拟合,采用剪枝的方法缓解过拟合。

2. CART决策树(分类与回归树(Classification and Regression Tree))

2.1 核心原理

  1. 强制二分

分类问题:是xxx/不是xxx

回归问题:x>=30 / x<30

  1. 选择有价值的指标

基尼系数(Gini):衡量不确定性减少的程度。熵表示数据集的混乱程度,信息增益就是“在某个特征条件下,熵减少了多少”。减少得越多,说明该特征对分类越有用

信息增益熵(Gain):衡量数据集不纯度的程度。Gini值表示从数据集中随机抽取两个样本,其类别标签不一致的概率。Gini值越小,数据越纯。 $$ 熵:H(D) = -\sum_{k=1}^{|\mathcal{Y}|} p_k \log_2 p_k $$

$$ 信息增益:\text{Gain}(D, A) = H(D) - \sum_{v=1}^{V} \frac{|D_v|}{|D|} H(D_v) $$

$$ 基尼系数:\text{Gini}(D) = 1 - \sum_{k=1}^{|\mathcal{Y}|} p_k^2 $$

维度说明
p~k~第 k类样本在数据集中的占比
D数据集
|y|类别总数
A某个特征
V特征A的取值个数
D~v~特征A取第v个值时对应的子集
|.|表示集合大小
  1. 一层一层往下分(重复1,2)

  2. 剪枝

防止过拟合,设置最大层数,设置叶子节点的数量,设置分裂的最小数量...

2.2 独热编码 - one-hot(pandas中的API)

新数据 = pd.get_dummies(数据)

eg:

sex = ['male','female'] -> sex_male =[True,False] , sex_female = [True,False]

2.3 分类API

python
from sklearn.tree import DecisionTreeClassifier # 模型
from sklearn.metrics import classification_report # 分类报告
# 训练模型
model = DecisionTreeClassifier()
# Criterion: 特征选择标准,"gini"或"entropy",前者代表基尼系数,后者代表信息增益。默认"gini",即CART算法
# min_samples_split:内部节点再划分所需最小样本数
# min_samples_leaf:叶子节点最少样本数
# max_depth:决策树最大深度


model.fit(x_train, y_train)
# 分类性能查看
print(classification_report(y_test, y_pre))

3. CART分类树案例:泰塔尼克号生存预测

python
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, classification_report
import matplotlib.pyplot as plt
from sklearn.tree import plot_tree

# 1. 准备数据
# 1.1 加载数据
df = pd.read_csv('titanic_train.csv', sep=',', encoding='utf-8')
# 查看数据是否有缺失
# df.info()
# 1.2 数据清洗(删除,填充)
x = df[['Pclass', 'Age', 'Sex']]
x = x.copy()
y = df['Survived']
x['Age'] = x['Age'].fillna(x['Age'].mean())
# (独)热编码one-hot -> 字符串转化成布尔值
x_new = pd.get_dummies(x)

# 2. 特征工程(不需要)
# 3. 划分特征集
x_train, x_test, y_train, y_test = train_test_split(x_new, y, test_size=0.2)
# 4. 训练模型
model = DecisionTreeClassifier()
model.fit(x_train, y_train)
# 5. 模型预测
y_pre = model.predict(x_test)
# 6. 模型评估
print('准确率:', accuracy_score(y_test, y_pre))
print('精确率:', precision_score(y_test, y_pre, pos_label=1))
print('召回率:', recall_score(y_test, y_pre, pos_label=1))
print('F1-score:', f1_score(y_test, y_pre, pos_label=1))
# 分类性能查看
print(classification_report(y_test, y_pre))
# 7. 绘制决策树
plt.figure(figsize=(50, 50))
plot_tree(model, max_depth=10, filled=True)  # 不要绘制太多层
# 将绘制的内容保存成一张图片
plt.savefig('./titanic.png')

4. CART回归树案例:波士顿房价预测

python
# API:from sklearn.tree import DecisionTreeRegressor
# model = DecisionTreeRegressor()


import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split  # 划分训练集测试集
from sklearn.preprocessing import StandardScaler  # 数据标准化
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import mean_squared_error, mean_absolute_error, root_mean_squared_error  # 损失函数

# 1. 准备数据(包,离线)
# 1.1 数据需要实例化
raw_df = pd.read_csv("./Boston.txt", sep=r"\s+", skiprows=22, header=None)
data = np.hstack([raw_df.values[::2, :], raw_df.values[1::2, :2]])
target = raw_df.values[1::2, 2]

# 2. 数据预处理(划分训练集和测试集)
x_train, x_test, y_train, y_test = train_test_split(data, target, test_size=0.2)

# 3. 特征工程(标准化)
transfer = StandardScaler()
# x_train 需要转标准化,训练一次transfer,此时transfer才有标准
x_train = transfer.fit_transform(x_train)  # 以x_train为标准
x_test = transfer.transform(x_test)

# 4. 模型训练
model = DecisionTreeRegressor()
model.fit(x_train, y_train)

# 5. 模型预测
y_predict = model.predict(x_test)

# 6. 模型评估(回归问题)  y_predict和y_test
print(mean_squared_error(y_test, y_predict))
print(mean_absolute_error(y_test, y_predict))
print(root_mean_squared_error(y_test, y_predict))

5. 决策树剪枝

原因:防止决策树过拟合的一种正则化方法;提高其泛化能力。

概述:把子树的节点全部删掉,使用用叶子节点来替换

方法:

  • 预剪枝:在决策树生成过程中,对每个节点在划分前先进行估计,若当前节点的划分不能带来决策树泛化性能提升,则停止划分并将当前节点标记为叶节点
  • 后剪枝:先从训练集生成一棵完整的决策树,然后自底向上地对非叶节点进行考察,若将该节点对应的子树替换为叶节点能带来决策树泛化性能提升,则将该子树替换为叶节点。

五、集成学习

1. 集成学习

集成学习是机器学习中的一种思想,它通过多个模型的组合形成一个精度更高的模型,参与组合的模型称为弱学习器(基学习器)。

1.1 Bagging(随机森林)

  • 有放回的抽样,产生不同的训练集,从而训练不同的学习器
  • 通过平权投票、多数表决的方式决定预测结果
  • 并行训练

1.2 Boosting(Adaboost、GBDT、XGBoost、LightGBM)

  • 每一个训练器重点关注前一个训练器不足的地方进行训练
  • 通过加权投票的方式,得出预测结果
  • 串行训练

2. 随机森林(Bagging+决策树)

API:sklearn.ensemble.RandomForestClassifier()

参数:

  • n_estimators: 决策树数量(默认 = 10)

  • criterion: 特征选择标准,可选 "entropy""gini"(默认 = "gini"

  • max_depth: 树的最大深度(默认 = None,表示树会尽可能生长)

  • max_features: 构建决策树时使用的最大特征数量

  • "auto"max_features = sqrt(n_features)

  • "sqrt"max_features = sqrt(n_features)(同 "auto"

  • "log2"max_features = log2(n_features)

  • Nonemax_features = n_features

  • bootstrap: 是否采用有放回抽样(默认 = True);若为 False,将使用全部训练样本

  • min_samples_split: 结点分裂所需最小样本数(默认 = 2)

  • 如果节点样本数少于 min_samples_split,则不会再进行划分。

  • 如果样本量不大,不需要设置这个值。

  • 如果样本量数量级非常大,则推荐增大这个值。

  • min_samples_leaf: 叶子节点的最小样本数(默认 = 1)

  • 如果某叶子节点数目小于样本数,则会和兄弟节点一起被剪枝。

  • 较小的叶子结点样本数量使模型更容易捕捉训练数据中的噪声。

  • min_impurity_split: 节点划分最小不纯度(默认 = 1e-7)

  • 如果某节点的不纯度(基尼系数、均方差等)小于这个阈值,则该节点不再生成子节点,并变为叶子节点。

  • 一般不推荐改动默认值。

python
import pandas as pd
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, recall_score, f1_score, precision_score

# 1. 准备数据
# 1.1 加载数据
df = pd.read_csv('../day03/titanic_train.csv', sep=',', encoding='utf-8')
# 查看数据是否有缺失
# df.info()
# 1.2 数据清洗(删除,填充)
x = df[['Pclass', 'Age', 'Sex']]
x = x.copy()
y = df['Survived']
x['Age'] = x['Age'].fillna(x['Age'].mean())
# (独)热编码one-hot -> 字符串转化成布尔值
x_new = pd.get_dummies(x)

# 2. 特征工程(不需要)
# 3. 划分特征集
x_train, x_test, y_train, y_test = train_test_split(x_new, y, test_size=0.2, random_state=3)

# 4.1 训练模型(决策树)
model1 = DecisionTreeClassifier(random_state=3)
model1.fit(x_train, y_train)
# 4.2 训练模型(随机森林默认参数)
model2 = RandomForestClassifier(random_state=3)
model2.fit(x_train, y_train)
# 4.3 训练模型(随机森林超参优化)
model3 = RandomForestClassifier(random_state=3)
# None表示让树无限增长
model3 = GridSearchCV(model3, param_grid={'n_estimators': [10, 20, 30, 40, 50], 'max_depth': [6, 8, 10, None]}, cv=5)
model3.fit(x_train, y_train)

# 5. 模型预测
y_pre1 = model1.predict(x_test)
y_pre2 = model2.predict(x_test)
y_pre3 = model3.predict(x_test)
# 6. 模型评估
print('model1准确率:', accuracy_score(y_test, y_pre1))
print('model1精确率:', precision_score(y_test, y_pre1, pos_label=1))
print('model1召回率:', recall_score(y_test, y_pre1, pos_label=1))
print('model1 F1-score:', f1_score(y_test, y_pre1, pos_label=1))
print('model2准确率:', accuracy_score(y_test, y_pre2))
print('model2精确率:', precision_score(y_test, y_pre2, pos_label=1))
print('model2召回率:', recall_score(y_test, y_pre2, pos_label=1))
print('model2 F1-score:', f1_score(y_test, y_pre2, pos_label=1))
print('model3准确率:', accuracy_score(y_test, y_pre3))
print('model3精确率:', precision_score(y_test, y_pre3, pos_label=1))
print('model3召回率:', recall_score(y_test, y_pre3, pos_label=1))
print('model3 F1-score:', f1_score(y_test, y_pre3, pos_label=1))
print(model3.best_params_)

六、聚类算法

1. 简介

根据样本之间的相似性,将样本划分到不同的类别中 - 无监督学习算法

2. 分类

  • 根据聚类颗粒度分类
    • 细聚类
    • 粗聚类
  • 根据实现方法分类
    • K-means
    • 层次聚类
    • DBSCAN聚类
    • 谱聚类

3. K-means

3.1 实现步骤

  1. 事先确定常数K(聚类类别数)
  2. 随机选择K个样本点作为初始聚类中心
  3. 计算每个样本点到K个中心的距离,选择最近的聚类中心点作为标记类别
  4. 根据每个类别中的样本点,重新计算新的聚类中心
  5. 若新的聚类中心与原聚类中心相同,则停止,否则一直重复3,4步

3.2 聚类模型评估方法

  • SSE+肘方法 $$ 簇内误差平方和SSE = \sum_{i=1}^k \sum_{p \in C_i} |p - m_i|^2 $$

  • C~i~:表示第 i个簇

  • k:表示聚类中心的个数(即簇的数量)

  • p:表示某个簇内的样本点

  • m~i~:表示第 i个簇的质心(均值向量)

SSE 越小,聚类效果越好

  • SC轮廓系数(看峰值)

  • CH轮廓系数(越大越好,但无限增长,仅供参考)

3.3 API

python
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs  # 构造测试数据
model.inertia_  # sse评估
silhouette_score(x, pre)  # sc评估
calinski_harabasz_score(x, pre)  # ch评估
model.cluster_centers_  # 质心获取

3.4 K-means案例 - 客户画像划分

python
import os

os.environ['OMP_NUM_THREADS'] = '1'
from sklearn.metrics import silhouette_score, calinski_harabasz_score
import pandas as pd
from matplotlib import pyplot as plt
from sklearn.cluster import KMeans

# 1. 准备数据
df = pd.read_csv('customers.csv', sep=',', encoding='utf-8')
x = df.values[:, [3, 4]]


# 2. 寻找划分最优簇个数
def find_best_k():
    sse_list = []
    sc_list = []
    ch_list = []
    # 评估最优簇个数的思想
    # CH轮廓系数
    # SSE肘部法
    # SC轮廓系数(无限增长,参考)
    for i in range(2, 20):
        model = KMeans(n_clusters=i, random_state=9)
        pre = model.fit_predict(x)
        sse_list.append(model.inertia_)  # sse评估
        sc_list.append(silhouette_score(x, pre))  # sc评估
        ch_list.append(calinski_harabasz_score(x, pre))  # ch评估

    # sse展示
    plt.scatter(range(2, 20), sse_list)
    plt.xticks(range(2, 20))
    plt.show()
    # sc展示
    plt.scatter(range(2, 20), sc_list)
    plt.xticks(range(2, 20))
    plt.show()
    # ch展示
    plt.scatter(range(2, 20), ch_list)
    plt.xticks(range(2, 20))
    plt.show()


model = KMeans(n_clusters=5, random_state=9)
pre = model.fit_predict(x)
colors_list = ['red', 'blue', 'green', 'cyan', 'magenta']
labels_list = ['Standard', 'Traditional', 'Normal', 'Youth', 'TA']
print(pre == 4)  # 布尔值,可以做索引
print(x[pre == 4])  # 获取属于第4簇(布尔值为True)的点
print(model.cluster_centers_)  # 当前簇心
for i in range(len(labels_list)):
    # plt.scatter(x[pre == i, 0], x[pre == i, 1], c=colors_list[i], label=labels_list[i])
    plt.scatter(x[pre == i][:, 0], x[pre == i][:, 1], c=colors_list[i], label=labels_list[i])
# 绘制簇心
plt.scatter(model.cluster_centers_[:, 0], model.cluster_centers_[:, 1], c='black', s=100, label='centers')
plt.legend()
# 绘制坐标轴
plt.xlabel('Salary')
plt.ylabel('pay')
# 绘制标题
plt.title('clusters of customers')
plt.show()

补充

布尔索引

python
# 布尔索引
import numpy as np

arr = np.array([3, 4, 5, 6, 7])
data = np.array([[1, 2], [4, 5], [7, 8], [10, 11], [13, 14]])
# numpy数组(特有用法)与python列表
print(arr - 5)  # 加减运算
print(arr > 5)  # 比较运算 -> 布尔值
print(arr[arr > 5])  # 布尔索引,只保留布尔索引为Ture的值

# 示例
print(arr == 5)
print(data[arr == 5])