机器学习

【了解】人工智能三大概念

人工智能

  • Artificial Intelligence 人工智能

  • 释义 - 仿智; 像人一样机器智能的综合与分析;机器模拟代替人类

image-20230830154440581

  • 释义:是一个系统,像人那样思考 像人那样理性思考

  • 释义:是一个系统,像人那样活动 像人那样合理行动

机器学习

  • Machine Learning 释义:机器学习

  • 释义:让机器自动学习,而不是基于规则的编程(不依赖特定规则编程)

  • 人类识别车:根据车的特征归纳出车的规律;来了一个新的图片,判断预测是否是车

  • 机器学习识别车: 从数据中获取规律;来了一个新的数据,产生一个新的预测

深度学习

深度学习(DL, Deep Learning) : ,也叫深度神经网络,大脑仿生,设计一层一层的神经元模拟万事万物

三者之间的关系

机器学习是实现人工智能的一种途径

深度学习是机器学习的一种方法

模型学习方式方式

基于规则的学习

•基于规则的学习 : 程序员根据经验利用手工的if-else方式进行预测

但是有好多问题, 无法明确的写下规则,此时我们无法使用规则学习的方式来解决这一类问题,比如:

  • 图像和语音识别
  • 自然语言处理

举例:我们尝试通过基于规则的学习方式让计算机识别大象,大象千差万别, 有的是实物,有的是雕塑,有的是画,我们无法通过创建一套规则的方式让计算机准确识别每一头大象, 此时我们需要一种新的方法来解决这类问题。

基于模型的学习

基于模型的学习就是通过编写机器学习算法,让机器自己学习从历史数据中获得经验、训练模型

案例巩固

比如房价预测,数据如下图

image-20220117155634566

  • 我们可以使用一条直线尽可能多的通过这些点,不通过的点尽量分布在直线的两侧,利用这条直线所表示的线性关系,我们就可以预测房价。
  • 直线可以写成y=ax+b,若a,b已知,我们就能够预测房价。机器学习中a,b称为 参数 ,y=ax+b称为 模型 。通常a,b未知,是我们需要求解的量。

【了解】人工智能应用领域和发展史

应用领域

用户分析:社交网络、影评、商品评论

搜素引擎:网页、图片、规频、新闻、学术、地图

信息推荐:新闻、商品、游戏、书籍

图片识别:人像、用品、劢物、交通工具

机器翻译、摘要生成 … …

生物信息学习 … … 多模态 AR/VR

发展历史

image-20230830163616925

1956年夏季,以麦卡赛、明斯基、罗切斯特和香农等为首的一批有远见卓识的年轻科学家在一起聚会,共同研究和探讨用机器模拟智能的一系列有关问题,并首次提出了“人工智能”这一术语,它标志着“人工智能”这门新兴学科的正式诞生。

1956 年被认为是人工智能元年

机器学习发展三要素

  • 数据、算法、算力三要素相互作用,是AI发展的基石
  1. CPU:负责调度任务、计算任务等;主要适合I\O密集型的任务
  2. GPU:更加适合矩阵运算;主要适合计算密集型任务
  3. TPU:Tensor,专门针对神经网络训练设计一款处理器

【掌握】基础概念

样本,特征,目标值

image-20260613101056545

image-20260226171204598

样本(sample) :一行数据就是一个样本;多个样本组成数据集;有时一条样本被叫成一条记录

特征(feature) :一列数据一个特征,有时也被称为属性。特征是从数据中抽取出来的,对结果预测有用的信息

标签/目标(label/target) :模型要预测的那一列数据。本场景是就业薪资

数据集划分

image-20260226171530667

数据集可划分两部分:训练集、测试集 比例:8 : 2,7 : 3

训练集(training set) :用来训练模型(model)的数据集

测试集(testing set):用来测试模型的数据集

扩展:机器学习中的训练集、测试集、验证集分别用在什么地方

1- 训练集:用来对模型进行训练

2- 测试集:在对模型优化过程中,判断优化是否有作用

3- 验证集:用来最终考核模型

大多数情况下,测试集和验证集是同一份数据。

【熟悉】算法分类

有监督学习

  • 定义:输入数据是由输入特征值和目标值所组成,即输入的训练数据有标签(目标值)的

  • 数据集:需要人工标注数据

    image-20230830173907526

分类

  • 目标值(标签值)是不连续

  • 分类种类:二分类、多分类任务、

image-20230830174449204

回归

目标值(标签值)是连续

image-20230830174516047

无监督学习

  • 定义:输入数据没有被标记,即样本数据类别未知,没有标签,根据样本间的相似性,对样本集聚类,以发现事物内部 结构及相互关系。
  • 数据集:不需要标注数据

无监督学习特点:

1 训练数据无标签

2 根据样本间的相似性对样本集进行聚类,发现事物内部结构及相互关系

image-20230830174630247

半监督学习

工作原理:

1 让专家标注少量数据,利用已经标记的数据(也就是带有类标签)训练出一个模型

2 再利用该模型去套用未标记的数据

3 通过询问领域专家分类结果与模型分类结果做对比,从而对模型做进一步改善和提高

image-20230830174748910

半监督学习方式可大幅降低标记成本

【了解】强化学习

思考、行动、观察、奖励

1 强化学习(Reinforcement Learning):机器学习的一个重要分支

2 应用场景:里程碑AlphaGo围棋、各类游戏、对抗比赛、无人驾驶场景

3 基本原理:通过构建四个要素-> agent,环境状态,行动,奖励

agent根据环境状态进行行动获得最多的累计奖励。。

image-20260301111147510

小孩子学走路:

​ (1) 小孩就是 agent,他试图通过采取(即行走)来操纵环境(地面),

​ (2) 并且从一个状态转变到另一个状态(即他走的每一步),

​ (3) 当他完成任务的子任务(即走了几步)时,孩子得到奖励(给巧克力吃),

​ (4) 并且当他不能走路时,就不会给巧克力。

总结

image-20230830175447247

image-20230830175454832

【掌握】机器学习的建模流程

1- 准备数据
2- 数据清洗
3- 特征工程
    特征提取
    *特征预处理
    特征降维
    特征选择
    特征组合
4- 模型训练
5- 模型评估
6- 模型上线

image-20260613110303335

【理解】特征工程

特征提取和特征选择的区别?
特征提取:一般是领域专家进行。数据是从无到有的过程
特征选择:一般是程序员进行,从多个特征列中,选择出有价值的特征。

特征工程

image-20230831101912582

从数据集角度来看: 一列一列的数据为特征。

从模型训练角度来看: 对预测结果有用的属性为特征

特征工程是:利用专业背景知识和技巧处理数据,让机器学习算法效果最好。这个过程就是特征工程

数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已。

特征提取

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

对于文本、图片这种非行列形式的数据行列形式转换,

一旦转换成行列形式一列就是特征

这个过程是由专家来干的

特征预处理

特征对模型产生影响;因量纲问题,有些特征对模型影响大、有些影响小

image-20230831103613657

将不同的单位的特征数据转换成同一个范围内,使训练数据中不同特征对模型产生较为一致的影响

特征降维

将原始数据的维度降低,叫做特征降维

比如:3D->2D

会丢失部分信息。降维就需要保证数据的主要信息要保留下来

原始数据会发生变化,不需要了解数据本身是什么含义,它保留了最主要的信息

特征选择

原始数据特征很多,但是对任务相关是其中一个特征集合子集。

image-20230831105621223

从特征中选择出一些重要特征(选择就需要根据一些指标来选择)

特征选择不会改变原来的数据

这个过程可以是程序员来做

特征组合

把多个的特征合并成一个特征。

image-20230831112038043

通过加法、乘法等方法将特征值合并

image-20240505090201123

【掌握】模型拟合问题

image-20230831113029823

拟合:用来表示模型对样本点的拟合情况

欠拟合:模型在训练集上表现很差、在测试集表现也很差

原因:模型过于简单,学到的特征过少

过拟合:模型在训练集上表现很好、在测试集表现很差

原因:模型太过于复杂、数据不纯、训练数据太少、样本数据类型过于单一

