机器学习

机器学习

1.机器学习概述

机器学习(Machine Learning, ML)主要研究计算机系统对于特定任务的性能,逐步进行改善的算法和统计模型。通过输入海量训练数据对模型进行训练,使模型掌握数据所蕴含的潜在规律,进而对新输入的数据进行准确的分类或预测。

机器学习是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸优化、算法复杂度理论等多门学科。

image-20260607154341402

image-20260607154412690

image-20260607154426616

image-20260607154440031

image-20260607154459980

image-20260607154519819

1.1 人工智能、机器学习与深度学习

 人工智能(AI)是计算机科学的一个广泛领域,目标是让机器具备类人的“智能”,包括自然语言处理(NLP)、计算机视觉、机器人技术、专家系统等等;具体实现手段多种多样,包括规则系统、符号逻辑、统计方法、机器学习等。
 机器学习是AI的一个子领域,核心是通过数据驱动,让计算机进行学习并改进性能,自动发现规律(模式),并利用这些规律进行预测或决策。

 深度学习是机器学习的一个子领域,基于多层神经网络处理复杂任务。

image-20260607154717773

1.2 发展历史

1.2.1 早期探索:20世纪50-70年代

人工智能研究处于“推理期”,人们认为只要能赋予机器逻辑推理能力,机器就能具有智能。
 图灵提出“图灵测试”,定义机器智能的基本标准
 弗兰克·罗森布拉特提出感知机算法,这是最早的人工神经网络模型之一,用于线性分类问题
 亚瑟·李·塞谬尔提出“机器学习”一词,并设计了一个用于玩跳棋的学习算法

1.2.2 知识驱动与专家系统:20世纪70-80年代

随着研究推进,人们逐渐认识到,仅具有逻辑推理能力是远远实现不了人工智能的。部分人认为,要使机器具有智能,就必须设法使机器拥有知识。计算机硬件逐步发展,人工智能的研究进入以规则为主的“知识驱动”阶段。

Ø 出现众多专家系统,如MYCIN(用于医疗诊断)

Ø 引入了决策树(如ID3算法)

Ø 统计学习理论开始成形,例如贝叶斯定理在机器学习中的应用

1.2.3 数据驱动与统计学习:20世纪80年代-21世纪

专家系统面临“知识工程瓶颈”。机器学习成为一个独立的学科领域,各种机器学习技术百花初绽。基于神经网络的连接主义逐步发展,但其局限性也开始凸显。统计学习登场并占据主流,代表技术是支持向量机。互联网的发展带来了大量数据,统计学方法逐渐成为机器学习的核心。
 决策树算法得到进一步发展(如C4.5算法)
 支持向量机(SVM)被提出,成为一种强大的分类工具
 无监督学习方法开始成熟,例如K-means聚类
 随机森林和Boosting方法(如AdaBoost)引入,提升了集成学习的性能

1.2.4 深度学习崛起:21世纪初

随着计算能力(特别是GPU的发展)和数据规模的快速增长,深度学习技术得以崛起。深度神经网络主导,突破了图像、语音和文本领域的性能瓶颈。

Ø 深度信念网络(DBN)被提出,标志着深度学习研究的复兴

Ø AlexNet在ImageNet图像分类竞赛中获胜,证明了卷积神经网络(CNN)的强大性能

Ø 生成对抗网络(GAN)被提出,用于生成图像和其他生成任务

Ø Transformer架构在论文《Attention is All You Need》中提出,彻底改变了自然语言处理领域

1.2.5 大模型与通用人工智能:2020年代

深度学习进入规模化应用阶段,大语言模型和多模态模型的出现推动了机器学习的新高潮。模型参数规模空前,技术以通用性和泛化能力为目标。

Ø 自然语言处理:如OpenAI的GPT系列模型、Google的BERT

Ø 多模态模型:如OpenAI的CLIP、DeepMind的Gato

Ø 自监督学习成为重要方向,降低了对人工标注数据的依赖

Ø 强化学习和深度学习结合,应用于AlphaGo、AlphaFold等项目

1.3 机器学习应用领域

今天,在计算机科学的诸多分支学科领域中,无论是多媒体、图形学,还是网络通信、软件工程,乃至体系结构、芯片设计,都能找到机器学习技术的身影,尤其是在计算机视觉、自然语言处理等计算机应用技术领域,机器学习已成为最重要的技术进步源泉之一,并为许多交叉学科提供了重要的技术支撑。

image-20260607155623024

1.4 基本术语

image-20260607155907489

l 数据集(Data Set):多条记录的集合。

Ø 训练集(Training Set):用于训练模型的数据。

Ø 验证集(Validation Set):用于调节超参数的数据。

Ø 测试集(Test Set):用于评估模型性能的数据。

l 样本(Sample):数据集中的一条记录是关于一个事件或对象的描述,称为一个样本。

l 特征(Feature):数据集中一列反映事件或对象在某方面的表现或性质的事项,称为特征或属性。

l 特征向量(Feature Vector):将样本的所有特征表示为向量的形式,输入到模型中。

l 标签(Label):监督学习中每个样本的结果信息,也称作目标值(target)。

l 模型(Model):一个机器学习算法与训练后的参数集合,用于进行预测或分类。

l 参数(Parameter):模型通过训练学习到的值,例如线性回归中的权重和偏置。

超参数(Hyper Parameter):由用户设置的参数,不能通过训练自动学习,例如学习率、正则化系数等

2.机器学习基本理论

2.1 机器学习三要素

机器学习的方法一般主要由三部分构成:模型、策略和算法,可以认为:

机器学习方法 = 模型 + 策略 + 算法

l 模型(model):总结数据的内在规律,用数学语言描述的参数系统

l 策略(strategy):选取最优模型的评价准则

l 算法(algorithm):选取最优模型的具体方法

2.2 机器学习方法分类

机器学习的方法种类繁多,并不存在一个统一的理论体系能够涵盖所有内容。从不同的角度,可以将机器学习的方法进行不同的分类:

Ø 通常分类:按照有无监督,机器学习可以分为 有监督学习无监督学习半监督学习,除此之外还有 强化学习

Ø 按模型分类:根据模型性质,可以分为概率模型/非概率模型,线性/非线性模型等。

Ø 按学习技巧分类:根据算法基于的技巧,可以分为贝叶斯学习、核方法等。

image-20260607160303698

各种类型的机器学习方法可以用下图汇总展示:

image-20260607160352607

2.3 建模流程

我们可以以监督学习为例,考察一下机器学习的具体过程。

image-20260607160446584

可以看到,机器学习是由数据驱动的,核心是利用数据来“训练模型”;模型训练的结果需要用一定的方法来进行评估、优化,最终得到一个成熟的学习模型;最后就可以用这个模型来进行预测和解决问题了。

总结监督学习建模的整体流程如下:

image-20260607160524222

2.4 特征工程

2.4.1 什么是特征工程

特征工程(Feature Engineering)是机器学习过程中非常重要的一步,指的是通过对原始数据的处理、转换和构造,生成新的特征或选择有效的特征,从而提高模型的性能。简单来说,特征工程是将原始数据转换为可以更好地表示问题的特征形式,帮助模型更好地理解和学习数据中的规律。优秀的特征工程可以显著提高模型的表现;反之,忽视特征工程可能导致模型性能欠佳。

实际上,特征工程是一个迭代过程。特征工程取决于具体情境。它需要大量的数据分析和领域知识。其中的原因在于,特征的有效编码可由所用的模型类型、预测变量与输出之间的关系以及模型要解决的问题来确定。在此基础上,辅以不同类型的数据集(如文本与图像)则可能更适合不同的特征工程技术。因此,要具体说明如何在给定的机器学习算法中最好地实施特征工程可能并非易事。

2.4.2 特征工程的内容

1)特征选择

从原始特征中挑选出与目标变量关系最密切的特征,剔除冗余、无关或噪声特征。这样可以减少模型的复杂度、加速训练过程、并减少过拟合的风险。

特征选择不会创建新特征,也不会改变数据结构。

(1)过滤法(Filter Method)