泛化:模型在新数据集(非训练数据)上的表现好坏的能力(就是一种适应能力

奥卡姆剃刀原则:给定两个具有相同泛化误差的模型,较简单的模型比较复杂的模型更可取(选简单的

【操作】机器学习开发环境

因为已经装了anaconda,所以无需安装。

sklearn官网:https://scikit-learn.org/stable/

中文官网:https://scikit-learn.cn/stable/

  • 什么是沙箱环境?

    • 沙箱环境为应用程序或进程提供了一个独立的执行环境,内部程序的执行不会影响到外部程序的运行。
  • 沙箱环境的作用?

    • 给不同的工程创建互相独立的运行环境,避免不同项目之间的依赖冲突。
  • 安装Python机器学习框架 scikit-learn

    pip install scikit-learn
    

基于Python的 scikit-learn 库:

  1. 简单高效的数据挖掘和数据分析工具
  2. 可供大家使用,可在各种环境中重复使用
  3. 建立在NumPy,SciPy和matplotlib上
  4. 开源,可商业使用-获取BSD许可证

【理解】线性回归算法介绍

举个栗子

假若有了身高和体重数据,来了播仔的身高,你能预测播仔体重吗?

image-20230901101426794

这是一个回归问题,该如何求解呢?

思路:先从已知身高X和体重Y中找规律,再预测

•数学问题:用一条线来拟合身高和体重之间的关系,再对新数据进行预测

image-20260302161926667

k:斜率/权重 coef
b:截距/偏置 bias

什么是线性回归

定义:通过算法模型对【训练集】数据进行【拟合】,得到【线性回归方程】,然后使用这个方程对未知数据进行【预测】

注意事项:

1 为什么叫线性模型?因为求解的w,都是w的零次幂(常数项)所以叫成线性模型

2 在线性回归中,从数据中获取的规律其实就是学习权重系数w

3 某一个权重值w越大,说明这个权重的数据对房子价格影响越大

线性回归种类

  • 一元线性回归

y = kx +b

目标值只与一个因变量有关系

image-20230901102857178

  • 多元线性回归

image-20230901102940614

目标值只与多个因变量有关系

image-20230901103000204

应用场景

依据学习时长、刷题量,预估考试分数
根据气温、季节,预测用电量、用水量
...

【熟悉】基础API使用

预测播仔身高案例

已知数据:

image-20230901104147248

需求:播仔身高是176,请预测体重?

from sklearn.linear_model import LinearRegression   # 线性回归算法

if __name__ == '__main__':
    # 1- 准备数据
    x = [
        [160],
        [166],
        [172],
        [174],
        [180]
    ]
    y = [56.3, 60.6, 65.1, 68.5, 75]

    # 2- 创建算法模型实例对象
    # 参数解释:fit_intercept是否训练得到b偏置
    model = LinearRegression(fit_intercept=True)

    # 3- 模型训练
    model.fit(x,y)

    # 4- 模型预测
    pred_result = model.predict([[176]])
    print("预测结果",pred_result)
    print("权重/斜率",model.coef_)
    print("偏置/截距",model.intercept_)

算法原理

总结:
1- 损失函数可以得到最优的线性方程(w、b) -> 损失函数
2- 为了求损失值最小 -> 梯度下降法 和 正规方程法

问题

通过线性回归API可快速的找到一条红色直线,是怎么求解的呢?

image-20230901104626001

【掌握】损失函数

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

损失函数:衡量每个样本预测值与真实值之间差距的一种函数(误差求和)。当损失函数取最小值时,得到k就是最优解

作用:指定模型优化、评估模型性能

image-20260302172541288

image-20260302175636813

image-20260304091542116

image-20260304092207956

【复习】导数和偏导

数据形式

image-20260304095219369

  • 标量scalar :一个独立存在的数,只有大小没有方向

  • 向量vector :向量指一列顺序排列的元素。默认是列向量

  • 矩阵matrix :二维数组

    image-20230901115223778

    image-20230901115232323

  • 张量Tensor :多维数组,张量是基于向量和矩阵的推广

    image-20230901115246275

导数

image-20260304100520432

常见函数的导数:

image-20260304101332004

导数的四则运算:

image-20260304102712665

偏导

image-20260304110223543

【掌握】梯度下降算法

梯度值=导数值=斜率,这3个是同一个东西

一种求解损失函数最优解的算法

梯度下降算法思想

什么是梯度下降法

• 求解函数极值还有更通用的方法就是梯度下降法。顾名思义:沿着梯度下降的方向求解极小值 • 举个例子:坡度最陡下山法

image-20260614095740496

最终找到最优解 这个方法可用来求损失函数最优解, 比正规方程更通用

梯度下降过程就和下山场景类似
可微分的损失函数,代表着一座山
寻找的函数的最小值,也就是山底

image-20260614103714435

下一点权重 = 当前点权重 - 学习率*损失函数偏导值

梯度下降算法分类

下面的4中计算方式,指的是对上面【梯度下降算法分类章节】中梯度下降公式里面的紫色方框里面的内容进行讨论。说的是在计算偏导的时候,到底使用样本数据中的多少条样本数据来进行计算。

image-20260228174449744

正规方程和梯度下降算法的对比

什么是正规方程法:单纯的通过纯数学的手段和思想,让损失函数取最小值的过程。

正规方程存在如下两个弊端:

  • 矩阵的逆不一定存在
  • 即使矩阵的逆存在,但是计算量非常的庞大

image-20260614110121579

【熟悉】回归问题的评估指标

平均绝对误差

Mean Absolute Error (MAE)

img
  • 上面的公式中:n 为样本数量, y 为实际值, $\hat{y}$ 为预测值

  • MAE 越小模型预测约准确

Sklearn 中MAE的API

from sklearn.metrics import mean_absolute_error
mean_absolute_error(y_test,y_predict)

均方误差

Mean Squared Error (MSE)

img
  • 上面的公式中:n 为样本数量, y 为实际值, $\hat{y}$ 为预测值
  • MSE 越小模型预测约准确

Sklearn 中MSE的API

from sklearn.metrics import mean_squared_error
mean_squared_error(y_test,y_predict)

均方根误差

Root Mean Squared Error (RMSE)

img
  • 上面的公式中:n 为样本数量, y 为实际值, $\hat{y}$ 为预测值

  • RMSE 越小模型预测约准确

【掌握】综合案例

线性回归API

正规方程

sklearn.linear_model.LinearRegression(fit_intercept=True)
  • 参数:fit_intercept,是否计算偏置
  • 属性:LinearRegression.coef_ (回归系数) LinearRegression.intercept_(偏置)

随机梯度下降

sklearn.linear_model.SGDRegressor(loss="squared_loss", fit_intercept=True, learning_rate ='constant', eta0=0.01)
  • 参数:loss(损失函数类型),fit_intercept(是否计算偏置)learning_rate (学习率)
  • 属性:SGDRegressor.coef_ (回归系数)SGDRegressor.intercept_ (偏置)

波士顿房价预测

案例背景介绍

数据介绍

属性

给定的这些特征,是专家们得出的影响房价的结果属性。我们此阶段不需要自己去探究特征是否有用,只需要使用这些特征。到后面量化很多特征需要我们自己去寻找

案例分析

回归当中的数据大小不一致,是否会导致结果影响较大。所以需要做标准化处理。

  • 数据分割与标准化处理
  • 回归预测
  • 线性回归的算法效果评估

代码实现

import pandas as pd
from sklearn.model_selection import train_test_split    # 划分训练集和测试集
from sklearn.preprocessing import StandardScaler        # 特征工程->特征预处理->标准化
from sklearn.linear_model import LinearRegression       # 线性回归算法
from sklearn.linear_model import SGDRegressor           # SGD随机梯度下降算法
from sklearn.metrics import mean_squared_error          # MSE
from sklearn.metrics import root_mean_squared_error     # RMSE
from sklearn.metrics import mean_absolute_error         # MAE


def ml():
    # 1- 准备数据
    df = pd.read_excel("data/boston_house_prices.xlsx")
    # print(df.head())

    # 2- 数据基本处理
    # 2.1- 从DF中获得特征数据
    x = df.iloc[:, :-1]

    # 2.2- 从DF中获得目标值数据
    # iloc[行索引开始下标:行索引结束下标:step步长, 列索引开始下标:列索引结束下标:step步长],注意事项:左闭右开
    y = df.iloc[:, -1]

    # 2.3- 划分训练集和测试集:一般是8:2或者7:3
    """
        参数解释:
            *arrays:特征数据、目标值数据按顺序传递进去。千万不要搞反x和y的顺序
            test_size:测试集数据占比,0.2表示占20%
            random_state:随机数种子。如果设置了该值,那么不管代码运行多少次,数据的划分结果不变
            shuffle:是否要打散数据。推荐设置为True,为了缓解样本数据分布不均衡。
                举例:100条样本,A类数据有80条,B类数据有20条。如果不设置shuffle=True,那么有可能会出现80条训练集中全是A类的数据
    """
    # 返回值结果顺序:先特征再目标值,先训练集再测试集
    x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=614,shuffle=True)
    # print(x_test)

    # 3- 特征工程
    transformer = StandardScaler()
    x_train = transformer.fit_transform(x_train)
    x_test = transformer.transform(x_test)      # 注意:测试集数据只能调用transform

    # 4- 模型训练
    model = LinearRegression()
    model.fit(x_train,y_train)  # 使用训练集数据训练模型

    # 5- 模型评估
    # 5.1- 得到预测结果
    """
        类似上学时候的考试:
            x_test -> 卷子
            pred_y -> 你写的答案
            y_test -> 卷子的标准答案
    """
    pred_y = model.predict(x_test)

    # 5.2- 评估
    print("MSE均方误差:",mean_squared_error(y_test, pred_y))
    print("RMSE均方根误差:",root_mean_squared_error(y_test, pred_y))
    print("MAE平均绝对误差:",mean_absolute_error(y_test, pred_y))

    # 6- 模型上线
    # 无

def sgd_ml():
    # 1- 准备数据
    df = pd.read_excel("data/boston_house_prices.xlsx")

    # 2- 数据基本处理
    # 2.1- 得到特征数据和目标值数据
    x = df.iloc[:, :-1]
    y = df.iloc[:, -1]

    # 2.2- 划分得到训练集和测试集
    """
        参数解释:
            *arrays:特征数据、目标值数据严格按照顺序传递进去
            test_size:测试集的占比
            random_state:随机数种子。如果设置了该值,那么每次运行代码的时候,数据划分结果一样
            shuffle:是否要打散数据。推荐设置为True
    """
    x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=614,shuffle=True)

    # 3- 特征工程
    transformer = StandardScaler()
    x_train = transformer.fit_transform(x_train)    # 训练集一定要调用带fit的方法
    x_test = transformer.transform(x_test)          # 测试集只能调用不带fit的方法

    # 4- 模型训练
    """
        参数解释:
            eta0:梯度下降公式中的α学习率
            learning_rate:设置学习率的更新策略。常见取值如下:
                constant:常数。学习率设置完以后固定不变
                invscaling:学习率会按照后面的公式进行更新 eta = eta0 / pow(t, power_t)
    """
    model = SGDRegressor(learning_rate="constant",eta0=0.01)
    model.fit(x_train,y_train)

    # 5- 模型评估
    # 5.1- 对测试集数据进行预测,得到预测结果
    y_pred = model.predict(x_test)
    # 5.2- 回归问题的评估指标
    print("MSE:",mean_squared_error(y_test, y_pred))
    print("RMSE:",root_mean_squared_error(y_test, y_pred))
    print("MAE:",mean_absolute_error(y_test, y_pred))

    # 6- 模型上线
    # 无

if __name__ == '__main__':
    # 1- 普通的线性回归(也就是正规方程法)
    ml()

    print("-"*30)

    # 2- 随机梯度下降的线性回归
    sgd_ml()

【理解】正则化

欠拟合与过拟合

过拟合:一个假设 在训练数据上能够获得比其他假设更好的拟合, 但是在测试数据集上却不能很好地拟合数据 (体现在准确率下降),此时认为这个假设出现了过拟合的现象。(模型过于复杂)

欠拟合:一个假设 在训练数据上不能获得更好的拟合,并且在测试数据集上也不能很好地拟合数据 ,此时认为这个假设出现了欠拟合的现象。(模型过于简单)

过拟合和欠拟合的区别:

æ¬ æ‹Ÿåˆè¿‡æ‹Ÿåˆå›¾ç¤º

欠拟合在训练集和测试集上的误差都较大

过拟合在训练集上误差较小,而测试集上误差较大

【演示】通过代码认识过拟合和欠拟合

目的:借助线性回归模型,演示不同特征数据情况下的模型欠拟合、恰好拟合、过拟合效果

原因以及解决办法

欠拟合产生原因: 学习到数据的特征过少

解决办法:

1)添加其他特征项,有时出现欠拟合是因为特征项不够导致的,可以添加其他特征项来解决

2)添加多项式特征,模型过于简单时的常用套路,例如将线性模型通过添加二次项或三次项使模型泛化能力更强

过拟合产生原因: 原始特征过多,存在一些嘈杂特征, 模型过于复杂是因为模型尝试去兼顾所有测试样本

解决办法:

1)重新清洗数据,导致过拟合的一个原因有可能是数据不纯,如果出现了过拟合就需要重新清洗数据。

2)增大数据的训练量,还有一个原因就是我们用于训练的数据量太小导致的,训练数据占总数据的比例过小。

4)减少特征维度

3)正则化(L1和L2,一般用L2)

正则化

正则化是什么:在损失函数上加上一些限制减少甚至删除某些特征的影响,避免模型过于复杂。

在解决回归过拟合中,我们选择正则化。但是对于其他机器学习算法如分类算法来说也会出现这样的问题,除了一些算法本身作用之外(决策树、神经网络),我们更多的也是去自己做特征选择,包括之前说的删除、合并一些特征

如何解决?

正则化

在学习的时候,数据提供的特征有些影响模型复杂度或者这个特征的数据点异常较多,所以算法在学习的时候尽量减少这个特征的影响(甚至删除某个特征的影响),这就是正则化

注:调整时候,算法并不知道某个特征影响,而是去调整参数得出优化的结果

L1正则化

α惩罚系数:α越大,惩罚越重,被压缩成0的权重就越多

作用:在训练完成后,它会倾向于将许多不重要的特征的权重压缩为0

使用:当你认为只有少数几个特征是真正重要的,或者需要进行特征选择以减少特征数量时。

Lasso回归: from sklearn.linear_model import Lasso

image-20260614154455057

L2正则化

α惩罚系数:α越大,惩罚越重,所有权重值越趋近于0

作用:它会使权重的值变得非常小(趋近于0但不等于0),不会彻底移除任何一个特征。

使用:当你认为所有特征都对输出都有一定影响(即使影响很小),不希望彻底剔除任何特征时。

推荐:优先使用L2正则化

image-20260614154703048

Ridge回归: from sklearn.linear_model import Ridge

正则化案例

  • 导包
import numpy as np
from sklearn.linear_model import LinearRegression, Lasso, Ridge
from sklearn.metrics import mean_squared_error
import matplotlib.pyplot as plt
  • 无正则项的线性回归拟合
def over_fitting():
    """
    演示过拟合:
        1.构造数据
        2.模型实例化
        3.模型训练
        4.模型预测
        5.模型评价
        6.画图
    """

    # 1.构造数据
    np.random.seed(555)
    x = np.random.uniform(-3, 3, size=100)
    y = 0.5 * x ** 2 + x + 2 + np.random.normal(0, 1, size=100)
    # 2.模型实例化
    model = LinearRegression()
    # 3.模型训练
    X = x.reshape(-1, 1)
    X = np.hstack([X, X ** 2, X ** 3, X ** 4, X ** 5, X ** 6, X * 7, X ** 8, X ** 9, X ** 10])
    model.fit(X, y)
    # 4.模型预测
    y_pred = model.predict(X)
    # 5.模型评价
    mse = mean_squared_error(y, y_pred)
    print(f"模型预测的均方误差:{mse}")
    # 6.画图
    plt.scatter(x, y)
    plt.plot(np.sort(x), y_pred[np.argsort(x)], c='r')
    plt.show()

img

  • 引入L1正则的线性回归拟合-Lasso回归
def lasso_fitting():
    """
    引入正则项的线性回归-Lasso回归:
        1.构造数据
        2.模型实例化
        3.模型训练
        4.模型预测
        5.模型评价
        6.画图
    """

    # 1.构造数据
    np.random.seed(555)
    x = np.random.uniform(-3, 3, size=100) # 生成100个在-3到3之间均匀分布的数,赋值给 x
    y = 0.5 * x ** 2 + x + 2 + np.random.normal(0, 1, size=100) #有噪声,噪声是从标准正态分布(均值为0,标准差为1)中抽取100个随机数
    
    # 2.模型实例化(关键改动)
    model = Lasso(alpha=0.005, normalize=True)
    # 3.模型训练
    X = x.reshape(-1, 1)
    X = np.hstack([X, X ** 2, X ** 3, X ** 4, X ** 5, X ** 6, X * 7, X ** 8, X ** 9, X ** 10]) #扩展成多列特征
    model.fit(X, y)
    print('estimator.coef_', model.coef_)
    # 4.模型预测
    y_pred = model.predict(X)
    # 5.模型评价
    mse = mean_squared_error(y, y_pred)
    print(f"模型预测的均方误差:{mse}")
    # 6.画图
    plt.scatter(x, y)
    plt.plot(np.sort(x), y_pred[np.argsort(x)], c='r')
    plt.show()

img

  • 引入L2正则的线性回归拟合-Ridge回归(岭回归)