基于统计测试(如卡方检验、相关系数、信息增益等)来评估特征与目标变量之间的关系,选择最相关的特征。

(2)包裹法(Wrapper Method)

使用模型(如递归特征消除 RFE)来评估特征的重要性,并根据模型的表现进行特征选择。

(3)嵌入法(Embedded Method)

使用模型本身的特征选择机制(如决策树的特征重要性,L1正则化的特征选择)来选择最重要的特征

2)特征转换
对数据进行数学或统计处理,使其变得更加适合模型的输入要求。
(1)归一化(Normalization)
将特征缩放到特定的范围(通常是0到1之间)。适用于对尺度敏感的模型(如KNN、SVM)。
(2)标准化(Standardization)
通过减去均值并除以标准差,使特征的分布具有均值0,标准差1。
(3)对数变换
对于有偏态的分布(如收入、价格等),对数变换可以将其转化为更接近正态分布的形式。
(4)类别变量的编码
独热编码(One-Hot Encoding):将类别型变量转换为二进制列,常用于无序类别特征。
标签编码(Label Encoding):将类别型变量映射为整数,常用于有序类别特征。
目标编码(Target Encoding):将类别变量的每个类别替换为其对应目标变量的平均值或其他统计量。
频率编码(Frequency Encoding):将类别变量的每个类别替换为该类别在数据集中的出现频率。

3)特征构造

特征构造是基于现有的特征创造出新的、更有代表性的特征。通过组合、转换、或者聚合现有的特征,形成能够更好反映数据规律的特征。

(1)交互特征

将两个特征组合起来,形成新的特征。例如,两个特征的乘积、和或差等。

例如,将年龄与收入结合创建新的特征,可能能更好地反映某些模式。

(2)统计特征

从原始特征中提取统计值,例如求某个时间窗口的平均值、最大值、最小值、标准差等。

例如,在时间序列数据中,你可以从原始数据中提取每个小时、每日的平均值。

(3)日期和时间特征

从日期时间数据中提取如星期几、月份、年份、季度等特征。

例如,将“2000-01-01”转换为“星期几”、“是否节假日”、“月初或月末”等特征。

4)特征降维

当数据集的特征数量非常大时,特征降维可以帮助减少计算复杂度并避免过拟合。通过降维方法,可以在保持数据本质的情况下减少特征的数量。

(1)主成分分析(PCA)

通过线性变换将原始特征映射到一个新的空间,使得新的特征(主成分)尽可能地保留数据的方差。

(2)线性判别分析(LDA)

一种监督学习的降维方法,通过最大化类间距离与类内距离的比率来降维。

(3)t-SNE(t-Distributed Stochastic Neighbor Embedding,t分布随机近邻嵌入)

一种非线性的降维技术,特别适合可视化高维数据。

(4)自编码器(Auto Encoder)

一种神经网络模型,通过压缩编码器来实现数据的降维。

2.4.3 常用方法

对于一个模型来说,有些特征可能很关键,而有些特征可能用处不大。

例如:

某个特征取值较接近,变化很小,可能与结果无关。

某几个特征相关性较高,可能包含冗余信息。

因此,特征选择 在特征工程中是最基本、也最常见的操作。

另外,在训练模型时有时也会遇到维度灾难,即特征数量过多。我们希望能在确保不丢失重要特征的前提下减少维度的数量,来降低训练模型的难度。所以在特征工程中,也经常会用到 特征降维 方法。

1)低方差过滤法

对于特征的选择,可以直接基于方差来判断,这是最简单的。低方差的特征意味着该特征的所有样本值几乎相同,对预测影响极小,可以将其去掉

from sklearn.feature_selection import VarianceThreshold

# 低方差过滤:删除方差低于 0.01 的特征
var_thresh = VarianceThreshold(threshold=0.01)
X_filtered = var_thresh.fit_transform(X)

2)相关系数法

image-20260607161313553

import pandas as pd

advertising = pd.read_csv("data/advertising.csv")
advertising.drop(advertising.columns[0], axis=1, inplace=True)
advertising.dropna(inplace=True)
X = advertising.drop("Sales", axis=1)
y = advertising["Sales"]
# 计算皮尔逊相关系数
print(X.corrwith(y, method="pearson"))
# TV           0.782224
# Radio        0.576223
# Newspaper    0.228299
# dtype: float64


import seaborn as sns
import matplotlib.pyplot as plt

# 使用pandas.DataFrame.corr(method="pearson")计算皮尔逊相关系数矩阵。
# 计算皮尔逊相关系数矩阵
corr_matrix = advertising.corr(method="pearson")
# 可视化热力图
sns.heatmap(corr_matrix, annot=True, cmap="coolwarm", fmt=".2f")
plt.title("Feature Correlation Matrix")
plt.show()

image-20260607161452422

image-20260607161642161

image-20260607161700909

import pandas as pd

# 每周学习时长
X = [[5], [8], [10], [12], [15], [3], [7], [9], [14], [6]]
# 数学考试成绩
y = [55, 65, 70, 75, 85, 50, 60, 72, 80, 58]
# 计算斯皮尔曼相关系数
X = pd.DataFrame(X)
y = pd.Series(y)
print(X.corrwith(y, method="spearman"))
# 0.987879

1)主成分分析(PCA)

主成分分析(Principal Component Analysis,PCA)是一种常用的降维技术,通过线性变换将高维数据投影到低维空间,同时保留数据的主要变化模式。

image-20260607161756729

import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler

n_samples = 1000
# 第1个主成分方向
component1 = np.random.normal(0, 1, n_samples)
# 第2个主成分方向
component2 = np.random.normal(0, 0.2, n_samples)
# 第3个方向(噪声,方差较小)
noise = np.random.normal(0, 0.1, n_samples)
# 构造3维数据
X = np.vstack([component1 - component2, component1 + component2, component2 + noise]).T

# 标准化
scaler = StandardScaler()
X_standardized = scaler.fit_transform(X)

# 应用PCA,将3维数据降维到2维
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_standardized)

# 可视化
# 转换前的3维数据可视化
fig = plt.figure(figsize=(12, 4))
ax1 = fig.add_subplot(121, projection="3d")
ax1.scatter(X[:, 0], X[:, 1], X[:, 2], c="g")
ax1.set_title("Before PCA (3D)")
ax1.set_xlabel("Feature 1")
ax1.set_ylabel("Feature 2")
ax1.set_zlabel("Feature 3")
# 转换后的2维数据可视化
ax2 = fig.add_subplot(122)
ax2.scatter(X_pca[:, 0], X_pca[:, 1], c="g")
ax2.set_title("After PCA (2D)")
ax2.set_xlabel("Principal Component 1")
ax2.set_ylabel("Principal Component 2")
plt.show()

2.5 模型评估和模型选择(重点)

2.5.1 损失函数

image-20260607162045217

image-20260607162122975

2.5.2 经验误差

image-20260607162159962

2.5.3 欠拟合与过拟合

image-20260607162245443

image-20260607162329495

image-20260607162344888

image-20260607162411378

image-20260607162521942

import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

plt.rcParams["font.sans-serif"] = ["KaiTi"]
plt.rcParams["axes.unicode_minus"] = False

def polynomial(x, degree):
    """构成多项式,返回 [x^1,x^2,x^3,...,x^n]"""
    return np.hstack([x**i for i in range(1, degree + 1)])


# 生成随机数据
X = np.linspace(-3, 3, 300).reshape(-1, 1)
y = np.sin(X) + np.random.uniform(-0.5, 0.5, 300).reshape(-1, 1)
fig, ax = plt.subplots(1, 3, figsize=(15, 4))
ax[0].plot(X, y, "yo")
ax[1].plot(X, y, "yo")
ax[2].plot(X, y, "yo")

# 划分训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 创建线性回归模型
model = LinearRegression()