def ridge_fitting():
    """
    引入正则项的线性回归-ridge回归(岭回归):
        1.构造数据
        2.模型实例化
        3.模型训练
        4.模型预测
        5.模型评价
        6.画图
    """

    # 1.构造数据
    np.random.seed(555)
    x = np.random.uniform(-3, 3, size=100)
    y = 0.5 * x ** 2 + x + 2 + np.random.normal(0, 1, size=100)
    # 2.模型实例化(关键改动)
    model = Ridge(alpha=0.005, normalize=True)
    # 3.模型训练
    X = x.reshape(-1, 1)
    X = np.hstack([X, X ** 2, X ** 3, X ** 4, X ** 5, X ** 6, X * 7, X ** 8, X ** 9, X ** 10])
    model.fit(X, y)
    print('estimator.coef_', model.coef_)
    # 4.模型预测
    y_pred = model.predict(X)
    # 5.模型评价
    mse = mean_squared_error(y, y_pred)
    print(f"模型预测的均方误差:{mse}")
    # 6.画图
    plt.scatter(x, y)
    plt.plot(np.sor

img

总结对比

对比项Ridge(L2)Lasso(L1)
正则项参数平方和参数绝对值和
特征选择不做选择,保留所有特征自动筛特征,产生稀疏解
权重变化全部缩小,不为 0部分直接置 0
共线性处理效果好、稳定不稳定,随机选特征
适用场景特征都有用、数据噪声小特征冗余多、需要降维 / 选特征

【理解】KNN算法介绍

算法思想

K-近邻算法(K Nearest Neighbor,简称KNN)。

找出与未知样本数据距离最近的K个邻居,来预测未知样本数据的目标值是啥。

思考:如何确定样本的相似性?使用欧氏距离计算

样本相似性:样本都是属于一个任务数据集的。样本距离越近则越相似。

利用K近邻算法预测电影类型

image-20260301153210953

KNN的应用场景

  • 解决问题:分类问题、回归问题

  • 算法思想:若一个样本在特征空间中的 k 个最相似的样本大多数属于某一个类别,则该样本也属于这个类别

1.计算未知样本到训练样本的距离  【计算距离】
2.对训练样本按距离升序排序  【升序排序】
3.选取k个距离最近的训练样本 【选择k个样本】
4.取多数表决/平均值作为预测值 【确定预测值】
    分类问题:【多数表决】确定预测值
    回归问题:【平均值】作为预测值

【熟悉】基础API使用

分类API

sklearn.neighbors.KNeighborsClassifier(n_neighbors=5) 

n_neighbors:int,可选(默认= 5),n_neighbors查询默认使用的邻居数

回归API

sklearn.neighbors.KNeighborsRegressor(n_neighbors=5)

完整代码

from sklearn.neighbors import KNeighborsClassifier  # KNN分类算法
from sklearn.neighbors import KNeighborsRegressor   # KNN回归算法

def demo01():
    # 1- 准备数据
    # 特征
    x = [
        [0],
        [1],
        [2],
        [3]
    ]

    # 目标值
    y = [0, 0, 1, 1]

    # 2- 模型训练
    # 参数解释:n_neighbors也就是k,取距离最近的多少个邻居
    model = KNeighborsClassifier(n_neighbors=1)
    model.fit(x,y)

    # 3- 模型上线
    print("分类预测结果:",model.predict([[4]]))

def demo02():
    # 1- 准备数据
    """
        特征1 特征2 特征3 目标值     欧式距离
        0     0     1   0.1       =(0-3)²+(0-11)²+(1-10)²,再开根号
        1     1     0   0.2       =(1-3)²+(1-11)²+(0-10)²,再开根号
        3     10    10  0.3       =(3-3)²+(10-11)²+(10-10)²,再开根号=1
        4     11    12  0.4       =(4-3)²+(11-11)²+(12-10)²,再开根号=2.236

        未知样本数据
        特征1 特征2 特征3 目标值
        3     11    10  ?
        
        欧式距离升序排序,取出前2个,分别对应的目标值是0.3、0.4
        然后目标值算均值(0.3+0.4)/2=0.35
    """

    # 特征数据
    x = [
        [0, 0, 1],
        [1, 1, 0],
        [3, 10, 10],
        [4, 11, 12]
    ]
    # 目标值
    y = [0.1, 0.2, 0.3, 0.4]

    # 2- 模型训练
    model = KNeighborsRegressor(n_neighbors=2)
    model.fit(x,y)

    # 3- 模型上线
    print("回归预测结果:",model.predict([[3, 11, 10]]))


if __name__ == '__main__':
    # KNN分类算法
    demo01()

    # KNN回归算法
    demo02()

算法原理

【掌握】欧式距离

image-20230831153948263

【掌握】机器学习公共能力

特征预处理

为什么进行特征预处理

特征的单位或者大小相差较大,或者某特征的方差相比其他的特征要大出几个数量级容易影响(支配)目标结果,使得一些模型(算法)无法学习到其它的特征。

image-20230831155159883

归一化

通过对原始数据进行变换把数据映射到【mi,mx】(默认为[0,1])之间

image-20260301174907289

数据归一化的API实现

from sklearn.preprocessing import MinMaxScaler  # 归一化

def demo01():
    # 1- 准备特征数据
    x = [
        [90, 2, 10, 40],
        [60, 4, 15, 45],
        [75, 3, 13, 46]
    ]

    # 2- 创建特征预处理实例对象
    transformer = MinMaxScaler()
    new_x = transformer.fit_transform(x)

    # 下面的代码等价与上面的fit_transform
    # transformer.fit(x)
    # new_x = transformer.transform(x)

    print("归一化以后的结果:\n",new_x)

if __name__ == '__main__':
    # 归一化
    demo01()

feature_range 缩放区间

  • 调用 fit_transform(X) 将特征进行归一化缩放

归一化受到最大值与最小值的影响,这种方法容易受到异常数据的影响, 鲁棒性较差,适合传统精确小数据场景

鲁棒性:面对干扰/异常时的稳定性,也就是抗干扰能力

泛化:面对新数据时的表现,也就是适应能力

标准化

通过对原始数据进行标准化,转换为均值为0标准差为1的标准正态分布的数据

image-20260614174400329

  • mean 为特征的平均值
  • σ 为特征的标准差

数据标准化的API实现

from sklearn.preprocessing import StandardScaler    # 标准化

def demo02():
    # 1- 准备特征数据
    x = [
        [90, 2, 10, 40],
        [60, 4, 15, 45],
        [75, 3, 13, 46]
    ]

    # 2- 创建特征预处理实例对象
    transformer = StandardScaler()
    result = transformer.fit_transform(x)
    print(f"标准化处理后的结果:\n{result}")

    print("标准差:\n",transformer.scale_)
    print("方差:\n",transformer.var_)
    print("均值:\n",transformer.mean_)


if __name__ == '__main__':
    # 标准化
    demo02()

调用 fit_transform(X) 将特征进行归一化缩放

对于标准化来说,如果出现异常点,由于具有一定数据量,少量的异常点对于平均值的影响并不大

最终的结论:

image-20260614180323332

鸢尾花分类案例

机器学习代码的开发完整流程:
   1- 数据探索:打印、画图、describe()、info()、特征和目标值之间的关系
   2- 使用机器学习的技术实现需求
       2.1- 准备数据
           将数据从文件里、数据库中读取出来
       2.2- 数据基本处理
           异常值处理、数据格式化、得到特征数据、得到目标值数据、划分训练集和测试集
       2.3- 特征工程
           使用最多的是特征预处理中标准化
       2.4- 模型训练
           选择合适的算法模型、使用训练集数据训练模型
       2.5- 模型评估
           使用测试集数据对训练好的模型进行评估。保存满足要求的模型。
       2.6- 模型上线
           使用训练好、评估好的模型对未知数据进行预测。

鸢尾花Iris Dataset数据集是机器学习领域经典数据集,鸢尾花数据集包含了150条鸢尾花信息,每50条取自三个鸢尾花中之一:Versicolour、Setosa和Virginica

每个花的特征用如下属性描述:

代码实现:

"""
    机器学习代码的开发完整流程:
        1- 数据探索:打印、画图、describe()、info()、特征和目标值之间的关系
        2- 使用机器学习的技术实现需求
            2.1- 准备数据
                将数据从文件里、数据库中读取出来
            2.2- 数据基本处理
                异常值处理、数据格式化、得到特征数据、得到目标值数据、划分训练集和测试集
            2.3- 特征工程
                使用最多的是特征预处理中标准化
            2.4- 模型训练
                选择合适的算法模型、使用训练集数据训练模型
            2.5- 模型评估
                使用测试集数据对训练好的模型进行评估。保存满足要求的模型。
            2.6- 模型上线
                使用训练好、评估好的模型对未知数据进行预测。
"""
import seaborn as sns   # Seaborn:一个高效的画图开源库。底层是基于Matplotlib
import matplotlib.pyplot as plt
import pandas as pd

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split    # 划分训练集和测试集
from sklearn.preprocessing import StandardScaler        # 特征工程->特征预处理->标准化
from sklearn.neighbors import KNeighborsClassifier      # KNN分类算法
from sklearn.metrics import accuracy_score              # 准确率。  准确率 = 预测正确的条数 / 测试集样本条数
import joblib   # 用来存储和加载训练好的模型

def eda():
    # 1- 加载数据
    iris_data = load_iris()
    print(iris_data)

    # 2- 获取数据内容
    feature_data = iris_data["data"]
    feature_names = iris_data["feature_names"]
    print("特征值:",feature_data[:5])
    print("特征字段名称:",feature_names)

    target = iris_data["target"]
    target_names = iris_data["target_names"]
    print("目标值:",target[:5])
    print("花的品种:",target_names)

    data_info = iris_data["DESCR"]
    print("数据信息:",data_info)

    # 3- 构建得到DF对象
    df = pd.DataFrame(feature_data,columns=feature_names)
    df["target"] = target
    print(df.head())

    # 4- 【了解】通过图形化的形式研究特征和目标值之间的关系
    """
        参数解释:
            data:要对什么数据进行可视化展示
            x:哪个字段要作为横轴使用。注意:不是表示特征
            y:哪个字段要作为纵轴使用。注意:不是表示目标值
            fit_reg:是否要展示线性回归拟合线
            scatter:是否要展示散点
            hue:是否要对散点的颜色进行渲染。一般给目标值
    """
    sns.lmplot(data=df, x="petal length (cm)", y="petal width (cm)",hue="target",fit_reg=False,scatter=True)
    sns.lmplot(data=df, x="sepal length (cm)", y="sepal width (cm)",hue="target",fit_reg=False,scatter=True)
    plt.show()

def ml():
    # 1- 准备数据
    iris_data = load_iris()

    # 2- 数据基本处理
    # 2.1- 得到特征数据
    x = pd.DataFrame(iris_data["data"])

    # 2.2- 得到目标值数据
    y = pd.DataFrame(iris_data["target"])

    # 2.3- 划分得到训练集和测试集
    x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=619,shuffle=True)

    # 3- 特征工程
    """
        为什么 训练集数据 只能调用带fit的方法,而 测试集、未知数据只能调用不带fit的方法?
        原因:为了提升模型的泛化能力。也就是对新数据的适应能力。
    """
    transformer = StandardScaler()
    x_train = transformer.fit_transform(x_train)
    x_test = transformer.transform(x_test)

    # 4- 模型训练
    model = KNeighborsClassifier(n_neighbors=5)
    model.fit(x_train,y_train)

    # 5- 模型评估
    # 5.1- 对测试集进行预测:相当于考试的时候自己做题
    y_pred = model.predict(x_test)
    # 5.2- 分类问题的评估指标
    print("准确率:",accuracy_score(y_test, y_pred))
    # 5.3- 保存训练好的模型
    # 参数解释:要保存的模型对象;要保存到的文件路径,文件的后缀名一般是pkl,bin、pth等
    joblib.dump(model,"data/iris_model.pkl")
    # 加载训练好的模型
    # model = joblib.load("data/iris_model.pkl")

    # 6- 未知数据预测
    # 6.1- 准备未知数据
    unknown_data = [[5.1, 3.5, 1.4, 0.2]]
    # 6.2- 未知数据标准化
    unknown_data = transformer.transform(unknown_data)
    # 6.3- 预测
    unknown_data_y = model.predict(unknown_data)
    print("未知数据预测结果:",unknown_data_y)


if __name__ == '__main__':
    # 1- 数据探索(explorer data analysis):对数据的内容、数据的分布等情况进行了解
    # eda()

    # 2- 机器学习
    ml()

超参数选择的方法

总结:
交叉验证:只负责对训练集进行划分,不负责模型训练
网格搜索:只负责从指定范围中找最优的超参组合

交叉验证

把【训练集】切分成n份(折),轮流拿一份当验证集、其余训练,多次取平均得分。

1- 交叉验证的目的:为了得到更加准确的模型
2- 交叉验证是对样本数据中的【训练集】进行划分为n份(称之为多少折)
3- 注意:训练多少次与你将数据中的【训练集】进行划分为多少份有关系。与k值无关

image-20260616112301197

网格搜索

自动遍历预设超参数组合,选出效果最好的参数

1744898295569

交叉验证网格搜索的API:

image-20230831163636694

交叉验证网格搜索在鸢尾花分类中的应用:

"""
    机器学习代码的开发完整流程:
        1- 数据探索:打印、画图、describe()、info()、特征和目标值之间的关系
        2- 使用机器学习的技术实现需求
            2.1- 准备数据
                将数据从文件里、数据库中读取出来
            2.2- 数据基本处理
                异常值处理、数据格式化、得到特征数据、得到目标值数据、划分训练集和测试集
            2.3- 特征工程
                使用最多的是特征预处理中标准化
            2.4- 模型训练
                2.4.1- 选择合适的算法模型
                2.4.2- 【可选】交叉验证+网格搜索,获得最优的超参数组合
                2.4.3- 使用训练集数据训练模型
                2.4.4- 【可选】输出交叉验证+网格搜索 的 最优超参数组合
            2.5- 模型评估
                使用测试集数据对训练好的模型进行评估。保存满足要求的模型。
            2.6- 模型上线
                使用训练好、评估好的模型对未知数据进行预测。
"""
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split    # 划分训练集和测试集
from sklearn.preprocessing import StandardScaler        # 特征工程->特征预处理->标准化
from sklearn.neighbors import KNeighborsClassifier      # KNN分类算法
from sklearn.metrics import accuracy_score              # 准确率。  准确率 = 预测正确的条数 / 测试集样本条数
from sklearn.model_selection import GridSearchCV        # 网格搜索+交叉验证(cross validation)
import joblib   # 用来存储和加载训练好的模型

def ml():
    # 1- 准备数据
    iris_data = load_iris()

    # 2- 数据基本处理
    # 2.1- 得到特征数据
    x = pd.DataFrame(iris_data["data"])

    # 2.2- 得到目标值数据
    y = pd.DataFrame(iris_data["target"])

    # 2.3- 划分得到训练集和测试集
    x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=619,shuffle=True)

    # 3- 特征工程
    transformer = StandardScaler()
    x_train = transformer.fit_transform(x_train)
    x_test = transformer.transform(x_test)

    # 4- 模型训练
    # PyCharm同时编辑多行:shift+alt+鼠标左键
    # 4.1- 选择合适的算法模型
    model = KNeighborsClassifier()

    # 4.2- 【可选】交叉验证+网格搜索,获得最优的超参数组合
    """
        参数解释:
            estimator:要用来进行交叉验证和网格搜索的初始化模型
            cv:将样本集中的训练集划分为几份。注意:实际工作中该参数的值一般在2-5之间
            param_grid:超参数的排列组合范围。一般传递的是字典类型
                字典的key:超参数的名称
                字典的value:超参数的取值范围
    """
    param_dict = {
        "n_neighbors":[i for i in range(2,6)]
    }
    model = GridSearchCV(estimator=model, cv=2, param_grid=param_dict)

    # 4.3- 使用训练集数据训练模型
    model.fit(x_train, y_train)

    # 4.4- 【可选】输出交叉验证+网格搜索 的 最优超参数组合
    print("最优超参数组合:",model.best_params_)
    print("最优超参数组合对应的分数:",model.best_score_)
    print("交叉验证+网格搜索的内部细节:",model.cv_results_)

    # 5- 模型评估
    # 5.1- 对测试集进行预测:相当于考试的时候自己做题
    y_pred = model.predict(x_test)
    # 5.2- 分类问题的评估指标
    print("准确率:",accuracy_score(y_test, y_pred))
    # 5.3- 保存训练好的模型
    # 参数解释:要保存的模型对象;要保存到的文件路径,文件的后缀名一般是pkl,bin、pth等
    joblib.dump(model,"data/iris_model.pkl")
    # 加载训练好的模型
    # model = joblib.load("data/iris_model.pkl")

    # 6- 未知数据预测
    # 6.1- 准备未知数据
    unknown_data = [[5.1, 3.5, 1.4, 0.2]]
    # 6.2- 未知数据标准化
    unknown_data = transformer.transform(unknown_data)
    # 6.3- 预测
    unknown_data_y = model.predict(unknown_data)
    print("未知数据预测结果:",unknown_data_y)

if __name__ == '__main__':
    # 机器学习
    ml()

【掌握】分类算法评估指标

混淆矩阵

一个四格统计表,区分正负样本预测对错

image-20260617203109392

混淆矩阵作用在测试集样本集中:

  1. 真实值是 正例 的样本中,被分类为 正例 的样本数量有多少,这部分样本叫做真正例(TP,True Positive)
  2. 真实值是 正例 的样本中,被分类为 假例 的样本数量有多少,这部分样本叫做伪反例(FN,False Negative)
  3. 真实值是 假例 的样本中,被分类为 正例 的样本数量有多少,这部分样本叫做伪正例(FP,False Positive)
  4. 真实值是 假例 的样本中,被分类为 假例 的样本数量有多少,这部分样本叫做真反例(TN,True Negative)

Precision(精确率)

精确率也叫做查准率,指的是对正例样本的预测准确率。比如:我们把恶性肿瘤当做正例样本,则我们就需要知道模型对恶性肿瘤的预测准确率。

预测为正的样本里,真正为正的比例,反映预测不瞎报(竖着看混淆矩阵)

Recall(召回率)

召回率也叫做查全率,指的是预测为真正例样本占所有真实正例样本的比重。例如:我们把恶性肿瘤当做正例样本,则我们想知道模型是否能把所有的恶性肿瘤患者都预测出来。

所有真实正样本中,被成功检出的比例,反映不漏检。(横着看混淆矩阵)

F1-score

如果我们对模型的精度、召回率都有要求,希望知道模型在这两个评估方向的综合预测能力如何?则可以使用 F1-score 指标。

精确率与召回率综合,越接近 1 模型效果越好

代码

import pandas as pd
from sklearn.metrics import confusion_matrix    # 混淆矩阵
from sklearn.metrics import precision_score     # 精确率 = TP / (TP+FP)
from sklearn.metrics import recall_score        # 召回率 = TP / (TP+FN)
from sklearn.metrics import f1_score            # F1值  = 2*精确率*召回率 / (精确率+召回率)

if __name__ == '__main__':
    # 1- 准备数据
    # 真实样本数据。10条,6个恶性,4个良性。假设恶性为正例
    y_true = ["恶性","恶性","恶性","恶性","恶性","恶性","良性","良性","良性","良性"]
    # A医生预测结果:10条,预测对了3个恶性,4个良性;预测错了3条,预测为了良性
    A_pred = ["恶性","恶性","恶性","良性","良性","良性","良性","良性","良性","良性"]
    # B医生预测结果:10条,预测对了6个恶性,1个良性;预测错了3条,预测为了恶性
    B_pred = ["恶性","恶性","恶性","恶性","恶性","恶性","恶性","恶性","恶性","良性"]

    # 2- 构造对应的混淆矩阵
    """
        注意事项:混淆矩阵、精确率、召回率、F1值,既能够使用在二分类问题,也能够使用在多分类问题
        参数解释:
            y_true:真实值
            y_pred:预测值
            labels:样本数据中各个目标值的取值列表
    """
    A_cm = confusion_matrix(y_true,A_pred,labels=["恶性","良性"])
    B_cm = confusion_matrix(y_true,B_pred,labels=["恶性","良性"])

    # 3- 将混淆矩阵转成DataFrame对象
    A_df = pd.DataFrame(A_cm,index=["正例(恶性)","反例(良性)"],columns=["正例(恶性)","反例(良性)"])
    B_df = pd.DataFrame(B_cm,index=["正例(恶性)","反例(良性)"],columns=["正例(恶性)","反例(良性)"])

    print(A_df)
    print("-"*30)
    print(B_df)

    # 4- 分类问题的评估指标【掌握】
    """
        参数解释:
            y_true:真实值
            y_pred:预测值
            pos_label:正例样本对应的目标值(标签值)
    """
    print("A医生 精确率:",precision_score(y_true, A_pred, pos_label="恶性"))
    print("A医生 召回率:",recall_score(y_true, A_pred, pos_label="恶性"))
    print("A医生 F1值:",f1_score(y_true, A_pred, pos_label="恶性"))
    print("-" * 30)
    print("B医生 精确率:",precision_score(y_true, B_pred, pos_label="恶性"))
    print("B医生 召回率:",recall_score(y_true, B_pred, pos_label="恶性"))
    print("B医生 F1值:",f1_score(y_true, B_pred, pos_label="恶性"))

【理解】决策树算法简介

基于树结构进行决策的算法模型,能够解决分类和回归问题。中间节点是特征,叶子节点是分类或预测结果。

简介: 将生活中对事情的思考过程进行模拟,因此产生了决策树
决策树不同算法的核心区别: 判断将什么样的特征优先作为划分依据

应用场景:

分类问题:比如邮件分类,判断一封邮件是垃圾邮件还是正常邮件。可以根据邮件的发件人、主题、关键词等特征构建决策树,通过一系列判断得出邮件类别。
回归问题:预测数值,像预测房价。可以用房子的面积、房间数量、房龄等特征构建决策树,最终叶子节点给出房价的预测值。

决策树例子

决策树算法是一种监督学习算法,英文是Decision tree。

决策树思想的来源非常朴素,试想每个人的大脑都有类似于if-else这样的逻辑判断,这其中的if表示的是条件,if之后的else就是一种选择或决策。程序设计中的条件分支结构就是if-else结构,最早的决策树就是利用这类结构分割数据的一种分类学习方法。

比如:你母亲要给你介绍男朋友,是这么来对话的:

女儿:多大年纪了?

母亲:26。

女儿:长的帅不帅?

母亲:挺帅的。

女儿:收入高不?

母亲:不算很高,中等情况。

女儿:是公务员不?

母亲:是,在税务局上班呢。

女儿:那好,我去见见。

于是你在脑袋里面就有了下面这张图:

作为女孩的你在决策过程就是典型的分类树决策。相当于通过年龄、长相、收入和是否公务员对将男人分为两个类别:见和不见。

决策树简介

决策树是什么?

决策树是一种树形结构,树中每个内部节点表示一个特征上的判断,每个分支代表一个判断结果的输出,每个叶子节点代表一种分类结果

决策树的建立过程

1.特征选择:选取有较强分类能力的特征。

2.决策树生成:根据选择的特征生成决策树。

3.决策树也易过拟合,采用剪枝的方法缓解过拟合。

特征值的种类越多,熵值越大,也就是信息越丰富

特征值的种类越少,熵值越小,也就是信息越单一

【理解】CART决策树

Cart树简介

Cart模型是一种决策树模型,它即可以用于分类,也可以用于回归

分类和回归树模型采用不同的最优化策略。Cart回归树使用平方误差最小化策略,Cart分类生成树采用的基尼指数最小化策略。

基尼值和基尼指数

image-20260307152235979

CART决策树倾向选择基尼指数值小的特征作为划分依据。

基尼值(Gini Value)

它衡量一个集合里数据“乱不乱”。
如果一组数据全是同一类(比如全是“打球”),非常纯,基尼值 = 0。
如果一组数据五五开(一半打球,一半不打),最乱,基尼值接近 0.5。

基尼值 = 1 - (类别1比例² + 类别2比例² + …)

例子:一袋水果,10个苹果、0个梨 → 基尼值 = 1 - (1² + 0²) = 0(非常纯)。
如果5个苹果、5个梨 → 基尼值 = 1 - (0.5² + 0.5²) = 0.5(非常乱)。

基尼值越小,数据越“纯”。

基尼指数(Gini Index)

这是在做决策时,用来选“用哪个条件来分裂”的指标。比如你要选“按天气分”还是“按湿度分”,怎么比?

基尼指数 = 把各个子集的基尼值按样本大小加权求和。

通俗理解:

用某个条件分裂后,算一个总体的“混乱程度”;
哪个条件的基尼指数最小,说明分裂后整体最纯,就选它。

基尼指数越小,这个分裂条件越好。

CART决策树就是用基尼指数选分裂条件的。

每次分裂时,它会:

尝试所有可能的条件(比如“湿度 > 80%?”)。

计算每个条件分裂后的基尼指数。

挑出基尼指数最小的那个条件来分裂。

这就是CART用“基尼”做决策的核心逻辑。

总结
基尼值 = 看一个数据集合有多纯越小越纯)。

基尼指数 = 看哪个分裂条件更好(越小越好)。

CART就是用基尼指数最小来选每一步该怎么分。

【了解】分类树总结

名称提出时间分支方式特点
ID31975信息增益1.ID3只能对离散属性的数据集构成决策树 2.倾向于选择取值较多的属性
C4.51993信息增益率1.缓解了ID3分支过程中总喜欢偏向选择值较多的属性 2.可处理连续数值型属性,也增加了对缺失值的处理方法 3.只适合于能够驻留于内存的数据集,大数据集无能为力
CART1984基尼指数1.可以进行分类和回归,可处理离散属性,也可以处理连续属性 2.采用基尼指数,计算量减小 3.一定是二叉树