# 欠拟合
x_train1 = x_train
x_test1 = x_test
model.fit(x_train1, y_train)  # 模型训练
y_pred1 = model.predict(x_test1)  # 预测
ax[0].plot(np.array([[-3], [3]]), model.predict(np.array([[-3], [3]])), "c")  # 绘制曲线
ax[0].text(-3, 1, f"测试集均方误差:{mean_squared_error(y_test, y_pred1):.4f}")
ax[0].text(-3, 1.3, f"训练集均方误差:{mean_squared_error(y_train, model.predict(x_train1)):.4f}")

# 恰好拟合
x_train2 = polynomial(x_train, 5)
x_test2 = polynomial(x_test, 5)
model.fit(x_train2, y_train)  # 模型训练
y_pred2 = model.predict(x_test2)  # 预测
ax[1].plot(X, model.predict(polynomial(X, 5)), "k")  # 绘制曲线
ax[1].text(-3, 1, f"测试集均方误差:{mean_squared_error(y_test, y_pred2):.4f}")
ax[1].text(-3, 1.3, f"训练集均方误差:{mean_squared_error(y_train, model.predict(x_train2)):.4f}")

# 过拟合
x_train3 = polynomial(x_train, 20)
x_test3 = polynomial(x_test, 20)
model.fit(x_train3, y_train)  # 模型训练

y_pred3 = model.predict(x_test3)  # 预测
ax[2].plot(X, model.predict(polynomial(X, 20)), "r")  # 绘制曲线
ax[2].text(-3, 1, f"测试集均方误差:{mean_squared_error(y_test, y_pred3):.4f}")
ax[2].text(-3, 1.3, f"训练集均方误差:{mean_squared_error(y_train, model.predict(x_train3)):.4f}")
plt.show()

image-20260607162634104

ai 解释代码 有点厉害了,

image-20260607170025064

image-20260607170046446

image-20260607170115764

image-20260607170130243

image-20260607170150521

image-20260607170202865

image-20260607170214836

2.5.4 正则化

image-20260607172153331

image-20260607172213928

image-20260607172231085

image-20260607172244059

import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression, Lasso, Ridge
from sklearn.metrics import mean_squared_error

plt.rcParams["font.sans-serif"] = ["KaiTi"]
plt.rcParams["axes.unicode_minus"] = False

def polynomial(x, degree):
    """构成多项式,返回 [x^1,x^2,x^3,...,x^n]"""
    return np.hstack([x**i for i in range(1, degree + 1)])

# 生成随机数据
X = np.linspace(-3, 3, 300).reshape(-1, 1)
y = np.sin(X) + np.random.uniform(-0.5, 0.5, X.size).reshape(-1, 1)
fig, ax = plt.subplots(2, 3, figsize=(15, 8))
ax[0, 0].plot(X, y, "yo")
ax[0, 1].plot(X, y, "yo")
ax[0, 2].plot(X, y, "yo")

# 划分训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
x_train1 = polynomial(x_train, 20)
x_test1 = polynomial(x_test, 20)

# 拟合
model = LinearRegression()
model.fit(x_train1, y_train)  # 模型训练
y_pred3 = model.predict(x_test1)  # 预测
ax[0, 0].plot(X, model.predict(polynomial(X, 20)), "r")  # 绘制曲线
ax[0, 0].text(-3, 1, f"测试集均方误差:{mean_squared_error(y_test, y_pred3):.4f}")
ax[1, 0].bar(np.arange(20), model.coef_.reshape(-1))  # 绘制所有系数

# L1正则化-Lasso回归
lasso = Lasso(alpha=0.01)
lasso.fit(x_train1, y_train)  # 模型训练
y_pred3 = lasso.predict(x_test1)  # 预测
ax[0, 1].plot(X, lasso.predict(polynomial(X, 20)), "r")  # 绘制曲线
ax[0, 1].text(-3, 1, f"测试集均方误差:{mean_squared_error(y_test, y_pred3):.4f}")
ax[0, 1].text(-3, 1.2, "Lasso回归")
ax[1, 1].bar(np.arange(20), lasso.coef_)  # 绘制所有系数

# L2正则化-岭回归
ridge = Ridge(alpha=1)
ridge.fit(x_train1, y_train)  # 模型训练
y_pred3 = ridge.predict(x_test1)  # 预测
ax[0, 2].plot(X, ridge.predict(polynomial(X, 20)), "r")  # 绘制曲线
ax[0, 2].text(-3, 1, f"测试集均方误差:{mean_squared_error(y_test, y_pred3):.4f}")
ax[0, 2].text(-3, 1.2, "岭回归")
ax[1, 2].bar(np.arange(20), ridge.coef_)  # 绘制所有系数
plt.show()

image-20260607173012051

image-20260607173458240

image-20260607173533977

image-20260607173549850

image-20260607173603301

image-20260607173626121

image-20260607173640267

特性 普通线性回归 (左列) Lasso 回归 (中列) 岭回归 (右列)
‌正则化类型‌ L1 ($\sum w
‌过拟合处理‌ 严重过拟合,曲线震荡 有效抑制,曲线平滑 有效抑制,曲线平滑
‌系数特点‌ 系数值很大,正负剧烈波动 ‌稀疏‌:许多系数精确为 0 ‌收缩‌:所有系数很小但不为 0
‌适用场景‌ 特征少、无噪声时 需要特征选择、假设只有少数特征重要时 特征多且都相关、希望保留所有特征时

image-20260607173710091

2.5.5 交叉验证

交叉验证(Cross-Validation)是一种评估模型泛化能力的方法,通过将数据集划分为多个子集,反复进行训练和验证,以减少因单次数据划分带来的随机性误差。通过交叉验证能更可靠地估计模型在未知数据上的表现,亦能避免因单次数据划分不合理导致的模型过拟合或欠拟合。

1)简单交叉验证(Hold-Out Validation)

将数据划分为训练集和验证集(如70%训练,30%验证)。结果受单次划分影响较大,可能高估或低估模型性能。

2)k折交叉验证(k-Fold Cross-Validation)

将数据均匀分为k个子集(称为“折”),每次用k−1折训练,剩余1折验证,重复k次后取平均性能。充分利用数据,结果更稳定。

image-20260607175457741

2.6 模型求解算法

image-20260607175543391

2.6.1 解析法

image-20260607175749849

image-20260607175800676

2.6.2 梯度下降法(重点)

image-20260607180716448

image-20260607180737787

image-20260607180754373

image-20260607180809720

def J(x):
    """目标函数"""
    return (x**2 - 2) ** 2

def gradient(x):
    """梯度"""
    return 4 * x**3 - 8 * x

x = 1  # x的初始值
alpha = 0.1  # 学习率
while (j := J(x)) > 1e-30:  # 当目标函数的值小于10的-30次幂时停止计算
    print(f"x={x}\tJ={j}")
    grad = gradient(x)  # 求解梯度
    x = x - alpha * grad  # 更新参数

image-20260607180901841

image-20260607180922046

2.6.3 牛顿法和拟牛顿法(了解)

image-20260607203919804

牛顿法和拟牛顿法一般用于解决中小规模的凸优化问题。

2.7 模型评价指标(重点)

对学习的泛化性能进行评估,不仅需要有效可行的实验估计方法,还需要有衡量模型泛化能力的评价指标,也叫做性能度量(performance measure)。

2.7.1 回归模型评价指标

模型的评价指标用于衡量模型在训练集或测试集上的性能,评估结果反映了模型预测的准确性和泛化能力。

对于回归问题,最常用的性能度量是“均方误差” (Mean Squared Error,MSE)。

1.1.1 分类模型评价指标

2.7.2 分类模型评价指标

对于分类问题,最常用的指标就是“准确率”(Accuracy),它定义为分类器对测试集正确分类的样本数与总样本数之比。此外还有一系列常用的评价指标。

image-20260607204556991

import pandas as pd
import seaborn as sns
from sklearn.metrics import confusion_matrix

label = ["猫", "狗"]  # 标签
y_true = ["猫", "猫", "猫", "猫", "猫", "猫", "狗", "狗", "狗", "狗"]  # 真实值
y_pred1 = ["猫", "猫", "狗", "猫", "猫", "猫", "猫", "猫", "狗", "狗"]  # 预测值
matrix1 = confusion_matrix(y_true, y_pred1, labels=label)  # 混淆矩阵
print(pd.DataFrame(matrix1, columns=label, index=label))
sns.heatmap(matrix1, annot=True, fmt='d', cmap='Greens')