【掌握】泰坦尼克号生存案例

案例背景

泰坦尼克号沉没是历史上最著名的沉船事件。1912年4月15日,在她的处女航中,泰坦尼克号在与冰山相撞后沉没,在2224名乘客和船员中造成1502人死亡。这场耸人听闻的悲剧震惊了国际社会,并为船舶制定了更好的安全规定。 造成海难失事的原因之一是乘客和船员没有足够的救生艇。尽管幸存下来有一些运气因素,但有些人比其他人更容易生存,例如妇女,儿童和社会地位较高的人群。 在这个案例中,我们要求您完成对哪些人可能存活的分析。

数据集中的特征包括票的类别,是否存活,乘坐班次,姓名,年龄,上船港口,房间,性别等。

image-20230905161031728

API介绍

sklearn.tree.DecisionTreeClassifier(criterion=’gini’,max_depth=None,random_state=None)
  • criterion
    • 特征选择标准
    • “gini”或者”entropy”,前者代表基尼系数,后者代表信息增益。一默认”gini”,即CART算法。
  • min_samples_split
    • 内部节点(中间节点)再划分所需最小样本数
    • 这个值限制了子树继续划分的条件,如果某节点的样本数少于min_samples_split,则不会继续再尝试选择最优特征来进行划分。 默认是2.如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。我之前的一个项目例子,有大概10万样本,建立决策树时,我选择了min_samples_split=10。可以作为参考。
  • min_samples_leaf
    • 叶子节点最少样本数
    • 这个值限制了叶子节点最少的样本数,如果某叶子节点数目小于样本数,则会和兄弟节点一起被剪枝。 默认是1,可以输入最少的样本数的整数,或者最少样本数占样本总数的百分比。如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。之前的10万样本项目使用min_samples_leaf的值为5,仅供参考。
  • max_depth
    • 决策树最大深度
    • 决策树的最大深度,默认可以不输入,如果不输入的话,决策树在建立子树的时候不会限制子树的深度。一般来说,数据少或者特征少的时候可以不管这个值。如果模型样本量多,特征也多的情况下,推荐限制这个最大深度,具体的取值取决于数据的分布。常用的可以取值10-100之间
  • random_state
    • 随机数种子

案例实现

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.tree import DecisionTreeClassifier # 决策树_分类算法
from sklearn.metrics import precision_score,recall_score,f1_score
import matplotlib.pyplot as plt
from sklearn.tree import plot_tree  # 专门用来绘制决策树

if __name__ == '__main__':
    # 1- 准备数据
    df = pd.read_csv("train.csv",encoding="UTF-8")
    # print(df)

    # 2- 数据清洗
    # 2.1- 对年龄的空值使用中位数进行填充
    # print("数据清洗前的整体信息:",df.info())
    new_df = df.fillna(df["Age"].median())
    # print("数据清洗前的整体信息:",new_df.info())

    # 2.2- 特征选择:选择有价值的特征。删除无意义的特征
    drop_df = new_df.drop(columns=["PassengerId", "Name", "Ticket", "Cabin", "Embarked"])

    # 2.3- one-hot热编码处理:将非数字的特征值转成数字的
    one_hot_df = pd.get_dummies(drop_df)
    # print(one_hot_df.info())
    # print(one_hot_df.head())

    # 3- 得到特征数据和目标值数据
    x = one_hot_df[["Pclass", "Sex_female", "Age"]]
    y = one_hot_df.iloc[:, 0]

    # 4- 划分训练集和测试集
    x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=307,shuffle=True,stratify=y)

    # 5- 特征工程
    transformer = StandardScaler()
    x_train = transformer.fit_transform(x_train)
    x_test = transformer.transform(x_test)

    # 6- 模型训练
    """
        参数解释:
            criterion:决策树内部具体使用什么算法。取值如下:
                gini:默认值。默认使用CART分类树
                entropy:对应ID3/C4.5。程序内部会自动根据你数据的特点进行自动选择
                
            下面3个参数,是决策树中用来缓解模型过拟合的核心参数,也就是避免决策树生成的过于庞大
            max_depth:生成的决策树的最大深度。
            min_samples_split:子节点中最小样本条数
            min_samples_leaf:叶节点(不会再往下面进行划分,也称之为末端节点)中最小样本条数
    """
    model = DecisionTreeClassifier(criterion="gini",max_depth=8,min_samples_split=3,min_samples_leaf=1)
    model.fit(x_train,y_train)

    # 7- 模型评估
    # 7.1- 预测
    y_pred = model.predict(x_test)
    # 7.2- 分类的评估指标
    print("精确率:",precision_score(y_test, y_pred))
    print("召回率:",recall_score(y_test, y_pred))
    print("F1值:",f1_score(y_test, y_pred))

    # 8- 【了解】展示决策树图形
    # 8.1- 创建画布
    plt.figure(figsize=(20,20), dpi=200)
    # 8.2- 绘制决策树
    """
        参数解释:
            decision_tree:决策树模型
            max_depth:展示的最大深度
            feature_names:展示哪些特征。顺序必须与x中的字段名称顺序完全一致,否则会报错,核心原因是sklearn官方bug
            class_names:展示的目标值名称
            filled:将以上信息在决策树中进行展示
    """
    plot_tree(
        decision_tree=model,
        max_depth=5,
        feature_names=["Pclass", "Sex_female", "Age"],
        class_names=["no_Survived","yes_Survived"],
        filled=True
    )
    plt.show()

【理解】回归决策树

回归决策树构建原理

CART 回归树和 CART 分类树的不同之处在于:

  1. CART 分类树预测输出的是一个离散值CART 回归树预测输出的是一个连续值
  2. CART 分类树使用基尼指数作为划分、构建树的依据,CART 回归树使用平方损失。
  3. 分类树使用叶子节点里出现更多次数的类别作为预测类别(投票表决),回归树则采用叶子节点里均值作为预测输出

回归决策树实践

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.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error,mean_absolute_error,root_mean_squared_error

if __name__ == '__main__':
    # 1- 准备数据 -> 波士顿房价预测.
    data_url = "http://lib.stat.cmu.edu/datasets/boston"
    """
        参数解释:
            filepath_or_buffer:在线文件的网站地址
            sep:字段值之间的分隔符。目前这里给的是正则表达式,\s表示匹配空白字符(制表符、空格、回车)
            skiprows:跳过前面的多少行
            header:文件中是否字段名称
    """
    raw_df = pd.read_csv(data_url, sep="\\s+", skiprows=22, header=None)
    # hstack()函数: 水平拼接数组
    x = np.hstack([raw_df.values[::2, :], raw_df.values[1::2, :2]])
    y = raw_df.values[1::2, 2]

    # 2- 数据基本处理
    x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=617,shuffle=True)

    # 3- 特征工程
    transformer = StandardScaler()
    x_train = transformer.fit_transform(x_train)
    x_test = transformer.transform(x_test)

    # 4- 模型训练【掌握】
    model = DecisionTreeRegressor(max_depth=20,min_samples_split=2,min_samples_leaf=1)
    # model = LinearRegression()
    model.fit(x_train,y_train)

    # 5- 模型评估
    y_pred = model.predict(x_test)
    print(mean_squared_error(y_test, y_pred))
    print(root_mean_squared_error(y_test, y_pred))
    print(mean_absolute_error(y_test, y_pred))

【熟悉】决策树剪枝

总结:一般常用预剪枝,如果效果不好也就是准确度不高,那么可以考虑后剪枝。

什么是剪枝?

剪枝 (pruning)是决策树学习算法对付 过拟合 的主要手段。

在决策树学习中,为了尽可能正确分类训练样本,结点划分过程将不断重复,有时会造成决策树分支过多,这时就可能因训练样本学得”太好”了,以致于把训练集自身的一些特点当作所有数据都具有的一般性质而导致过拟合。因此,可通过主动去掉一些分支来降低过拟合的风险。

剪枝是指将一颗子树的子节点全部删掉,利用叶子节点替换子树(实质上是后剪枝技术),也可以(假定当前对以root为根的子树进行剪枝)只保留根节点本身而删除所有的叶子,以下图为例:

img

常见减枝方法汇总

决策树剪枝的基本策略有”预剪枝” (pre-pruning)和”后剪枝”(post- pruning) 。

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

例子

在构建树时, 为了能够实现剪枝, 可预留一部分数据用作 “验证集” 以进行性能评估。

训练集如下:

验证集如下:

预剪枝
  1. 假设: 当前树只有一个结点, 即编号为1的结点. 此时, 所有的样本预测类别为: 其类别标记为训练样例数最多的类别,假设我们将这个叶结点标记为 “好瓜”。此时, 在验证集上所有的样本都会被预测为 “好瓜”, 此时的准确率为: 3/7

  2. 如果进行此次分裂, 则树的深度为 2, 有三个分支. 在用属性”脐部”划分之后,上图中的结点2、3、4分别包含编号为 {1,2,3, 14}、 {6,7, 15, 17}、 {10, 16} 的训练样例,因此这 3 个结点分别被标记为叶结点”好瓜”、 “好瓜”、 “坏瓜”。此时, 在验证集上 4、5、8、11、12 样本预测正确,准确率为: 5/7。很显然, 通过此次分裂准确率有所提升, 值得分裂.

  3. 接下来,对结点2进行划分,基于信息增益准则将挑选出划分属性”色泽”。然而,在使用”色泽”划分后,编号为 {5} 的验证集样本分类结果会由正确转为错误,使得验证集精度下降为 57.1%。于是,预剪枝策略将禁止结点2被划分。

  4. 对结点3,最优划分属性为”根蒂”,划分后验证集精度仍为 5/7. 这个 划分不能提升验证集精度,于是,预剪枝策略禁止结点3被划分。

  5. 对结点4,其所含训练样例己属于同一类,不再进行划分.

于是,基于预剪枝策略从上表数据所生成的决策树如上图所示,其验证集精度为 71.4%. 这是一棵仅有一层划分的决策树。

后剪枝

后剪枝先从训练集生成一棵完整决策树,继续使用上面的案例,从前面计算,我们知前面构造的决策树的验证集精度为42.9%。