image-20260607204628398

image-20260607204644066

from sklearn.metrics import accuracy_score

label = ["猫", "狗"]  # 标签
y_true = ["猫", "猫", "猫", "猫", "猫", "猫", "狗", "狗", "狗", "狗"]  # 真实值
y_pred1 = ["猫", "猫", "狗", "猫", "猫", "猫", "猫", "猫", "狗", "狗"]  # 预测值
accuracy = accuracy_score(y_true, y_pred1)
print(accuracy)

image-20260607204719914

from sklearn.metrics import precision_score

label = ["猫", "狗"]  # 标签
y_true = ["猫", "猫", "猫", "猫", "猫", "猫", "狗", "狗", "狗", "狗"]  # 真实值
y_pred1 = ["猫", "猫", "狗", "猫", "猫", "猫", "猫", "猫", "狗", "狗"]  # 预测值
precision = precision_score(y_true, y_pred1, pos_label="猫")  # pos_label指定正例
print(precision)

4)召回率(Recall)

image-20260607204756349

from sklearn.metrics import recall_score

label = ["猫", "狗"]  # 标签
y_true = ["猫", "猫", "猫", "猫", "猫", "猫", "狗", "狗", "狗", "狗"]  # 真实值
y_pred1 = ["猫", "猫", "狗", "猫", "猫", "猫", "猫", "猫", "狗", "狗"]  # 预测值
recall = recall_score(y_true, y_pred1, pos_label="猫")  # pos_label指定正例
print(recall)

5)F1分数(F1 Score)

image-20260607204837583

from sklearn.metrics import f1_score

label = ["猫", "狗"]  # 标签
y_true = ["猫", "猫", "猫", "猫", "猫", "猫", "狗", "狗", "狗", "狗"]  # 真实值
y_pred1 = ["猫", "猫", "狗", "猫", "猫", "猫", "猫", "猫", "狗", "狗"]  # 预测值
f1 = f1_score(y_true, y_pred1, pos_label="猫")  # pos_label指定正例
print(f1)

在代码中,我们可通过sklearn.metrics.classification_report生成分类任务的评估报告,包括精确率、召回率、F1分数等。

from sklearn.metrics import classification_report
report = classification_report(y_true, y_pred, labels=[], target_names=None)
# y_true:真实标签
# y_pred:预测的标签
# labels:可选,指定需要计算的类别列表(默认计算所有出现过的类别)
# target_names:可选,类别名称(默认使用 labels 指定的类别号)


from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report

# 生成一个二分类数据集
X, y = make_classification(n_samples=1000, n_features=20, n_classes=2, random_state=100)

# 划分训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=100)

# 训练一个逻辑回归模型
model = LogisticRegression()
model.fit(x_train, y_train)

# 预测
y_pred = model.predict(x_test)

# 生成分类报告
report = classification_report(y_test, y_pred)
print(report)

image-20260607205015504

image-20260607205027204

image-20260607205040314

image-20260607205059400

image-20260607205118490

from sklearn.metrics import roc_auc_score

auc_score = roc_auc_score(y_true, y_score)
# y_true: 真实标签(0 或 1)
# y_score: 正例的概率值或置信度


from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score

# 生成一个二分类数据集
X, y = make_classification(n_samples=1000, n_features=20, n_classes=2, random_state=100)

# 划分训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=100)

# 训练一个逻辑回归模型
model = LogisticRegression()
model.fit(x_train, y_train)

# 预测概率值(取正类的概率)
y_pred_proba = model.predict_proba(x_test)[:, 1]

# 计算AUC
auc_score = roc_auc_score(y_test, y_pred_proba)
print(auc_score)

3. KNN算法

3.1 KNN算法介绍

K近邻算法(K-Nearest Neighbors,KNN)是一种基本的分类与回归方法,属于监督学习算法。其核心思想是通过计算给定样本与数据集中所有样本的距离,找到距离最近的K个样本,然后根据这K个样本的类别或值来预测当前样本的类别或值。

image-20260608101138081

3.1.1 工作原理

计算距离:计算待分类样本与训练集中每个样本的距离。
选择K个近邻:根据计算的距离,选择距离最近的K个样本。
投票或平均:

​ 分类任务:统计K个近邻各类别的数量,将待分类样本归为数量最多的类别。

​ 回归任务:取K个近邻的平均值作为预测结果。

3.1.2 关键参数

距离度量方法:选择合适的距离度量方法,常见的有欧氏距离、曼哈顿距离、切比雪夫距离、闵可夫斯基距离等。
K值:K值的选择对结果影响很大。K值过小容易过拟合,K值过大则可能欠拟合。

3.1.3 优缺点

KNN优点:
 简单直观,易于理解和实现。
 无需训练过程,直接利用训练数据进行预测。
KNN缺点:
 计算量大,尤其是训练集较大时。
 对噪声数据较敏感。

3.1.4 API使用

1)分类

from sklearn.neighbors import KNeighborsClassifier

knn = KNeighborsClassifier(n_neighbors=2)  # KNN分类模型,K值为2
X = [[2, 1], [3, 1], [1, 4], [2, 6]]  # 特征
y = [0, 0, 1, 1]  # 标签
knn.fit(X, y)  # 模型训练
knn.predict([[4, 9]])  # 预测

image-20260608103757424

image-20260608103554047

image-20260608103645903

2)回归

from sklearn.neighbors import KNeighborsRegressor

knn = KNeighborsRegressor(n_neighbors=2)  # KNN回归模型,K值为2
X = [[2, 1], [3, 1], [1, 4], [2, 6]]  # 特征
y = [0.5, 0.33, 4, 3]  # 标签
knn.fit(X, y)  # 模型训练
knn.predict([[4, 9]])  # 预测

3.2 常见距离度量方法(了解)

3.2.1 欧氏距离

image-20260608104329543

3.2.2 曼哈顿距离

image-20260608104406656

image-20260608104453936

3.2.3 切比雪夫距离

image-20260608104518417

image-20260608104548258

3.2.4 闵可夫斯基距离

image-20260608104614027

3.3 归一化与标准化

3.3.1 归一化

image-20260608105443878

image-20260608105457810

4)API使用

from sklearn.preprocessing import MinMaxScaler

X = [[2, 1], [3, 1], [1, 4], [2, 6]]
# 归一化,区间设置为(-1,1)
X = MinMaxScaler(feature_range=(-1, 1)).fit_transform(X)
print(X)

3.3.2 标准化

image-20260608105651363

4)API使用

from sklearn.preprocessing import StandardScaler

X = [[2, 1], [3, 1], [1, 4], [2, 6]]
# 标准化
X = StandardScaler().fit_transform(X)
print(X)

3.4 案例:心脏病预测

3.4.1 数据集说明

Heart Disease数据集 https://www.kaggle.com/datasets/johnsmith88/heart-disease-dataset
 年龄:连续值
 性别:0-女,1-男
 胸痛类型:0-典型心绞痛,1-非典型心绞痛,2-非心绞痛,3-无症状
 静息血压:连续值,单位mmHg
 胆固醇:连续值,单位mg/dl
 空腹血糖:1-大于120mg/dl,0-小于等于120mg/dl
 静息心电图结果:0-正常,1-ST-T异常,2-可能左心室肥大
 最大心率:连续值
 运动性心绞痛:1-有,0-无
 运动后的ST下降:连续值
 峰值ST段的斜率:0-向上,1-水平,2-向下
 主血管数量:0到3
 地中海贫血:一种先天性贫血,0-正常,1-固定缺陷,2-可逆缺陷
 是否患有心脏病:标签,0-否,1-是

3.4.2 加载数据集

import pandas as pd

# 加载数据集
heart_disease = pd.read_csv("data/heart_disease.csv")
# 处理缺失值
heart_disease.dropna()
heart_disease.info()
heart_disease.head()

image-20260608111825826

3.4.3 数据集划分

from sklearn.model_selection import train_test_split

# 划分特征和标签
X = heart_disease.drop("是否患有心脏病", axis=1)  # 特征
y = heart_disease["是否患有心脏病"]  # 标签
# 将数据集按7:3划分为训练数据与测试数据
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=100)

3.4.4 特征工程

1)特征转换
数据集中包含多种类型的特征:
 类别型特征(需要特殊处理)
 胸痛类型:4种分类(名义变量)
 静息心电图结果:3种分类(名义变量)
 峰值ST段的斜率:3种分类(有序变量)
 地中海贫血:4种分类(名义变量)
 数值型特征(可直接标准化):年龄、静息血压、胆固醇、最大心率、运动后的ST下降、主血管数量
 二元特征(保持原样):性别、空腹血糖、运动性心绞痛
对于类别型特征,直接使用整数编码的类别特征会被算法视为有序数值,导致错误的距离计算(例如:会认为 胸痛类型=1 和 胸痛类型=2 之间的差异比 胸痛类型=1和 胸痛类型=3之间差异更小,而实际上它们都是类别)。使用 独热编码(One-Hot Encoding)可将类别特征转换为二元向量,消除虚假的顺序关系。

image-20260608112026336

from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer

# 数值型特征
numerical_features = ["年龄", "静息血压", "胆固醇", "最大心率", "运动后的ST下降", "主血管数量"]
# 类别型特征
categorical_features = ["胸痛类型", "静息心电图结果", "峰值ST段的斜率", "地中海贫血"]
# 二元特征
binary_features = ["性别", "空腹血糖", "运动性心绞痛"]
# 创建列转换器
preprocessor = ColumnTransformer(
    transformers=[
        # 对数值型特征进行标准化
        ("num", StandardScaler(), numerical_features),
        # 对类别型特征进行独热编码,使用drop="first"避免多重共线性
        ("cat", OneHotEncoder(drop="first"), categorical_features),
        # 二元特征不进行处理
        ("binary", "passthrough", binary_features),
    ]
)
# 执行特征转换
x_train = preprocessor.fit_transform(x_train)  # 计算训练集的统计信息并进行转换
x_test = preprocessor.transform(x_test)  # 使用训练集计算的信息对测试集进行转换

2)避免多重共线性

drop="first"是独热编码中的一个参数,它的核心目的是避免多重共线性(Multicollinearity)。

image-20260608112210390

3.4.5 模型训练与评估

from sklearn.neighbors import KNeighborsClassifier

# 使用K近邻分类模型,K=3
knn = KNeighborsClassifier(n_neighbors=3)
# 模型训练
knn.fit(x_train, y_train)
# 模型评估,计算准确率
knn.score(x_test, y_test)

3.4.6 模型的保存

可以使用Python的joblib库保存训练好的模型:

import joblib

joblib.dump(knn, "knn_heart_disease")

加载先前保存的模型:

# 加载模型
knn_loaded = joblib.load("knn_heart_disease")
# 预测
y_pred = knn_loaded.predict(x_test[10:11])
# 打印真实值与预测值
print(y_test.iloc[10], y_pred)

3.5 模型评估与超参数调优

3.5.1 网格搜索

网格搜索(Grid Search)是一种系统化的超参数调优方法,通过遍历预定义的超参数组合,找到使模型性能最优的参数配置。通过自动化调参避免手动试错,提高效率。
网格搜索通常嵌套交叉验证,与交叉验证结合以提高调参的可靠性:
 外层循环:遍历参数网格中的每个参数组合。
 内层循环:对每个参数组合使用交叉验证评估模型性能。

3.5.2 对心脏病预测模型进行超参数调优

对模型训练与评估部分进行修改,使用sklearn.model_selection.GridSearchCV进行交叉验证和网格搜索:

rom sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import GridSearchCV

knn = KNeighborsClassifier()
# 网格搜索参数,K值设置为1到10
param_grid = {"n_neighbors": list(range(1, 11))}
# GridSearchCV(estimator=模型, param_grid=网格搜索参数, cv=k折交叉验证)
knn = GridSearchCV(estimator=knn, param_grid=param_grid, cv=10)

# 模型训练
knn.fit(x_train, y_train)
print(pd.DataFrame(knn.cv_results_))  # 所有交叉验证结果
print(knn.best_estimator_)  # 最佳模型
print(knn.best_score_)  # 最佳得分

# 使用最佳模型进行评估
knn = knn.best_estimator_
print(knn.score(x_test, y_test))

4. 线性回归

4.1 线性回归简介

4.1.1 什么是线性回归

image-20260608131224790

image-20260608131303576

image-20260608131318515

4.1.2 线性回归应用场景

 GDP预测:用历史数据(如投资、消费、出口)建立回归模型,预测GDP增长趋势。
 广告效果评估:量化不同渠道广告投入对销售额的影响,优化预算分配。
 药物剂量研究:分析药物剂量与患者生理指标(如血压、血糖)之间的关系。
 产品质量控制:通过生产参数(温度、压力、原料配比)预测产品性能(如强度、耐久)。
 政策效果评估:分析最低工资政策对就业率的影响,或环保法规对污染排放的抑制作用。
 气候变化建模:用工业排放量、森林覆盖率等变量预测全球气温变化趋势。

4.1.3 API使用

例如,某中学教师想研究学生每周学习时间(小时)与数学考试成绩(0-100分)之间的关系,并预测学生成绩。

from sklearn.linear_model import LinearRegression

# 自变量,每周学习时长
X = [[5], [8], [10], [12], [15], [3], [7], [9], [14], [6]]
# 因变量,数学考试成绩
y = [55, 65, 70, 75, 85, 50, 60, 72, 80, 58]
# 实例化线性回归模型
model = LinearRegression()
# 模型训练

model.fit(X, y)
# 系数,每周每学习1小时,成绩会增加多少分
print(model.coef_)
# 截距
print(model.intercept_)
# 预测,每周学习11小时,成绩可能是多少分
print(model.predict([[11]]))

image-20260608131507574

4.2 线性回归求解

4.2.1 损失函数

image-20260608131628269

损失函数用于衡量模型预测值与真实值之间的误差,并通过最小化损失函数来优化模型参数。当损失函数最小时,得到的自变量系数就是最优解。

image-20260608131703442

image-20260608131717817

image-20260608131731901

4.2.2 一元线性回归解析解

image-20260608131823495

image-20260608131840393

image-20260608131856896

image-20260608131910429

4.2.3 正规方程法(解析法)

image-20260608170711647

image-20260608170730350

2)API使用

# fit_intercept: 是否计算偏置
model = sklearn.linear_model.LinearRegression(fit_intercept=True)
model.fit([[0, 3], [1, 2], [2, 1]], [0, 1, 2])
# coef_: 系数
print(model.coef_)
# intercept_: 偏置
print(model.intercept_)

4.2.4 梯度下降法

image-20260608170845848

image-20260608170858645

image-20260608170912157

import numpy as np

def J(beta):
    """目标函数"""
    return np.sum((X @ beta - y) ** 2, axis=0).reshape(-1, 1) / n

def gradient(beta):
    """梯度"""
    return X.T @ (X @ beta - y) / n * 2

X = np.array([[5], [8], [10], [12], [15], [3], [7], [9], [14], [6]])  # 自变量,每周学习时长
y = np.array([[55], [65], [70], [75], [85], [50], [60], [72], [80], [58]])  # 因变量,数学考试成绩
beta = np.array([[1], [1]])  # 初始化参数
n = X.shape[0]  # 样本数
X = np.hstack([np.ones((n, 1)), X])  # X添加一列1,与偏置项相乘
alpha = 1e-2  # 学习率
epoch = 0  # 迭代次数
while (j := J(beta)) > 1e-10 and (epoch := epoch + 1) <= 10000:
    grad = gradient(beta)  # 求解梯度
    if epoch % 1000 == 0:
        print(f"beta={beta.reshape(-1)}\tJ={j.reshape(-1)}")
    beta = beta - alpha * grad  # 更新参数
    

image-20260608170958223

5)API使用