image-20230905171420720

  1. 首先考察结点6,若将其领衔的分支剪除则相当于把6替换为叶结点。替换后的叶结点包含编号为 {7, 15} 的训练样本,于是该叶结点的类别标记为”好瓜”, 此时决策树的验证集精度提高至 57.1%。
  1. 然后考察结点5,若将其领衔的子树替换为叶结点,则替换后的叶结点包含编号为 {6,7,15}的训练样例,叶结点类别标记为”好瓜’;此时决策树验证集精度仍为 57.1%. 于是,可以不进行剪枝.
  2. 对结点2,若将其领衔的子树替换为叶结点,则替换后的叶结点包含编号 为 {1, 2, 3, 14} 的训练样例,叶结点标记为”好瓜”此时决策树的验证集精度提高至 71.4%. 于是,后剪枝策略决定剪枝.
  3. 对结点3和1,若将其领衔的子树替换为叶结点,则所得决策树的验证集 精度分别为 71.4% 与 42.9%,均未得到提高,于是它们被保留。
  4. 最终, 基于后剪枝策略生成的决策树如上图所示, 其验证集精度为 71.4%。

剪枝方法对比

image-20260617115012180

剪枝相关的代码:
预剪枝:max、min这种开头的基本都是预剪枝代码
    max_depth:生成的决策树的最大深度。
    min_samples_split:子节点中最小样本条数
    min_samples_leaf:叶节点(不会再往下面进行划分,也称之为末端节点)中最小样本条数

后剪枝:
    ccp_alpha:成本复杂度剪枝(Cost Complexity Pruning)的参数。实际工作中一般设置为0-0.1之间,然后进行交叉验证+网格搜索

总结:工作中一般使用预剪枝的方式会多一些

决策树总结

  • 决策树 = 一系列“如果…就…”的判断流程图。
  • CART = 每次只分两叉、既能分类又能预测数值的决策树。
  • 预剪枝 = 边建树边停(早停),省时但可能错失好分支。
  • 后剪枝 = 建完大树再修剪(后砍),效果更好但费时。

【理解】集成学习算法介绍

集成学习是什么

集成学习是机器学习中的一种思想,它通过多个模型的组合形成一个精度更高的模型,参与组合的模型成为弱学习器(基学习器)。训练时,使用训练集依次训练出这些弱学习器,对未知的样本进行预测时,使用这些弱学习器联合进行预测。

传统机器学习算法 (例如:决策树,逻辑回归等) 的目标都是寻找一个最优分类器尽可能的将训练数据分开。集成学习 (Ensemble Learning) 算法的基本思想就是将多个分类器组合,从而实现一个预测效果更好的集成分类器。集成算法可以说从一方面验证了中国的一句老话:三个臭皮匠,顶过诸葛亮

img

集成学习通过建立几个模型来解决单一预测问题。它的工作原理是 生成多个分类器/模型,各自独立地学习和作出预测。这些预测最后结合成组合预测,因此优于任何一个单分类的做出预测。

集成学习分类

集成学习算法一般分为:bagging和boosting。

img

bagging集成

Baggging 框架通过有放回的抽样产生不同的训练集,从而训练具有差异性的弱学习器,然后通过平权投票、多数表决的方式决定预测结果。

image-20260617144527179

boosting集成

Boosting 体现了提升思想,每一个训练器重点关注前一个训练器不足的地方进行训练,通过加权投票的方式,得出预测结果。

image-20260617145338105

Boosting是一组可将弱学习器升为强学习器算法。这类算法的工作机制类似:

1.先从初始训练集训练出一个基学习器

2.在根据基学习器的表现对训练样本分布进行调整,使得先前基学习器做错的训练样本在后续得到最大的关注。

3.然后基于调整后的样本分布来训练下一个基学习器;

4.如此重复进行,直至基学习器数目达到实现指定的值T为止。

5.再将这T个基学习器进行加权结合得到集成学习器。

简而言之:每新加入一个弱学习器,整体能力就会得到提升

Bagging 与 Boosting的区别

区别一:数据方面
- Bagging:有放回采样
- Boosting:全部数据集, 重点关注前一个弱学习器不足

区别二:投票方面
- Bagging:平权投票
- Boosting:加权投票

区别三:学习顺序
- Bagging的学习是并行的,每个学习器没有依赖关系
- Boosting学习是串行,学习有先后顺序

随机森林

【理解】算法介绍

随机森林是基于 Bagging 思想实现的一种集成学习算法,它采用决策树模型作为每一个基学习器。其构造过程:

  1. 训练:
    1. 有放回的产生训练样本
    2. 随机挑选 n 个特征(n 小于总特征数量)
  2. 预测:平权投票,多数表决输出预测结果

image-20230905235742221

随机森林的步骤

image-20260617150506082

如上图:

首先,对样本数据进行有放回的抽样,得到多个样本集。具体来讲就是每次从原来的N个训练样本中有放回地随机抽取m个样本(包括可能重复样本)。

然后,从候选的特征中随机抽取k个特征,作为当前节点下决策的备选特征,从这些特征中选择最好地划分训练样本的特征。用每个样本集作为训练样本构造决策树。单个决策树在产生样本集和确定特征后,使用CART算法计算,不剪枝。

最后,得到所需数目的决策树后,随机森林方法对这些树的输出进行投票,以得票最多的类作为随机森林的决策。

说明:

(1)随机森林的方法即对训练样本进行了采样,又对特征进行了采样,充分保证了所构建的每个树之间的独立性,使得投票结果更准确。

(2)随机森林的随机性体现在每棵树的训练样本是随机的,树中每个节点的分裂属性也是随机选择的。有了这2个随机因素,即使每棵决策树没有进行剪枝,随机森林也不会产生过拟合的现象。

随机森林中有两个可控制参数:

  • 森林中树的数量(一般选取值较大)

  • 抽取的属性值m的大小

思考

  1. 为什么要随机抽样训练集?

  

如果不进行随机抽样,每棵树的训练集都一样,那么最终训练出的树分类结果也是完全一样。

  1. 为什么要有放回地抽样?

如果不是有放回的抽样,那么每棵树的训练样本都是不同的,都是没有交集的,这样每棵树都是“有偏的”,都是绝对“片面的”,也就是说每棵树训练出来都是有很大的差异的;而随机森林最后分类取决于多棵树(弱分类器)的投票表决。

【熟悉】基础API使用

sklearn.ensemble.RandomForestClassifier()

n_estimators:决策树数量,(default = 10)

Criterion:entropy、或者 gini, (default = gini)

max_depth:指定树的最大深度,(default = None 表示树会尽可能的生长)

max_features=”auto”, 决策树构建时使用的最大特征数量

  • If “auto”, then max_features=sqrt(n_features).
  • If “sqrt”, then max_features=sqrt(n_features)(same as “auto”).
  • If “log2”, then max_features=log2(n_features).
  • If None, then max_features=n_features.

bootstrap:是否采用有放回抽样,如果为 False 将会使用全部训练样本,(default = True)

min_samples_split: 结点分裂所需最小样本数,(default = 2)

  • 如果节点样本数少于min_samples_split,则不会再进行划分.
  • 如果样本量不大,不需要设置这个值.
  • 如果样本量数量级非常大,则推荐增大这个值.

min_samples_leaf: 叶子节点的最小样本数,(default = 1)

  • 如果某叶子节点数目小于样本数,则会和兄弟节点一起被剪枝.
  • 较小的叶子结点样本数量使模型更容易捕捉训练数据中的噪声.

min_impurity_split: 节点划分最小不纯度

  • 如果某节点的不纯度(基尼系数,均方差)小于这个阈值,则该节点不再生成子节点,并变为叶子节点.
  • 一般不推荐改动默认值1e-7。

【掌握】 泰坦尼克号生存预测案例

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV    # 网格搜索+交叉验证
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestClassifier  # 随机森林:分类算法
from sklearn.metrics import accuracy_score,precision_score,recall_score,f1_score

def rf():
    # 1- 准备数据
    df = pd.read_csv("data/train.csv", encoding="UTF-8")

    # 2- 数据基本处理
    # 2.1- Age字段缺失值填充:用中位数填充
    df["Age"] = df["Age"].fillna(value=df["Age"].median())

    # 2.2- 取出需要的字段
    df = df[["Survived", "Pclass", "Sex", "Age"]]

    # 2.3- Sex字符串字段列进行one-hot独热编码处理:将字符串转成数值
    df = pd.get_dummies(df)
    # print(df.info())

    # 2.4- 分别取出特征数据和目标值
    x = df.iloc[:, 1:-1]
    y = df.iloc[:, 0]
    # print(x.head())

    # 2.5- 划分训练集和测试集
    x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=617, shuffle=True)

    # 3- 特征工程
    transformer = StandardScaler()
    x_train = transformer.fit_transform(x_train)
    x_test = transformer.transform(x_test)

    # 4- 模型训练
    # 代码格式化ctrl+alt+L
    """
        参数解释:
            n_estimators:弱学习器的个数。也就是决策树的棵树。一般设置为30-200之间
            criterion:随机森林中的弱学习器使用的算法。默认是gini,也就是CART决策树
            max_features:特征列随机选择的时候,特征列的上限。
            bootstrap:每个弱学习器随机选取样本数据的时候,是否是有放回的。推举设置为True
    """
    model = RandomForestClassifier(
        n_estimators=100,
        criterion="gini",
        max_features="sqrt",
        bootstrap=True,
        max_depth=20,
        min_samples_split=2,
        min_samples_leaf=1
    )
    model.fit(x_train, y_train)

    # 5- 模型评估
    # 预测
    y_pred = model.predict(x_test)
    # 评估
    print("准确率:",accuracy_score(y_test, y_pred))
    print("精确率:",precision_score(y_test, y_pred))
    print("召回率:",recall_score(y_test, y_pred))
    print("F1值:",f1_score(y_test, y_pred))

    # 6- 模型上线
    # 无