model = sklearn.linear_model.SGDRegressor(
    loss="squared_error",  # 损失函数,默认为均方误差
    fit_intercept=True,  # 是否计算偏置
    learning_rate="constant",  # 学习率策略
    eta0=0.1,  # 初始学习率
    max_iter=1000,  # 最大迭代次数
    tol=1e-8,  # 损失值变化量小于tol时停止迭代
)
model.fit([[0, 3], [1, 2], [2, 1]], [0, 1, 2])
# coef_: 系数
print(model.coef_)
# intercept_: 偏置
print(model.intercept_)

4.3 广告投放效果预测

4.3.1 数据集说明

Advertising数据集: https://www.kaggle.com/datasets/tawfikelmetwally/advertising-dataset
 ID:序号
 TV:电视广告投放金额,单位千元
 Radio:广播广告投放金额,单位千元
 Newspaper:报纸广告投放金额,单位千元
 Sales:销售额,单位百万元

4.3.2 使用线性回归预测广告投放效果

import pandas as pd
from sklearn.preprocessing import StandardScaler  # 标准化
from sklearn.model_selection import train_test_split  # 划分数据集
from sklearn.linear_model import LinearRegression, SGDRegressor  # 线性回归-正规方程,线性回归-随机梯度下降
from sklearn.metrics import mean_squared_error  # 均方误差

# 加载数据集
advertising = pd.read_csv("data/advertising.csv")
advertising.drop(advertising.columns[0], axis=1, inplace=True)
advertising.dropna(inplace=True)
advertising.info()
print(advertising.head())

# 划分训练集与测试集
X = advertising.drop("Sales", axis=1)
y = advertising["Sales"]
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)
# 标准化
preprocessor = StandardScaler()
x_train = preprocessor.fit_transform(x_train)  # 计算训练集的均值和标准差,并标准化训练集
x_test = preprocessor.transform(x_test)  # 使用训练集的均值和标准差对测试集标准化

# 使用正规方程法拟合线性回归模型
normal_equation = LinearRegression()
normal_equation.fit(x_train, y_train)
print("正规方程法解得模型系数:", normal_equation.coef_)
print("正规方程法解得模型偏置:", normal_equation.intercept_)

# 使用随机梯度下降法拟合线性回归模型
gradient_descent = SGDRegressor()
gradient_descent.fit(x_train, y_train)
print("随机梯度下降法解得模型系数:", gradient_descent.coef_)
print("随机梯度下降法解得模型偏置:", gradient_descent.intercept_)

# 使用均方误差评估模型
print("正规方程法均方误差:", mean_squared_error(y_test, normal_equation.predict(x_test)))
print("随机梯度下降法均方误差:", mean_squared_error(y_test, gradient_descent.predict(x_test)))

5 逻辑回归

5.1 逻辑回归简介

5.1.1 什么是逻辑回归

image-20260609104740395

image-20260609104801480

5.1.2 逻辑回归应用场景

l 信用评分:预测客户是否会违约(违约/不违约)。

l 欺诈检测:预测某笔交易是否是欺诈行为。

l 垃圾邮件检测:预测一封邮件是否是垃圾邮件(垃圾邮件/非垃圾邮件)。

l 广告点击预测:预测用户是否会点击某个广告(点击/不点击)。

l 图像分类:将图像分类为不同的类别(如猫、狗、鸟等)。

l 情感分析:将文本分类为正面、负面或中性情感。

l 产品质量分类:预测产品是否合格。

l 医学诊断:预测患者是否患有某种疾病(患病/未患病)。

蛋白质功能预测:基于蛋白质序列和结构特征预测其功能类别。

5.1.3 逻辑回归损失函数

image-20260609104907750

5.1.4 损失函数的梯度(了解)

image-20260609104936140

image-20260609104956822

5.1.5 API使用

1)LogisticRegression参数说明

scikit-learn中的LogisticRegression类用于实现逻辑回归。它支持二分类和多分类任务,并提供了多种优化算法和正则化选项。

# solver: 优化算法
#   lbfgs: 拟牛顿法(默认),仅支持L2正则化
#   newton-cg: 牛顿法,仅支持L2正则化
#   liblinear: 坐标下降法,适用于小数据集,支持L1和L2正则化
#   sag: 随机平均梯度下降,适用于大规模数据集,仅支持L2正则化
#   saga: 改进的随机梯度下降,适用于大规模数据,支持L1、L2和ElasticNet正则化
# penalty: 正则化类型,可选l1、l2和elasticnet
# C: 正则化强度,C越小,正则化强度越大
# class_weight: 类别权重,balanced表示自动平衡类别权重,让模型在训练时更关注少数类,从而减少类别不平衡带来的偏差
model = sklearn.linear_model.LogisticRegression(solver="lbfgs", penalty="l2", C=1, class_weight="balanced")

1)案例:心脏病预测

Heart Disease数据集 https://www.kaggle.com/datasets/johnsmith88/heart-disease-dataset

Ø 年龄:连续值

Ø 性别:0-女,1-男

Ø 胸痛类型:0-典型心绞痛,1-非典型心绞痛,2-非心绞痛,3-无症状

Ø 静息血压:连续值,单位mmHg

Ø 胆固醇:连续值,单位mg/dl

Ø 空腹血糖:1-大于120mg/dl,0-小于等于120mg/dl

Ø 静息心电图结果:0-正常,1-ST-T异常,2-可能左心室肥大

Ø 最大心率:连续值

Ø 运动性心绞痛:1-有,0-无

Ø 运动后的ST下降:连续值

Ø 峰值ST段的斜率:0-向上,1-水平,2-向下

Ø 主血管数量:0到3

Ø 地中海贫血:一种先天性贫血,0-正常,1-固定缺陷,2-可逆缺陷

Ø 是否患有心脏病:标签,0-否,1-是

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.linear_model import LogisticRegression

# 加载数据集
heart_disease = pd.read_csv("data/heart_disease.csv")
heart_disease.dropna()

# 划分为训练集与测试集
X = heart_disease.drop("是否患有心脏病", axis=1)  # 特征
y = heart_disease["是否患有心脏病"]  # 标签
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=100)

# 特征工程
# 数值型特征
numerical_features = ["年龄", "静息血压", "胆固醇", "最大心率", "运动后的ST下降", "主血管数量"]
# 类别型特征
categorical_features = ["胸痛类型", "静息心电图结果", "峰值ST段的斜率", "地中海贫血"]
# 二元特征
binary_features = ["性别", "空腹血糖", "运动性心绞痛"]
# 创建列转换器
preprocessor = ColumnTransformer(
    transformers=[
        # 对数值型特征进行标准化
        ("num", StandardScaler(), numerical_features),
        # 对类别型特征进行独热编码,使用drop="first"避免多重共线性
        ("cat", OneHotEncoder(drop="first"), categorical_features),
        # 二元特征不进行处理
        ("binary", "passthrough", binary_features),
    ]
)
# 执行特征转换
x_train = preprocessor.fit_transform(x_train)  # 计算训练集的统计信息并进行转换
x_test = preprocessor.transform(x_test)  # 使用训练集计算的信息对测试集进行转换

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

# 模型评估,计算准确率
model.score(x_test, y_test)

5.2 多分类任务

逻辑回归通常用于二分类问题,但可以通过一对多(One-vs-Rest,OvR)以及Softmax回归(Multinomial Logistic Regression,多项逻辑回归)来扩展到多分类任务。

5.2.1 一对多(OVR)

image-20260609111102582

缺点:每个类别训练1个分类器,当类别数量较多时,训练时间较长。

3)API

from sklearn.linear_model import LogisticRegression

model = LogisticRegression(multi_class="ovr")

# 或

from sklearn.multiclass import OneVsRestClassifier

model = OneVsRestClassifier(LogisticRegression())

5.2.2 Softmax回归(多项逻辑回归)

image-20260609111231041

3)API

from sklearn.linear_model import LogisticRegression

model = LogisticRegression(multi_class="multinomial")

# 对于多分类问题,LogisticRegression会自动使用multinomial,因此multi_class参数可省略

model = LogisticRegression()

5.3 案例: 手写数字识别

5.3.1 数据集说明

Digit Recognizer数据集: https://www.kaggle.com/competitions/digit-recognizer

image-20260609111435899

5.3.2 逻辑回归实现手写数字识别

import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
from sklearn.linear_model import LogisticRegression

# 加载数据集
digit = pd.read_csv("data/train.csv")
plt.imshow(digit.iloc[10, 1:].values.reshape(28, 28), cmap="gray")
plt.show()

image-20260609111530995

# 划分训练集和测试集
X = digit.drop("label", axis=1)  # 特征
y = digit["label"]  # 标签
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=100)

# 归一化
preprocessor = MinMaxScaler()
x_train = preprocessor.fit_transform(x_train)
x_test = preprocessor.transform(x_test)

# 模型训练
model = LogisticRegression(max_iter=500)
model.fit(x_train, y_train)

# 模型评估
model.score(x_test, y_test)

# 预测
plt.imshow(digit.iloc[123, 1:].values.reshape(28, 28), cmap="gray")
plt.show()
print(model.predict(digit.iloc[123, 1:].values.reshape(1, -1)))

6 感知机

6.1 感知机的概念

image-20260609115244703

感知机的多个输入信号都有各自的权重,这些权重发挥着控制各个信号的重要性的作用,权重越大,对应信号的重要性越高。

6.2 简单逻辑电路

6.2.1 与门

image-20260609115401712

6.2.2 与非门

image-20260609115446733

6.2.3 或门

再来看一下或门(OR gate)。或门只要有一个输入信号为1,输出就为1。

image-20260609115532416

6.3 感知机的实现

6.3.1 简单实现

image-20260609115651377

def AND(x1, x2):
    w1, w2, theta = 0.5, 0.5, 0.7
    res = x1 * w1 + x2 * w2
    if res <= theta:
        return 0
    elif res > theta:
        return 1

print(AND(0, 0))  # 0
print(AND(1, 0))  # 0
print(AND(0, 1))  # 0
print(AND(1, 1))  # 1

可以以同样的方式实现与非门和或门,不过在此之前先做一些修改。

6.3.2 导入权重和偏置

image-20260609115755668