def rf_gridsearch_cv():
    # 1- 准备数据
    df = pd.read_csv("data/train.csv", encoding="UTF-8")

    # 2- 数据基本处理
    # 2.1- Age字段缺失值填充:用中位数填充
    df["Age"] = df["Age"].fillna(value=df["Age"].median())

    # 2.2- 取出需要的字段
    df = df[["Survived", "Pclass", "Sex", "Age"]]

    # 2.3- Sex字符串字段列进行one-hot独热编码处理:将字符串转成数值
    df = pd.get_dummies(df)
    # print(df.info())

    # 2.4- 分别取出特征数据和目标值
    x = df.iloc[:, 1:-1]
    y = df.iloc[:, 0]
    # print(x.head())

    # 2.5- 划分训练集和测试集
    x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=617, shuffle=True)

    # 3- 特征工程
    transformer = StandardScaler()
    x_train = transformer.fit_transform(x_train)
    x_test = transformer.transform(x_test)

    # 4- 模型训练
    # 代码格式化ctrl+alt+L
    model = RandomForestClassifier()

    # 网格搜索+交叉验证
    param_dict = {
        "n_estimators": [20, 50, 100, 200, 500],
        "criterion": ["gini"],
        "max_features": ["sqrt","log2"],
        "bootstrap": [True],
        "max_depth": [5,10,15,20],
        "min_samples_split": [2],
        "min_samples_leaf": [1]
    }
    model = GridSearchCV(estimator=model,cv=3,param_grid=param_dict)
    model.fit(x_train, y_train)
    print("最优超参数组合:",model.best_params_)

    # 5- 模型评估
    # 预测
    y_pred = model.predict(x_test)
    # 评估
    print("准确率:",accuracy_score(y_test, y_pred))
    print("精确率:",precision_score(y_test, y_pred))
    print("召回率:",recall_score(y_test, y_pred))
    print("F1值:",f1_score(y_test, y_pred))

    # 6- 模型上线
    # 无


if __name__ == '__main__':
    # 随机森林
    rf()

    print("-"*30)

    # 随机森林+网格搜索+交叉验证
    rf_gridsearch_cv()

【理解】KMeans算法介绍

聚类算法介绍

一种典型的无监督学习算法,主要用于将相似的样本自动归到一个类别中。

在聚类算法中根据样本之间的相似性,将样本划分到不同的类别中,对于不同的相似度计算方法,会得到不同的聚类结果,常用的相似度计算方法有欧式距离法。

image-20230907095150331

聚类算法在现实中的应用

  • 用户画像,广告推荐,Data Segmentation,搜索引擎的流量推荐,恶意流量识别
  • 基于位置信息的商业推送,新闻聚类,筛选排序
  • 图像分割,降维,识别;离群点检测;信用卡异常消费;发掘相同功能的基因片段

分类

image-20230907101036326

【熟悉】基础API使用

API介绍

聚类的类别个数 等价于 簇的个数 等价于 心的个数

sklearn.cluster.KMeans(n_clusters=8)
  • 参数:
    • n_clusters:开始的聚类中心数量
      • 整型,缺省值=8,生成的聚类数,即产生的质心(centroids)数。
  • 方法:
    • estimator.fit(x)

    • estimator.predict(x)

    • estimator.fit_predict(x)

      • 计算聚类中心并预测每个样本属于哪个类别,相当于先调用fit(x),然后再调用predict(x)

案例

随机创建不同二维数据集作为训练集,并结合k-means算法将其聚类,你可以尝试分别聚类不同数量的簇,并观察聚类效果:

image-20230907102501138

from sklearn.datasets import make_blobs # 产生随机的测试数据
from sklearn.cluster import KMeans  # KMeans无监督学习算法
import matplotlib.pyplot as plt
from sklearn.metrics import calinski_harabasz_score # CH轮廓系数

if __name__ == '__main__':
    # 1- 准备数据
    """
        参数解释:
            n_samples:随机产生的样本条数
            n_features:每条样本中特征的列数。目前设置为2,也就是有2列特征,其中一列特征作为横轴,另一列特征作为纵轴
            centers:随机产生的样本对应的中心点坐标
            cluster_std:样本数据的标准差。标准差越大数据越离散;反之越聚集
            
        返回值解释:
            x:所有的特征数据,目前其中有2列
            y:随机产生的样本数据对应的目标值
    """
    x,y = make_blobs(
        n_samples=1000,
        n_features=2,
        centers=[[-1,-1], [0,0], [1,1], [2,2]],
        cluster_std=[0.4, 0.2, 0.2, 0.2],
        shuffle=True,
        random_state=617
    )

    # print(f"x---->{x}")
    # print(f"y---->{y}")

    # 2- 模型训练【掌握】
    # model = KMeans(n_clusters=1)
    # model = KMeans(n_clusters=2)
    # model = KMeans(n_clusters=3)
    model = KMeans(n_clusters=4)
    # 注意:因为是无监督学习,因此不要传递y进去
    y_pred = model.fit_predict(x)

    # 3- 绘制聚类效果图
    # 参数解释:c是color单词的首字母,c=y_pred不同的值渲染不同的颜色
    plt.scatter(x[:, 0], x[:, 1], c=y_pred)
    plt.show()

    # 4- 聚类算法评估指标
    print("聚类算法评估指标 CH轮廓系数:",calinski_harabasz_score(X=x, labels=y_pred))

【理解】算法原理

KMeans聚类流程:

1、随机设置K个特征空间内的点作为初始的聚类中心

2、对于其他每个点计算到K个中心的距离,未知的点选择最近的一个聚类中心点作为标记类别

3、接着对着标记的聚类中心之后,重新计算出每个聚类的新中心点(平均值)

4、如果计算得出的新中心点与原中心点一样(质心不再移动),那么结束,否则重新进行第二步过程

通过下图解释实现流程:

image-20230907103735327

用大白话总结
先随便立几个“靶子”,让大家找最近的靶子站队;站好后重新算每队的“平均位置”,把靶子移到平均位置;再让大家重新站队……反复挪靶子,直到靶子不动了,队伍就分好了。

【熟悉】评价指标

【了解】 SSE-误差平方和

  1. K 表示聚类中心的个数

  2. Ci 表示簇

  3. p 表示样本

  4. mi 表示簇的质心

    image-20260310121556367

SSE 越小,表示数据点越接近它们的中心聚类效果越好

SC轮廓系数、CH轮廓系数,它们两个是越大越好

【熟悉】肘部法

肘部法可以用来确定 K 值

  • 对于n个点的数据集,迭代计算 k from 1 to n,每次聚类完成后计算 SSE

  • SSE 是会逐渐变小的,因为每个点都是它所在的簇中心本身。

  • SSE 变化过程中会出现一个拐点,下降率突然变缓时即认为是最佳 n_clusters 值。

  • 在决定什么时候停止训练时,肘形判据同样有效,数据通常有更多的噪音,在增加分类无法带来更多回报时,我们停止增加类别。

image-20230907113314803

y轴对应的就是sse的值;x轴对应的是k,也就是簇的个数

【掌握】聚类评估的使用

import os
os.environ["OMP_NUM_THREADS"]="4"

from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt

def evaluate_fn():
    # 1- 准备数据
    x,y = make_blobs(
        n_samples=1000,
        n_features=2,
        centers=[[-1,-1], [0,0], [1,1], [2,2]],
        cluster_std=[0.4, 0.2, 0.2, 0.2],
        shuffle=True,
        random_state=310
    )

    # 2- 肘方法:调整n_clusters超参数的值,得到评估指标
    evaluate_value_list = []

    for n_clusters in range(1,101):
        model = KMeans(n_clusters=n_clusters)
        y_pred = model.fit_predict(x)

        # 得到评估指标
        evaluate_value_list.append(model.inertia_)

    # 3- 绘制图形
    fig = plt.figure(figsize=(20, 10), dpi=200)
    plt.plot(range(1,101), evaluate_value_list, c="r")
    plt.xticks(ticks=range(1, 101, 3))
    plt.title("SSE")
    plt.xlabel("n_clusters")
    plt.ylabel("SSE")
    plt.grid()
    plt.show()

if __name__ == '__main__':
    evaluate_fn()

【掌握】综合案例

案例介绍

已知:客户性别、年龄、年收入、消费指数

需求:对客户进行分析,找到业务突破口,寻找黄金客户

image-20230907112055346

数据集共包含顾客的数据, 数据共有 4 个特征, 数据共有 200 条。接下来,使用聚类算法对具有相似特征的的顾客进行聚类,并可视化聚类结果。

案例实现

from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import pandas as pd

def evaluate_fn():
    # 1- 准备数据
    df = pd.read_csv("data/customers.csv",encoding="UTF-8")
    x = df.iloc[:, 3:]  # 数据文件中只取最后两个特征

    # 2- 模型训练和预测
    sse_list = []
    for n_clusters in range(1,101):
        # 2.1- 创建模型实例对象
        model = KMeans(n_clusters=n_clusters)
        # 2.2- 模型训练和预测
        y_pred = model.fit_predict(x)
        # 2.3- 记录SSE评估指标
        sse_list.append(model.inertia_)

    # 3- 绘制肘方法的曲线:也就是n_clusters和SSE的关系曲线
    plt.figure(figsize=(20,20), dpi=200)
    plt.plot(range(1,101),sse_list,c="r")
    plt.xticks(ticks=range(1,101,3))  # 横轴刻度尺
    plt.title("SSE")
    plt.xlabel("n_clusters")
    plt.ylabel("SSE")
    plt.grid()                  # 网格线
    plt.show()

def ml(n_clusters):
    # 1- 准备数据
    df = pd.read_csv("data/customers.csv", encoding="UTF-8")
    x = df.iloc[:, 3:]  # 数据文件中只取最后两个特征

    # 2- 模型训练和预测
    # 2.1- 创建模型实例对象
    model = KMeans(n_clusters=n_clusters)
    # 2.2- 模型训练和预测
    y_pred = model.fit_predict(x)
    # 2.3- SSE评估指标
    print("SSE评估指标:",model.inertia_)

    # 3- 结果展示【了解】
    # 3.1- 将所有的样本数据展示处理
    # 参数解释:c散点的颜色;s散点的大小

    # 注意:x是DF对象,不能直接展示,需要x.values转成ndarray数组
    plt.scatter(x.values[:,0], x.values[:,1], c=y_pred, s=100)

    # 3.2- 绘制质心
    # 获得质心的坐标
    """
        质心信息解释:
            1- 返回值数据类型是ndarray数组
            2- 每一个子列表表示一个质心的坐标
    """
    cc = model.cluster_centers_
    # print(cc)
    # print(type(cc))
    # 展示质心
    plt.scatter(cc[:,0], cc[:,1], c="black", s=400)

    # 3.3- 展示图形
    plt.show()


if __name__ == '__main__':
    # 1- 通过肘方法获得最优超参
    # evaluate_fn()

    # 2- 模型训练
    ml(5)
    ml(7)
    ml(13)

本文为 程序员青阳 原创文章,遵循 CC BY-NC-SA 4.0 版权协议,转载请附上原文链接及本声明。

原文链接:https://heliufang.github.io/posts/498ab7d9/index.html