import numpy as np
def AND(x1, x2):
    x = np.array([x1, x2])
    w = np.array([0.5, 0.5])
    b = -0.7
    tmp = np.sum(w * x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

print(AND(0, 0))  # 0
print(AND(1, 0))  # 0
print(AND(0, 1))  # 0
print(AND(1, 1))  # 1

image-20260609115831111

import numpy as np

def NAND(x1, x2):
    x = np.array([x1, x2])
    w = np.array([-0.5, -0.5])
    b = 0.7
    tmp = np.sum(w * x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

print(NAND(0, 0))  # 1
print(NAND(1, 0))  # 1
print(NAND(0, 1))  # 1
print(NAND(1, 1))  # 0

def OR(x1, x2):
    x = np.array([x1, x2])
    w = np.array([0.5, 0.5])
    b = -0.2
    tmp = np.sum(w * x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

print(OR(0, 0))  # 0
print(OR(1, 0))  # 1
print(OR(0, 1))  # 1
print(OR(1, 1))  # 1

与门、与非门、或门是具有相同构造的感知机,区别仅在于权重参数的值。因此在与非门和或门的实现中,仅设置权重和偏置的值这一点和与门的实现不同。

6.4 感知机的局限

image-20260609115942954

image-20260609120000101

image-20260609120011378

6.5 多层感知机

image-20260609120034881

image-20260609120044803

import numpy as np

def AND(x1, x2):
    x = np.array([x1, x2])
    w = np.array([0.5, 0.5])
    b = -0.7
    tmp = np.sum(w * x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

def NAND(x1, x2):
    x = np.array([x1, x2])
    w = np.array([-0.5, -0.5])
    b = 0.7
    tmp = np.sum(w * x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

def OR(x1, x2):
    x = np.array([x1, x2])
    w = np.array([0.5, 0.5])
    b = -0.2
    tmp = np.sum(w * x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

def XOR(x1, x2):
    s1 = NAND(x1, x2)
    s2 = OR(x1, x2)
    y = AND(s1, s2)
    return y

print(XOR(0, 0))  # 0
print(XOR(1, 0))  # 1
print(XOR(0, 1))  # 1
print(XOR(1, 1))  # 0

image-20260609120118736

7 其他监督学习算法(了解)

7.1 朴素贝叶斯法

7.1.1 朴素贝叶斯法简介

朴素贝叶斯(naive Bayes)法是一种基于概率的机器学习算法。它基于贝叶斯定理,并假设特征之间相互独立(这就是“朴素”的来源)。朴素贝叶斯法实现简单,学习与预测的效率都很高,是一种常用方法,在许多场景下表现得非常好,如文本分类(垃圾邮件检测)、情感分析等。

image-20260609122115554

7.1.2 极大似然估计

image-20260609122139673

7.1.3 贝叶斯估计

image-20260609122213802

7.1.4 学习与分类过程

image-20260609122245722

7.2 决策树

7.2.1 决策树简介

决策树(Decision Tree)是一种基于树形结构的算法,根据一系列条件判断逐步划分数据,缩小范围,最终得出预测结果。决策树由4部分组成:
 根节点:树的节点,包含所有数据。
 内部节点:表示特征上的判断条件。
 分支:根据判断条件分出的路径。
 叶节点:最终分类或回归的结果。

image-20260609162108548

决策树适用于需要规则化、可解释性和快速决策的场景,尤其在数据特征明确、样本量适中的情况下表现良好。在复杂任务中,它常作为基础模型,与集成学习结合(如随机森林、梯度提升树)以提升性能。

7.2.2 决策树工作过程

决策树的学习通常包括3个步骤:特征选择、决策树的生成和决策树的剪枝。

如果特征数量很多,可以在决策树学习之前对特征进行选择,只留下对训练数据有足够分类能力的特征。

学习时通常是递归地选择最优特征,并根据该特征对训练数据进行划分,使得对各个子数据集有一个最好的分类。

Ø 首先构建根结点,将所有训练数据都放在根结点。

Ø 选择一个最优特征,按照这一特征将训练数据集划分成子集,使得各个子集有一个在当前条件下最好的分类。

Ø 如果这些子集已经能够被基本正确分类,那么构建叶结点,并将这些子集分到所对应的叶结点中去;如果还有子集不能被基本正确分类,那么就对这些子集选择新的最优特征,继续对其进行划分并构建相应的结点。

Ø 如此递归直至所有训练数据子集被基本正确分类,或者没有合适的特征为止。

最后每个子集都被分到叶结点上,即都有了明确的类,这就生成了一棵决策树。决策树的每次划分都相当于在特征空间中引入一个超平面将当前空间一分为二。

以上方法生成的决策树可能对训练数据有很好的分类能力,但对未知的测试数据却未必,即可能发生过拟合现象。因此需要对已生成的树自下而上进行剪枝,将树变得更简单,从而可能发生过拟合现象。因此需要对已生成的树自下而上进行剪枝,将树变得更简单,从而使它具有更好的泛化能力。具体地,就是去掉过于细分的叶结点,使其回退到父结点或更高的结点,然后将父结点或更高的结点改为新的叶结点。

决策树的生成只考虑局部最优,决策树的剪枝则考虑全局最优。

7.2.3 特征选择与决策树生成

特征选择在于选取对训练数据具有分类能力的特征,这样可以提高决策树学习的效率。如果利用一个特征进行分类的结果与随机分类的结果没有很大差别,则称这个特征是没有分类能力的,经验上扔掉这样的特征对决策树学习的精度影响不大。通常特征选择的准则是信息增益或信息增益率。

image-20260609162247380

image-20260609162256222

image-20260609162330430

image-20260609162343191

image-20260609162359500

image-20260609162419628

image-20260609162432075

image-20260609162443154

7.2.4 决策树的剪枝

image-20260609162524071

image-20260609162542971

7.3 支持向量机

7.3.1 支持向量机简介

image-20260609170321304

7.3.2 线性可分支持向量机-硬间隔

1)硬间隔

当训练样本线性可分时,此时可以通过最大化硬间隔来学习线性可分支持向量机。硬间隔是指超平面能够将不同类的样本完全划分开。距离超平面最近的几个样本点称为支持向量,它们直接决定超平面的位置和方向,只要支持向量不变,超平面就不会变。

image-20260609170406407

image-20260609170417959

image-20260609170433706

image-20260609170445154

image-20260609170459093

7.3.3 线性支持向量机-软间隔

image-20260609170522907

image-20260609170535234

这就是软间隔支持向量机。

7.3.4 非线性支持向量机-核函数

image-20260609170633018

image-20260609170647745

image-20260609170657642

7.4 集成学习

集成学习(Ensemble Learning)通过某种策略组合多个个体学习器的预测结果来提高整体的预测能力。只包含同种类型的个体学习器的集成称为同质集成,例如决策树集成中全是决策树,同质集成中的个体学习器亦称基学习器,相应的学习算法称为基学习算法。包含不同类型的个体学习器的集成称为异质集成,例如同时包含决策树和神经网络。

集成学习有三大经典方法:Boosting、Bagging和Stacking。

Boosting(提升方法)按顺序训练模型,每个模型关注前一个模型的错误,通过加权调整来优化整体预测。如AdaBoost通过给错分的样本更大的权重,逐步改进;梯度提升树用梯度下降法优化损失函数;XGBoost和LightGBM是高效的梯度提升树变种。Boosting主要关注于降低偏差。

Bagging(Bootstrap Aggregating,自助聚合)从原始数据集中通过有放回的对样本采样生成多个子数据集,分别训练多个独立模型,最后通过投票(分类)或平均(回归)得到结果。随机森林则是在Bagging基础上随机选择特征子集训练每棵树。Bagging主要关注于降低方差。

Stacking(堆叠)训练多个不同类型的个体学习器,之后使用一个元模型综合多个个体学习器的预测。灵活性强,能结合多种模型的优势。

7.4.1 AdaBoost

在概率近似正确学习的框架中,一个概念如果存在一个多项式的学习算法能够学习它,并且正确率很高,就称这个概念是强可学习的;一个概念如果存在一个多项式的学习算法能够学习它,但正确率仅比随机猜测略好,就称这个概念是弱可学习的。后来证明,强可学习与弱可学习是等价的。那么如果已经发现了弱学习算法,能否通过某种方式将其提升为强学习算法?
对于分类问题而言,给定一个训练样本集,求比较粗糙的分类规则(弱分类器)要比求精确的分类规则(强分类器)容易的多。Boosting就是从弱学习算法出发,反复学习,得到一系列弱分类器,然后组合这些弱分类器构成一个强分类器。AdaBoost通常使用单层决策树作为基学习器,单层决策树也被称为决策树桩(Decision Stump)。
大多数Boosting都是改变训练数据的概率分布(权重分布),针对不同的训练数据分布调用弱学习算法学习一系列弱分类器。AdaBoost(Adaptive Boosting,自适应提升)的做法是提高被前一轮弱分类器错误分类的样本的权重,降低被正确分类的样本的权重。这样一来后一轮弱学习器会更加关注那些没有被正确分类的数据。同时采用加权多数表决的方法,加大分类误差率小的弱分类器的权重,减小分类误差率大的弱分类器的权重。

image-20260609170836365

image-20260609170852202

7.4.2 随机森林

image-20260609170914640

image-20260609170932284

image-20260609170948846

随机森林简单易实现,但在很多任务中都展现出了强大性能,被誉为“代表集成学习技术水平的方法”。Bagging中基学习器的多样性仅来自于样本扰动,而随机森林中基学习器的多样性不仅来自样本扰动,还来自特征扰动,这就使得最终集成的泛化性能可通过基学习器之间差异度的增加而进一步提升。

8 无监督学习

8.1 聚类

8.1.1 聚类简介

聚类(Clustering)旨在将数据集中的样本分成若干个簇,使得同一个簇内的对象彼此相似,不同簇间的对象差异较大。聚类是一种无监督学习算法,不需要预先标记数据的标签,完全依赖数据本身内在结构和特征来进行分组,最终簇所对应的概念语义需由使用者来把握和命名。
聚类的核心是“物以类聚”,具体通过以下步骤实现:
 定义相似性:选择一个度量标准(如欧氏距离,余弦相似度)来衡量对象之间的相似性或距离。
 分组:根据相似性将对象分配到不同的簇中。
 优化:通过迭代或直接计算,调整簇的划分,使簇内相似性最大化,簇间差异最大化。
聚类应用场景:
 市场细分:将消费者按购买习惯分组。
 图像分割:将图像像素按颜色或纹理聚类。
 异常检测:识别不属于任何主要簇的异常点。
 生物信息:对基因表达数据进行分组。

8.1.2 常见聚类算法

image-20260609202445940

image-20260609202526327

image-20260609202540080

(2)K均值聚类工作流程

image-20260609202728913

image-20260609202742230

image-20260609202753130

image-20260609202811691

image-20260609202823184

image-20260609202837240

8.1.3 K-means API使用

kmeans = KMeans(n_clusters=3)
# n_clusters: 指定 K 的值
kmeans.fit(X)  # 训练
kmeans.predict(X)  # 预测
kmeans.fit_predict(X)  # 训练并预测
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs

plt.rcParams["font.sans-serif"] = ["KaiTi"]
plt.rcParams["axes.unicode_minus"] = False

# 使用 make_blobs 生成 3 个簇,每个簇 100 个点
X, y_true = make_blobs(n_samples=300, centers=3, cluster_std=2)

fig, ax = plt.subplots(2, figsize=(8, 8))
ax[0].scatter(X[:, 0], X[:, 1], s=50, c="gray", label="原始数据")
ax[0].set_title("原始数据")
ax[0].legend()

# 使用 K-Means 聚类
kmeans = KMeans(n_clusters=3)
kmeans.fit(X)
y_kmeans = kmeans.predict(X)  # 预测每个点的簇标签
centers = kmeans.cluster_centers_  # 获取簇中心

ax[1].scatter(X[:, 0], X[:, 1], s=50, c=y_kmeans)
ax[1].scatter(centers[:, 0], centers[:, 1], s=200, c="red", marker="o", label="簇中心")
ax[1].set_title("K-means 聚类结果 (K=3)")
ax[1].legend()
plt.show()

image-20260609202943726

8.1.4 聚类模型评估(了解)

image-20260609203022720

image-20260609203038856

image-20260609203048662

image-20260609203106295

5)聚类评估API使用

import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.metrics import silhouette_score, calinski_harabasz_score

plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False

# 使用 make_blobs 生成 3 个簇,每个簇 100 个点
X, y_true = make_blobs(n_samples=300, centers=3, cluster_std=5)
# 使用 K-Means 聚类
kmeans = KMeans(n_clusters=3)
kmeans.fit(X)
y_kmeans = kmeans.predict(X)  # 预测每个点的簇标签
centers = kmeans.cluster_centers_  # 获取簇中心
plt.scatter(X[:, 0], X[:, 1], s=50, c=y_kmeans, cmap="viridis")
plt.scatter(centers[:, 0], centers[:, 1], s=200, c="red", marker="*", label="簇中心")
plt.legend()
print("簇内平方和:", kmeans.inertia_)
print("轮廓系数:", silhouette_score(X, y_kmeans))
print("CH指数:", calinski_harabasz_score(X, y_kmeans))
plt.show()

8.2 降维(了解)

8.2.1 奇异值分解

image-20260609203228116

image-20260609203238935

image-20260609203259072

image-20260609203312038

image-20260609203331595

image-20260609203342041

image-20260609203400981

image-20260609203409817

numpy 中的 linalg.svd 函数

image-20260609210932204

image-20260609211059112

8.2.2 主成分分析

image-20260609203455847

image-20260609203505553

image-20260609203519088

image-20260609211941201

posted @ 2026-06-09 21:26  Ref-brief  阅读(6)  评论(1)    收藏  举报