机器学习概述 + Python 语言基础 · 知识点详解
本文档面向零基础初学者,每个知识点均包含:概念解释 → 直观理解 → 示例/代码 → 要点总结。建议按顺序阅读。
第一部分:机器学习概述
1.1 机器学习的定义
1.1.1 什么是机器学习
定义(Tom Mitchell, 1997,经典定义):
如果一个计算机程序针对某类任务 T,用性能指标 P 来衡量,在经验 E 上的性能随经验 E 的积累而自我改善,那么我们称这个程序"从经验 E 中学习"。
用公式化的语言描述:
任务 T: 程序要做的事(如"识别图片中是否有猫")
性能 P: 衡量好坏的标准(如"识别准确率")
经验 E: 数据和历次尝试的积累(如"10 万张已标注的图片")
通俗理解: 机器学习不是让程序员把所有规则写死,而是让计算机从数据中自己总结规律,并用这些规律对新数据做预测或决策。
1.1.2 机器学习与相关概念的区别
| 概念 | 核心思想 | 举例 |
|---|---|---|
| 传统编程 | 人写规则,机器执行 | if 温度>100: 报警 |
| 机器学习 | 人提供数据和答案,机器学出规则 | 给 1 万个锅炉数据,让模型学出报警条件 |
| 深度学习 | 机器学习的子集,用多层神经网络自动学特征 | 人脸识别、ChatGPT |
| 人工智能(AI) | 最大的范畴,让机器表现出智能 | 机器人、自动驾驶 |
| 数据挖掘 | 从大量数据中发现隐藏模式 | 超市购物篮分析 |
包含关系: 人工智能 ⊃ 机器学习 ⊃ 深度学习
1.1.3 机器学习 vs 传统编程(关键区别)
传统编程: 数据 + 规则 → 程序运行 → 结果
机器学习: 数据 + 结果 → 训练 → 模型(规则)
然后: 模型 + 新数据 → 预测 → 预测结果
1.1.4 机器学习能做什么、不能做什么
擅长:
- 规则复杂难以用代码穷举的问题(如"什么样的邮件是垃圾邮件")
- 有大量历史数据、需要预测的问题
- 模式识别:图像、语音、文本理解
不擅长:
- 数据极少的问题
- 要求 100% 精确、可解释性极强的场景(如法律条文判定)
- 超出训练数据分布太远的情况(外推能力有限)
1.2 发展历程与趋势
1.2.1 发展历程
第一阶段:推理期(20 世纪 50---70 年代)
- 核心思想:让机器模拟人的逻辑推理。
- 代表:符号主义,如"逻辑理论家"程序、专家系统。
- 局限:只能解决"玩具问题",无法处理现实中的模糊信息(如识别人脸)。
第二阶段:知识期(20 世纪 70---80 年代)
- 核心思想:把专家的知识总结成规则库,机器查规则做决策。
- 代表:医疗专家系统 MYCIN。
- 局限:知识获取困难("知识工程瓶颈"),规则之间冲突难以维护。
第三阶段:学习期(20 世纪 80 年代至今)------机器学习的黄金时代
- 核心思想:让机器从数据中自动学习。
- 关键里程碑:
| 时间 | 事件 | 意义 |
|---|---|---|
| 1986 | 反向传播算法(BP)用于多层神经网络 | 神经网络可训练 |
| 1995 | 支持向量机(SVM) 提出 | 统计学习理论成熟 |
| 1997 | IBM 深蓝战胜国际象棋冠军 | 机器在特定领域超越人类 |
| 2006 | Hinton 提出深度学习(深层神经网络预训练) | 深度学习复兴 |
| 2012 | AlexNet 在 ImageNet 竞赛夺冠 | 深度学习爆发 |
| 2016 | AlphaGo 战胜李世石 | 强化学习重大突破 |
| 2017 | Transformer 架构提出 | 大模型时代的基础 |
| 2020s | GPT 系列、大语言模型(LLM) | 生成式 AI 浪潮 |
驱动因素: 算力提升(GPU/TPU)+ 数据爆发(互联网)+ 算法创新(深度学习)。
1.2.2 发展趋势
- 大模型与预训练:一个超大模型在海量数据上预训练,再适配到各种下游任务(如 BERT、GPT)。
- 多模态融合:同时处理文本、图像、语音、视频。
- AutoML(自动化机器学习):自动选择模型、调参,降低使用门槛。
- 可解释性 AI(XAI):让"黑箱"模型的决策可理解、可追溯。
- 边缘计算与模型轻量化:把模型部署到手机、IoT 设备上。
- 小样本/零样本学习:用极少的数据学会新任务。
- 隐私保护与联邦学习:数据不出本地,多方协同训练。
- AI 与行业深度融合:医疗、金融、制造、教育等。
1.3 基本原理与关键术语
1.3.1 基本原理(机器学习的完整流程)
机器学习解决问题的标准流程(非常重要,贯穿所有项目):
1. 问题定义 → 我要预测什么?(分类?回归?)
2. 数据收集 → 从哪获得数据?
3. 数据预处理 → 清洗缺失值、异常值、特征缩放
4. 特征工程 → 把原始数据变成有信息量的特征
5. 选择模型 → 用什么算法?
6. 训练模型 → 用训练数据拟合模型(求参数)
7. 评估模型 → 用测试数据检验好坏
8. 调优 → 调超参数、换模型、加特征
9. 部署与监控 → 上线使用,持续观察效果
核心原理一句话概括: 基于"训练数据与未来数据同分布"的假设,通过最小化某个损失函数,找到一个从输入到输出的最优映射函数。
1.3.2 关键术语(务必记牢,面试与考试高频)
1. 数据集相关
| 术语 | 英文 | 解释 | 举例 |
|---|---|---|---|
| 样本/实例 | Sample / Instance | 一条数据记录 | 一位患者的一次体检记录 |
| 特征/属性 | Feature / Attribute | 描述样本的属性 | 年龄、血压、体重 |
| 标签/目标 | Label / Target | 要预测的答案 | 是否患病(是/否) |
| 特征向量 | Feature Vector | 一个样本所有特征组成的向量 | [35, 120, 70] |
| 数据集 | Dataset | 所有样本的集合 | 1 万份体检记录 |
| 维度 | Dimension | 特征的个数 | 3 个特征 → 3 维 |
| 训练集 | Training Set | 用来训练模型(约占 60%~80%) | |
| 验证集 | Validation Set | 用来调超参数、选模型(约 10%~20%) | |
| 测试集 | Test Set | 用来最终评估(约 10%~20%) | |
| 留出法 | Hold-out | 直接按比例划分数据集 | 7:3 划分 |
| k 折交叉验证 | k-Fold CV | 数据分 k 份轮流做测试集 | 5 折交叉验证 |
| 样本不均衡 | Imbalanced Data | 各类别样本数量差距大 | 欺诈样本仅占 0.1% |
2. 学习类型相关
| 术语 | 解释 | 典型算法 |
|---|---|---|
| 监督学习 | 训练数据带标签 | 线性回归、决策树、SVM、神经网络 |
| 无监督学习 | 训练数据无标签 | K-Means 聚类、PCA 降维 |
| 半监督学习 | 少量标签 + 大量无标签数据 | Self-training |
| 强化学习 | 智能体与环境交互,通过奖励学习策略 | Q-Learning、PPO(AlphaGo) |
| 分类 | 预测离散类别 | 邮件是否垃圾邮件 |
| 回归 | 预测连续数值 | 房价预测 |
| 聚类 | 自动把数据分组 | 客户分群 |
| 降维 | 减少特征数量 | PCA、t-SNE |
3. 模型训练相关
| 术语 | 英文 | 解释 |
|---|---|---|
| 假设空间 | Hypothesis Space | 模型所有可能的取值范围 |
| 损失函数 | Loss Function | 衡量预测值与真实值的差距(越小越好) |
| 代价函数 | Cost Function | 整个训练集上的平均损失 |
| 目标函数 | Objective Function | 代价函数 + 正则化项 |
| 经验风险 | Empirical Risk | 模型在训练集上的误差 |
| 结构风险 | Structural Risk | 经验风险 + 模型复杂度惩罚 |
| 梯度 | Gradient | 函数上升最快的方向(导数的推广) |
| 学习率 | Learning Rate (η) | 每次参数更新的步长 |
| 超参数 | Hyperparameter | 训练前人为设定的参数(如学习率、树的深度) |
| 参数 | Parameter | 模型训练过程中自动学到的量(如权重 w) |
4. 模型效果相关(重点!)
| 术语 | 解释 | 通俗说法 |
|---|---|---|
| 过拟合 | Overfitting | 模型把训练数据"背"得太死,新数据上表现差(高方差) |
| 欠拟合 | Underfitting | 模型学得太简单,训练数据都拟合不好(高偏差) |
| 泛化能力 | Generalization | 对没见过的新数据的预测能力 |
| 偏差(Bias) | 模型预测值与真实值的系统性偏离 | 模型"学得太少" |
| 方差(Variance) | 模型对不同训练数据的敏感程度 | 模型"学得太多、不稳" |
| 偏差-方差权衡 | Bias-Variance Tradeoff | 复杂度↑ → 偏差↓ 方差↑ |
判断过拟合/欠拟合的方法:
训练误差小 + 测试误差大 → 过拟合(解决:更多数据、正则化、简化模型)
训练误差大 + 测试误差大 → 欠拟合(解决:增加特征、增加模型复杂度、训练更久)
训练误差小 + 测试误差小 → 理想状态 ✓
5. 分类任务评估指标(重点!)
以"预测是否患病"为例,混淆矩阵:
| 预测为正(患病) | 预测为负(健康) | |
|---|---|---|
| 实际为正 | TP(真正例)✓ | FN(假负例)✗ 漏报 |
| 实际为负 | FP(假正例)✗ 误报 | TN(真负例)✓ |
准确率 Accuracy = (TP+TN) / (TP+TN+FP+FN) --- 所有预测中正确的比例
精确率 Precision = TP / (TP+FP) --- 预测为正的里面有多少真的正
召回率 Recall = TP / (TP+FN) --- 真实为正的里面找回来多少
F1 值 = 2 × P × R / (P + R) --- 精确率与召回率的调和平均
记忆技巧:
- 精确率关心"我说是的,是不是真的是"(查得准)
- 召回率关心"该抓的,有没有都抓到"(查得全)
- 不均衡数据下,准确率会骗人,要看 F1、AUC 等。
回归任务评估指标:
均方误差 MSE = (1/n) Σ(yi - ŷi)² --- 用得最多
均方根误差 RMSE = √MSE --- 与 y 同单位,更直观
平均绝对误差 MAE = (1/n) Σ|yi - ŷi| --- 对异常值不敏感
决定系数 R² = 1 - Σ(yi-ŷi)² / Σ(yi-ȳ)² --- 越接近 1 越好
1.4 数学本质
机器学习的数学本质可以浓缩为三句话:
① 模型定义 :假设一个函数族 f(x;θ)f(x; \theta)f(x;θ)
② 确定准则 :定义损失函数 L(y,f(x;θ))L(y, f(x;\theta))L(y,f(x;θ))
③ 模型求解 :找到使损失最小的参数 θ∗=argminθ∑L\theta^* = \arg\min_\theta \sum Lθ∗=argminθ∑L
1.4.1 模型定义
(1)模型 = 函数 + 参数
模型就是一个带参数的函数 ,它把输入 xxx 映射为输出 y^\hat{y}y^:
y^=f(x;θ)\hat{y} = f(x; \theta)y^=f(x;θ)
其中 θ\thetaθ 是参数(权重、偏置等),xxx 是特征向量。
(2)常见模型的函数形式举例
| 模型 | 函数形式 | 参数 θ\thetaθ |
|---|---|---|
| 线性回归 | y^=w1x1+w2x2+⋯+wnxn+b\hat{y} = w_1x_1 + w_2x_2 + \cdots + w_nx_n + by^=w1x1+w2x2+⋯+wnxn+b | wi,bw_i, bwi,b |
| 逻辑回归 | y^=σ(wTx+b)=11+e−(wTx+b)\hat{y} = \sigma(w^Tx + b) = \dfrac{1}{1+e^{-(w^Tx+b)}}y^=σ(wTx+b)=1+e−(wTx+b)1 | w,bw, bw,b |
| 决策树 | if-else 规则组合 | 树的结构与分裂点 |
| 神经网络 | y^=fL(⋯f2(f1(x;W1);W2)⋯ ;WL)\hat{y} = f_L(\cdots f_2(f_1(x;W_1);W_2)\cdots;W_L)y^=fL(⋯f2(f1(x;W1);W2)⋯;WL) | 所有权重矩阵 WlW_lWl、偏置 |
(3)假设空间(Hypothesis Space)
- 定义:模型所有可能函数的集合,记作 H\mathcal{H}H。
- 模型求解的过程,就是在假设空间 H\mathcal{H}H 中搜索最优函数 f∗f^*f∗。
- 假设空间越大 → 模型越复杂 → 越容易过拟合。
- 奥卡姆剃刀原则:在效果相当的情况下,优先选择简单的模型。
(4)线性模型的向量化表达(重点理解)
单个样本:
y^=wTx+b=∑i=1nwixi+b\hat{y} = w^Tx + b = \sum_{i=1}^{n} w_i x_i + by^=wTx+b=i=1∑nwixi+b
多个样本(矩阵形式,N 个样本,n 个特征):
X=x11⋯x1n⋮⋱⋮xN1⋯xNn∈RN×n,W=w1⋮wn∈Rn×1X = \begin{bmatrix} x_{11} & \cdots & x_{1n} \\ \vdots & \ddots & \vdots \\ x_{N1} & \cdots & x_{Nn} \end{bmatrix} \in \mathbb{R}^{N \times n}, \quad W = \begin{bmatrix} w_1 \\ \vdots \\ w_n \end{bmatrix} \in \mathbb{R}^{n \times 1}X= x11⋮xN1⋯⋱⋯x1n⋮xNn ∈RN×n,W= w1⋮wn ∈Rn×1
Y^=XW+b∈RN×1\hat{Y} = XW + b \in \mathbb{R}^{N \times 1}Y^=XW+b∈RN×1
这就是为什么后面要用 NumPy 的矩阵运算------向量化计算比 for 循环快几个数量级。
1.4.2 模型求解
模型求解 = 优化问题:定义损失函数 → 求让损失最小的参数。
(1)常用损失函数
| 任务 | 损失函数 | 公式 |
|---|---|---|
| 回归 | 均方误差(MSE) | L=1N∑(yi−y^i)2L = \dfrac{1}{N}\sum(y_i - \hat{y}_i)^2L=N1∑(yi−y^i)2 |
| 回归 | 平均绝对误差(MAE) | $L = \dfrac{1}{N}\sum |
| 分类 | 交叉熵损失(Cross-Entropy) | L=−1N∑yilogy\^i+(1−yi)log(1−y\^i)L = -\dfrac{1}{N}\sumy_i\\log\\hat{y}_i + (1-y_i)\\log(1-\\hat{y}_i)L=−N1∑yilogy\^i+(1−yi)log(1−y\^i) |
| 分类 | Hinge 损失(SVM) | L=max(0,1−y⋅y^)L = \max(0, 1 - y \cdot \hat{y})L=max(0,1−y⋅y^) |
| 0-1 损失 | 指示函数 | L=1(y≠y^)L = \mathbb{1}(y \neq \hat{y})L=1(y=y^)(不可导,理论用) |
(2)优化求解方法
① 解析解(正规方程) ------ 仅对凸问题(如线性回归):
θ∗=(XTX)−1XTY\theta^* = (X^TX)^{-1}X^T Yθ∗=(XTX)−1XTY
- 优点:一步到位;缺点:矩阵求逆复杂度 O(n3)O(n^3)O(n3),特征多时不可行。
② 梯度下降法(Gradient Descent) ------ 最通用、最重要:
核心思想:沿着梯度的反方向走一小步,重复直到收敛。
θt+1=θt−η∇θL(θt)\theta_{t+1} = \theta_t - \eta \nabla_\theta L(\theta_t)θt+1=θt−η∇θL(θt)
其中 η\etaη 为学习率,∇θL\nabla_\theta L∇θL 为损失函数对参数的梯度。
梯度下降的三种变体:
| 变体 | 每次更新使用的数据 | 特点 |
|---|---|---|
| 批量梯度下降(BGD) | 全部训练数据 | 稳定但慢,大数据集不可行 |
| 随机梯度下降(SGD) | 1 个样本 | 快但震荡 |
| 小批量(Mini-batch) | 一小批(如 32、64 个) | 实践中最常用 |
学习率 η\etaη 的影响(重点理解):
- η\etaη 太大 → 步子太大 → 震荡甚至发散,损失变大
- η\etaη 太小 → 步子太小 → 收敛极慢
- 常用技巧:学习率衰减、warmup、Adam/AdaGrad 等自适应优化器
③ 其他优化器(了解即可)
- 动量法(Momentum):积累历史梯度方向,减少震荡
- Adam:结合动量与自适应学习率,深度学习默认选择
- 牛顿法:用二阶导(Hessian 矩阵),收敛快但计算贵
(3)正则化(防止过拟合的核心手段)
在目标函数中加入对参数大小的惩罚:
J(θ)=L(θ)+λ⋅R(θ)J(\theta) = L(\theta) + \lambda \cdot R(\theta)J(θ)=L(θ)+λ⋅R(θ)
| 正则化 | 惩罚项 R(θ)R(\theta)R(θ) | 效果 |
|---|---|---|
| L1 正则(Lasso) | $\sum | \theta_i |
| L2 正则(Ridge) | ∑θi2\sum\theta_i^2∑θi2 | 使参数整体变小 → 防止过拟合,最常用 |
| 弹性网络 | L1 + L2 加权 | 结合两者优点 |
其他防过拟合方法:增加训练数据、Dropout(神经网络)、早停(Early Stopping)、交叉验证、数据增强、降低模型复杂度。
(4)模型求解完整流程示例(线性回归)
1. 假设模型:ŷ = w·x + b
2. 选损失函数:MSE = (1/N) Σ(yᵢ - w·xᵢ - b)²
3. 对 w、b 求偏导:
∂MSE/∂w = -(2/N) Σ xᵢ(yᵢ - ŷᵢ)
∂MSE/∂b = -(2/N) Σ (yᵢ - ŷᵢ)
4. 梯度下降迭代更新:
w ← w - η·∂MSE/∂w
b ← b - η·∂MSE/∂b
5. 当损失不再下降时停止 → 得到 w*, b*
6. 预测:ŷ_new = w*·x_new + b*
(5)数学本质总结
| 步骤 | 数学表述 | 说明 |
|---|---|---|
| 模型定义 | y^=f(x;θ), θ∈H\hat{y} = f(x;\theta),\ \theta \in \mathcal{H}y^=f(x;θ), θ∈H | 选定函数族 |
| 确定准则 | minθJ(θ)=1N∑L(yi,f(xi;θ))+λR(θ)\min_\theta J(\theta) = \dfrac{1}{N}\sum L(y_i, f(x_i;\theta)) + \lambda R(\theta)minθJ(θ)=N1∑L(yi,f(xi;θ))+λR(θ) | 定义目标函数 |
| 模型求解 | θ∗=argminθJ(θ)\theta^* = \arg\min_\theta J(\theta)θ∗=argminθJ(θ) | 解析解 / 梯度下降 |
| 模型评估 | 在测试集上计算指标 | Accuracy、MSE、F1 等 |
第二部分:Python 语言基础
2.1 Python 概述
Python 是什么:
- 一种解释型、面向对象、动态类型的高级编程语言。
- 语法简洁、接近英语,被称为"可执行的伪代码"。
- 由 Guido van Rossum 于 1991 年发布,目前主流版本为 Python 3.x(Python 2 已停止维护)。
为什么机器学习用 Python:
- 语法简单,上手快,适合快速实验。
- 生态丰富:NumPy、Pandas、Scikit-learn、PyTorch、TensorFlow 全在 Python 生态。
- 底层关键计算用 C/C++ 实现,速度不慢。
- 跨平台、开源、社区庞大。
Python 的特点:
- 缩进表示代码块 (不用花括号
{}),通常用 4 个空格。 - 动态类型:变量不用声明类型,赋什么值就是什么类型。
- 解释执行:逐行执行,无需编译。
- 丰富的标准库和第三方库。
开发环境: 推荐 Anaconda + Jupyter Notebook / PyCharm / VS Code。
2.2 基本语法
2.2.1 注释
python
# 这是单行注释
"""
这是多行注释(文档字符串)
可以写很多行
"""
# 快捷键:选中代码后 Ctrl+/ 可快速注释/取消注释
2.2.2 变量与命名规则
python
# 变量赋值:不需要声明类型
age = 18 # 整数
name = "小明" # 字符串
height = 1.75 # 浮点数
is_student = True # 布尔值
# 多重赋值
a = b = c = 0
x, y, z = 1, 2, 3
# 命名规则(强制):
# 1. 由字母、数字、下划线组成,不能以数字开头
# 2. 区分大小写(Name 与 name 是两个变量)
# 3. 不能使用 Python 关键字(如 if、for、class)
# 命名规范(建议):
# 变量名、函数名:小写+下划线 student_name
# 类名:驼峰式 StudentInfo
# 常量名:全大写 MAX_SIZE = 100
2.2.3 输入与输出
python
# 输出 print()
print("Hello, World!")
print("姓名:", "年龄:", 18) # 逗号分隔,默认空格连接
print("结果是", 3 + 5)
print(f"我叫{name},今年{age}岁") # f-string 格式化(推荐)
print("成绩: {:.2f}".format(95.678)) # 保留两位小数: 95.68
print("得分:%d,比例:%.1f%%" % (90, 88.5))
# 输入 input() ------ 返回值永远是字符串!
name = input("请输入姓名:")
age = int(input("请输入年龄:")) # 转成整数
score = float(input("请输入成绩:")) # 转成浮点数
格式化输出常用技巧:
python
a, b = 3, 4
print(f"{a} + {b} = {a + b}") # 3 + 4 = 7
print(f"{3.14159:.3f}") # 3.142 保留3位小数
print(f"{'hello':>10}") # 右对齐,宽度10
print(f"{255:#x}") # 0xff 十六进制
2.2.4 代码块与缩进
python
# Python 用缩进表示代码块(推荐 4 个空格)
if True:
print("这是 if 里的代码") # 必须缩进
print("同一层级")
print("这是 if 外的代码") # 缩进结束,回到外层
# 错误示例:缩进不一致会报 IndentationError
2.3 数据类型
2.3.1 基本数据类型总览
| 类型 | 关键字 | 示例 | 说明 |
|---|---|---|---|
| 整数 | int |
100, -5, 0xff |
无大小限制 |
| 浮点数 | float |
3.14, 1e5 |
有精度问题 |
| 布尔值 | bool |
True, False |
实质是 1 和 0 |
| 字符串 | str |
"hello", '世界' |
不可变序列 |
| 列表 | list |
[1, 2, 3] |
有序、可变 |
| 元组 | tuple |
(1, 2, 3) |
有序、不可变 |
| 字典 | dict |
{"name": "Tom"} |
键值对,无序 |
| 集合 | set |
{1, 2, 3} |
无序、不重复 |
| 空值 | NoneType |
None |
表示空 |
python
# 查看类型
x = 3.14
print(type(x)) # <class 'float'>
# 类型转换
int("123") # 123
float(5) # 5.0
str(100) # "100"
bool(0) # False
list("abc") # ['a', 'b', 'c']
2.3.2 字符串(重点)
python
s = "Hello, Python!"
# 1. 索引(从 0 开始)
print(s[0]) # H
print(s[-1]) # ! (倒数第一个)
# 2. 切片 s[start:stop:step] 含头不含尾
print(s[0:5]) # Hello
print(s[7:]) # Python!
print(s[::2]) # Hlo yhn 每隔一个取
print(s[::-1]) # !nohtyP ,olleH 反转字符串
# 3. 常用方法
print(len(s)) # 14 长度
print(s.lower()) # 全小写
print(s.upper()) # 全大写
print(s.replace("Python", "World"))
print(s.split(", ")) # ['Hello', 'Python!']
print("a-b-c".split("-")) # ['a', 'b', 'c']
print(" trim ".strip()) # 去两边空白 → "trim"
print(s.find("Python")) # 7 找到返回索引,找不到返回 -1
print(s.count("l")) # 2
print(s.startswith("Hello")) # True
print(s.endswith("!")) # True
print("Hello" in s) # True 成员判断
# 4. 字符串是不可变的!
# s[0] = "h" # 报错 TypeError
s = "h" + s[1:] # 想修改只能创建新字符串
2.3.3 列表 list(最常用,重点)
python
# 创建
nums = [1, 2, 3, 4, 5]
mixed = [1, "hello", 3.14, True, [1, 2]] # 可以混合类型
empty = []
# 索引与切片(同字符串)
print(nums[0]) # 1
print(nums[-1]) # 5
print(nums[1:4]) # [2, 3, 4]
# 增
nums.append(6) # 末尾加一个 → [1,2,3,4,5,6]
nums.insert(0, 0) # 指定位置插入 → [0,1,2,3,4,5,6]
nums.extend([7, 8]) # 合并另一个列表
# 删
nums.remove(0) # 删除第一个值为 0 的元素
last = nums.pop() # 弹出并返回末尾元素
nums.pop(0) # 弹出指定索引的元素
del nums[0] # 按索引删除
nums.clear() # 清空
# 改
nums = [1, 2, 3, 4, 5]
nums[0] = 100 # [100, 2, 3, 4, 5]
# 查
print(nums.index(3)) # 2 第一次出现的索引
print(nums.count(3)) # 1 出现次数
print(3 in nums) # True
# 排序
nums = [3, 1, 2]
nums.sort() # 原地升序 [1, 2, 3]
nums.sort(reverse=True) # 降序 [3, 2, 1]
new = sorted(nums) # 不修改原列表,返回新列表
# 其他常用
print(len(nums))
print(max(nums), min(nums), sum(nums))
print(list(range(1, 11))) # [1,2,...,10]
# 列表推导式(Python 精华,重点掌握!)
squares = [x**2 for x in range(1, 6)] # [1,4,9,16,25]
evens = [x for x in range(10) if x % 2 == 0] # [0,2,4,6,8]
2.3.4 元组 tuple
python
# 元组 = 不可变的列表,定义后不能修改
t = (1, 2, 3)
print(t[0]) # 1
print(len(t)) # 3
print(t.count(2)) # 1
print(t.index(3)) # 2
# 特殊情况
t1 = (5,) # 只有一个元素时必须加逗号!
t2 = (5) # 这是整数 5,不是元组
# 用途:函数返回多个值、作为字典的键、保护数据不被修改
def get_min_max(lst):
return min(lst), max(lst) # 返回元组
lo, hi = get_min_max([3, 1, 4, 1, 5])
2.3.5 字典 dict(重点)
python
# 字典 = 键值对(key: value),键必须唯一且不可变
student = {
"name": "小明",
"age": 18,
"scores": [90, 85, 92]
}
# 查
print(student["name"]) # 小明(键不存在会报错)
print(student.get("gender", "未知")) # 未知(键不存在返回默认值,不报错)
# 增 / 改
student["gender"] = "男" # 新增
student["age"] = 19 # 修改
# 删
del student["gender"]
student.pop("age")
student.clear()
# 遍历
for key in student:
print(key, student[key])
for key, value in student.items():
print(key, value)
for value in student.values():
print(value)
# 常用方法
print(student.keys()) # 所有键
print(student.values()) # 所有值
print("name" in student) # True 判断键是否存在
# 字典推导式
sq = {x: x**2 for x in range(1, 5)} # {1:1, 2:4, 3:9, 4:16}
2.3.6 集合 set
python
# 集合 = 无序、不重复的元素集合,支持数学集合运算
s = {1, 2, 3, 3, 2}
print(s) # {1, 2, 3} 自动去重
s.add(4) # 添加
s.remove(2) # 删除(不存在会报错)
s.discard(10) # 删除(不存在不报错)
a = {1, 2, 3}
b = {2, 3, 4}
print(a | b) # 并集 {1,2,3,4}
print(a & b) # 交集 {2,3}
print(a - b) # 差集 {1}
print(a ^ b) # 对称差集 {1,4}
# 去重的经典用法
names = ["Tom", "Jerry", "Tom", "Mike"]
print(list(set(names)))
2.4 运算符与表达式
2.4.1 常用运算符
| 类别 | 运算符 | 示例 | 结果 |
|---|---|---|---|
| 算术 | + - * / |
7 / 2 |
3.5(真除法) |
//(整除) |
7 // 2 |
3 |
|
%(取余) |
7 % 2 |
1 |
|
**(幂) |
2 ** 10 |
1024 |
|
| 比较 | == != > < >= <= |
3 == 3 |
True |
| 逻辑 | and or not |
True and False |
False |
| 赋值 | = += -= *= /= //= %= |
a += 1 等价 a = a + 1 |
|
| 成员 | in / not in |
2 in [1,2,3] |
True |
| 身份 | is / is not |
a is None |
判断是否同一对象 |
| 位运算 | `& | ^ ~ << >>` | 5 & 3 |
python
# 易错点 1:== 与 is 的区别
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b) # True 值相等
print(a is b) # False 不是同一个对象
# is 用于判断 None:if x is None:
# 易错点 2:浮点数精度
print(0.1 + 0.2) # 0.30000000000000004
print(abs(0.1 + 0.2 - 0.3) < 1e-9) # True 实际比较要用误差容忍
# 易错点 3:短路求值
# and:第一个为 False 就不看第二个
# or :第一个为 True 就不看第二个
# 链式比较(Python 特有)
x = 5
print(1 < x < 10) # True
2.4.2 运算符优先级(从高到低,了解即可)
** → +x -x ~x(正负、按位取反) → * / // % → + -
→ << >> → & → ^ → | → 比较运算符 → not → and → or
建议: 拿不准优先级时,用括号 ( ) 明确表达。
2.5 程序控制结构
2.5.1 顺序结构
代码从上到下依次执行,无分支无循环。
2.5.2 分支结构(if 语句)
python
# 基本形式
score = 85
if score >= 90:
print("优秀")
elif score >= 80:
print("良好") # 输出这个
elif score >= 60:
print("及格")
else:
print("不及格")
# 三元表达式(条件表达式)
x = 10
result = "正数" if x > 0 else "非正数"
# 嵌套 if(不建议嵌套太深,用 elif 替代)
2.5.3 循环结构
(1)for 循环 ------ 遍历可迭代对象
python
# 遍历列表
for fruit in ["苹果", "香蕉", "橘子"]:
print(fruit)
# 遍历 range
for i in range(5): # 0,1,2,3,4
print(i, end=" ")
for i in range(1, 11): # 1~10
print(i)
for i in range(0, 10, 2): # 0,2,4,6,8 步长为2
print(i)
# 遍历字符串
for ch in "hello":
print(ch)
# 遍历字典
info = {"a": 1, "b": 2}
for k, v in info.items():
print(k, v)
# 带索引遍历(实用!)
names = ["Tom", "Jerry", "Mike"]
for i, name in enumerate(names):
print(i, name) # 0 Tom / 1 Jerry / 2 Mike
# 并行遍历两个列表
scores = [90, 85, 88]
for name, score in zip(names, scores):
print(name, score)
(2)while 循环 ------ 条件成立就继续
python
# 求 1+2+...+100
total = 0
i = 1
while i <= 100:
total += i
i += 1
print(total) # 5050
# 经典用法:猜数字
import random
target = random.randint(1, 100)
while True:
guess = int(input("猜一个数:"))
if guess > target:
print("大了")
elif guess < target:
print("小了")
else:
print("猜对了!")
break
(3)循环控制语句
python
# break ------ 立即跳出整个循环
# continue ------ 跳过本次,进入下一轮
# else ------ 循环正常结束(没遇到 break)时执行
for i in range(5):
if i == 3:
continue # 跳过 3
if i == 4:
break # 遇到 4 终止
print(i) # 输出 0 1 2
# for-else 示例
for n in range(2, 10):
if 100 % n == 0:
print("100 能被", n, "整除")
break
else:
print("没有找到因子") # 没 break 时执行
2.5.4 嵌套循环
python
# 打印九九乘法表
for i in range(1, 10):
for j in range(1, i + 1):
print(f"{j}x{i}={i*j}", end="\t")
print()
2.6 函数
2.6.1 函数的定义与调用
python
# 定义函数
def greet(name):
"""向某人打招呼(这是文档字符串)"""
print(f"你好,{name}!")
# 调用
greet("小明") # 你好,小明!
# 带返回值的函数
def add(a, b):
return a + b
result = add(3, 5) # 8
# 返回多个值(实际返回的是元组)
def stats(numbers):
return min(numbers), max(numbers), sum(numbers)/len(numbers)
lo, hi, avg = stats([1, 2, 3, 4, 5])
# 无 return 或只有 return → 返回 None
2.6.2 参数类型(重点)
python
def func(a, b=10, *args, **kwargs):
print(f"a={a}, b={b}, args={args}, kwargs={kwargs}")
func(1) # a=1, b=10, args=(), kwargs={}
func(1, 2) # a=1, b=2
func(1, 2, 3, 4) # a=1, b=2, args=(3,4)
func(1, x=5, y=6) # a=1, b=10, kwargs={'x':5,'y':6}
| 参数类型 | 说明 | 示例 |
|---|---|---|
| 位置参数 | 按顺序一一对应 | def f(a, b) |
| 默认参数 | 有默认值,可不传 | def f(b=10) |
| 可变位置参数 | *args 收集成元组 |
f(1,2,3) → args=(1,2,3) |
| 可变关键字参数 | **kwargs 收集成字典 |
f(x=1) → kwargs={'x':1} |
| 关键字参数 | 按名字传参 | f(b=2, a=1) |
注意事项:
- 默认参数必须放在位置参数后面。
- 默认参数不要用可变对象 (如列表):
def f(lst=[])是经典坑。
2.6.3 变量作用域
python
x = 100 # 全局变量
def func():
x = 200 # 局部变量(只在函数内有效)
print(x) # 200
func()
print(x) # 100
# 在函数内修改全局变量要用 global
def func2():
global x
x = 999
func2()
print(x) # 999
# 作用域搜索顺序:局部 → 外层函数 → 全局 → 内置(LEGB 规则)
2.6.4 匿名函数 lambda
python
# lambda 参数: 表达式 ------ 适合简单的"一次性"函数
square = lambda x: x ** 2
print(square(5)) # 25
# 常与 sorted、map、filter 搭配
students = [("Tom", 90), ("Jerry", 85), ("Mike", 92)]
students.sort(key=lambda s: s[1], reverse=True)
print(students) # [('Mike',92), ('Tom',90), ('Jerry',85)]
# map:对每个元素应用函数
nums = [1, 2, 3, 4]
print(list(map(lambda x: x*2, nums))) # [2,4,6,8]
# filter:筛选元素
print(list(filter(lambda x: x % 2 == 0, nums))) # [2,4]
2.6.5 常用内置函数速查
| 函数 | 作用 | 示例 |
|---|---|---|
print() |
输出 | |
len() |
长度 | len([1,2,3]) → 3 |
type() |
查看类型 | |
int() float() str() list() |
类型转换 | |
range() |
生成整数序列 | range(1,5) |
enumerate() |
带索引遍历 | |
zip() |
并行遍历 | |
sorted() |
排序返回新列表 | |
max() min() sum() |
最大/最小/求和 | |
abs() |
绝对值 | |
round() |
四舍五入 | round(3.1415, 2) → 3.14 |
input() print() |
输入输出 | |
isinstance() |
判断类型 | isinstance(3, int) → True |
any() all() |
任一为真/全部为真 | |
id() |
对象内存地址 |
2.7 面向对象编程(OOP)
2.7.1 为什么需要面向对象
面向对象把"数据"和"操作数据的方法"打包成类(Class) ,适合描述复杂系统。核心思想:封装、继承、多态。
2.7.2 类与对象
python
# 定义类
class Student:
# 类属性(所有对象共享)
school = "清华大学"
# 初始化方法(构造函数),创建对象时自动调用
def __init__(self, name, age, score):
self.name = name # 实例属性
self.age = age
self.score = score
# 实例方法
def introduce(self):
print(f"我叫{self.name},{self.age}岁,成绩{self.score}")
# 魔术方法:定义打印行为
def __str__(self):
return f"Student({self.name}, {self.age}, {self.score})"
# 创建对象(实例化)
s1 = Student("小明", 18, 92)
s2 = Student("小红", 19, 88)
s1.introduce() # 我叫小明,18岁,成绩92
print(s1) # Student(小明, 18, 92) 自动调用 __str__
print(Student.school) # 清华大学
要点:
self代表对象本身,调用时不用手动传。__init__是构造方法,__str__定义print(obj)的输出。- 实例属性属于对象,类属性属于类。
2.7.3 封装(访问控制)
python
class Account:
def __init__(self, balance):
self.__balance = balance # 双下划线开头 = 私有属性,外部不能直接访问
def get_balance(self):
return self.__balance
def deposit(self, amount):
if amount > 0:
self.__balance += amount
acc = Account(1000)
# print(acc.__balance) # 报错 AttributeError
print(acc.get_balance()) # 1000
acc.deposit(500)
print(acc.get_balance()) # 1500
| 前缀 | 含义 | 可访问性 |
|---|---|---|
name |
公有 | 任意访问 |
_name |
约定为受保护 | 建议外部不访问(可访问) |
__name |
私有 | 外部不能直接访问 |
2.7.4 继承
python
# 父类(基类)
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
print(f"{self.name} 发出声音")
# 子类(派生类)继承父类
class Dog(Animal):
def speak(self): # 方法重写(Override)
print(f"{self.name} 汪汪叫")
class Cat(Animal):
def speak(self):
print(f"{self.name} 喵喵叫")
dog = Dog("旺财")
cat = Cat("咪咪")
dog.speak() # 旺财汪汪叫
cat.speak() # 咪咪喵喵叫
# super() 调用父类方法
class Puppy(Dog):
def __init__(self, name, age):
super().__init__(name) # 调用父类构造
self.age = age
# isinstance 判断继承关系
print(isinstance(dog, Animal)) # True
print(isinstance(dog, Dog)) # True
2.7.5 多态
python
# 同一方法,不同对象表现出不同行为
def animal_speak(animal):
animal.speak() # 传什么对象就调用什么对象的 speak
animal_speak(dog) # 旺财汪汪叫
animal_speak(cat) # 咪咪喵喵叫
OOP 三大特性总结:
- 封装:把数据和方法包在一起,隐藏细节。
- 继承:子类复用父类的代码。
- 多态:同一接口,不同实现。
2.7.6 常用魔术方法(了解)
python
class Vector:
def __init__(self, x, y):
self.x, self.y = x, y
def __add__(self, other): # 支持 v1 + v2
return Vector(self.x + other.x, self.y + other.y)
def __len__(self): # 支持 len(v)
return int((self.x**2 + self.y**2) ** 0.5)
def __eq__(self, other): # 支持 v1 == v2
return self.x == other.x and self.y == other.y
def __repr__(self):
return f"Vector({self.x}, {self.y})"
2.8 文件操作
2.8.1 文件的打开与关闭
python
# 基本语法:open(文件路径, 打开模式, 编码)
# 模式:'r' 只读(默认)'w' 写(覆盖)'a' 追加 'b' 二进制 'rb' 'wb'
# 推荐写法:with 语句(自动关闭文件)
with open("data.txt", "r", encoding="utf-8") as f:
content = f.read()
print(content)
# 不推荐写法(容易忘记 close)
f = open("data.txt", "r", encoding="utf-8")
content = f.read()
f.close()
打开模式表:
| 模式 | 说明 | 文件不存在时 |
|---|---|---|
r |
只读 | 报错 |
w |
写入(覆盖原有内容) | 自动创建 |
a |
追加 | 自动创建 |
rb/wb |
二进制读写(图片、模型文件) | |
r+ |
读写 | 报错 |
2.8.2 读文件
python
with open("data.txt", "r", encoding="utf-8") as f:
# 方式 1:一次性读全部
content = f.read()
with open("data.txt", "r", encoding="utf-8") as f:
# 方式 2:按行读成列表
lines = f.readlines() # ['第一行\n', '第二行\n']
with open("data.txt", "r", encoding="utf-8") as f:
# 方式 3:逐行读(大文件推荐,省内存)
for line in f:
print(line.strip()) # strip() 去掉换行符
2.8.3 写文件
python
# 覆盖写
with open("output.txt", "w", encoding="utf-8") as f:
f.write("第一行\n")
f.write("第二行\n")
f.writelines(["第三行\n", "第四行\n"])
# 追加写
with open("output.txt", "a", encoding="utf-8") as f:
f.write("追加的内容\n")
2.8.4 CSV 与 JSON 文件(机器学习中常用)
python
import csv
import json
# ---------- CSV ----------
# 写
with open("data.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow(["姓名", "年龄", "成绩"]) # 表头
writer.writerow(["小明", 18, 92])
writer.writerow(["小红", 19, 88])
# 读
with open("data.csv", "r", encoding="utf-8") as f:
reader = csv.reader(f)
header = next(reader) # 跳过表头
for row in reader:
print(row) # ['小明', '18', '92']
# ---------- JSON ----------
data = {
"name": "小明",
"scores": [90, 85, 92],
"info": {"age": 18, "city": "北京"}
}
# 写
with open("data.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
# 读
with open("data.json", "r", encoding="utf-8") as f:
loaded = json.load(f)
print(loaded["name"])
# 字符串与 JSON 互转
s = json.dumps(data, ensure_ascii=False) # dict → str
obj = json.loads(s) # str → dict
第三部分:机器学习常用库
3.1 科学计算库 NumPy
3.1.1 NumPy 简介
- NumPy(Numerical Python) 是 Python 科学计算的基础库,几乎所有数据科学库都依赖它。
- 核心对象:ndarray(N 维数组),比 Python 列表快 10~100 倍。
- 为什么快:底层 C 实现、连续内存 、向量化运算(免 for 循环)。
python
import numpy as np # 约定俗成的别名
3.1.2 创建 ndarray
python
import numpy as np
# 1. 从列表创建
a = np.array([1, 2, 3, 4, 5]) # 一维数组
b = np.array([[1, 2, 3], [4, 5, 6]]) # 二维数组(2行3列)
print(a) # [1 2 3 4 5]
print(b)
# [[1 2 3]
# [4 5 6]]
print(a.shape) # (5,) 形状
print(b.shape) # (2, 3) 2行3列
print(a.dtype) # int64 元素类型
print(b.ndim) # 2 维度
print(b.size) # 6 元素总数
# 2. 特殊数组
np.zeros((2, 3)) # 全0数组 2×3
np.ones((3, 3)) # 全1数组
np.full((2, 2), 7) # 全部填充 7
np.eye(3) # 3×3 单位矩阵
np.arange(0, 10, 2) # [0 2 4 6 8] 类似 range
np.linspace(0, 1, 5) # [0, 0.25, 0.5, 0.75, 1] 等距5个点
# 3. 随机数组(机器学习极常用!)
np.random.seed(42) # 设置随机种子,保证结果可复现
np.random.rand(3, 3) # [0,1) 均匀分布
np.random.randn(2, 3) # 标准正态分布
np.random.randint(0, 10, size=5) # [0,10) 随机整数
np.random.uniform(1, 10, 5) # [1,10) 均匀分布
np.random.choice([1, 2, 3, 4], 2) # 随机抽2个
3.1.3 索引与切片
python
a = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
print(a[0, 0]) # 1 第0行第0列
print(a[1]) # [4 5 6] 第1行
print(a[:, 0]) # [1 4 7] 第0列(所有行)
print(a[0:2, 1:3]) # [[2 3] [5 6]] 子矩阵
print(a[a > 5]) # [6 7 8 9] 布尔索引(重点!)
# 布尔索引实用场景:筛选数据
scores = np.array([85, 92, 78, 95, 60, 88])
print(scores[scores >= 80]) # [85 92 95 88]
print(scores[(scores >= 60) & (scores < 80)]) # [78 60] 注意用 & | ~
# 注意:切片是"视图",修改会影响原数组!
b = a[0:2, 0:2]
b[0, 0] = 999
print(a) # a[0,0] 也变成 999!
# 需要独立副本:c = a.copy()
3.1.4 数组运算(重点:向量化)
python
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print(a + b) # [5 7 9] 逐元素相加(不用写循环!)
print(a - b) # [-3 -3 -3]
print(a * b) # [4 10 18] 逐元素相乘(不是矩阵乘!)
print(a / b) # [0.25 0.4 0.5]
print(a ** 2) # [1 4 9]
print(a * 2 + 1) # [3 5 7] 标量广播
print(np.sqrt(a)) # [1. 1.414 1.732]
print(np.exp(a)) # e 的幂
print(np.log(a)) # 自然对数
# 矩阵乘法(线性代数意义下的乘法)
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
print(A @ B) # 矩阵乘(推荐写法)
print(np.dot(A, B)) # 同上
# 转置
print(A.T)
广播机制(Broadcasting)------自动扩展形状不同的数组:
python
a = np.array([[1], [2], [3]]) # 形状 (3,1)
b = np.array([10, 20, 30]) # 形状 (3,)
print(a + b) # 自动广播成 (3,3)
# [[11 21 31]
# [12 22 32]
# [13 23 33]]
3.1.5 常用统计与变形
python
a = np.array([[1, 2, 3], [4, 5, 6]])
# 统计
print(a.sum()) # 21
print(a.sum(axis=0)) # [5 7 9] 按列求和
print(a.sum(axis=1)) # [6 15] 按行求和
print(a.mean()) # 3.5
print(a.mean(axis=0)) # [2.5 3.5 4.5] 按列均值
print(a.std(), a.var()) # 标准差、方差
print(a.max(), a.min())
print(a.max(axis=1)) # [3 6] 每行最大值
print(np.argmax(a)) # 5 最大值的索引(展平后)
print(np.median(a)) # 中位数
# 变形
print(a.reshape(3, 2)) # 变形为 3×2(元素总数要一致)
print(a.flatten()) # 展平成一维 [1 2 3 4 5 6]
print(a.T) # 转置
# 拼接
c = np.array([[7, 8, 9]])
print(np.vstack([a, c])) # 纵向拼接(加行)
print(np.hstack([a, a])) # 横向拼接(加列)
# 其他
print(np.unique([1, 2, 2, 3, 3, 3])) # 去重排序 [1 2 3]
print(np.sort(a)) # 排序
print(np.where(a > 3, 1, 0)) # 条件取值:>3 取1 否则0
3.1.6 NumPy 与 Python 列表对比
| 对比项 | Python 列表 | NumPy 数组 |
|---|---|---|
| 速度 | 慢 | 快(C 实现 + 向量化) |
| 内存 | 大(存指针) | 小(连续内存) |
| 运算 | [1,2]+[3,4]=[1,2,3,4] 拼接 |
[1,2]+[3,4]=[4,6] 逐元素相加 |
| 便利性 | 一般 | 支持矩阵、广播、统计 |
口诀: 机器学习中一切数值计算都优先用 NumPy;能向量化就别写 for 循环。
3.2 机器学习库 Scikit-learn
3.2.1 Scikit-learn 简介
- Scikit-learn(sklearn) 是 Python 最流行的传统机器学习库。
- 特点:接口统一、文档完善、算法齐全,适合入门和实际项目。
- 官网:https://scikit-learn.org
主要模块:
| 模块 | 功能 | 代表算法 |
|---|---|---|
sklearn.linear_model |
线性模型 | 线性回归、逻辑回归、Ridge、Lasso |
sklearn.tree |
决策树 | DecisionTreeClassifier/Regressor |
sklearn.ensemble |
集成学习 | 随机森林、GBDT、XGBoost(需另装) |
sklearn.svm |
支持向量机 | SVC、SVR |
sklearn.neighbors |
近邻算法 | KNN |
sklearn.cluster |
聚类 | K-Means、DBSCAN |
sklearn.decomposition |
降维 | PCA |
sklearn.preprocessing |
数据预处理 | 标准化、归一化、编码 |
sklearn.model_selection |
模型选择 | train_test_split、交叉验证、网格搜索 |
sklearn.metrics |
评估指标 | accuracy、f1、MSE、混淆矩阵 |
sklearn.datasets |
数据集 | 内置玩具数据集、生成数据 |
3.2.2 sklearn 的统一 API(必背!)
sklearn 所有模型都遵循同一套使用模式,学会一个就等于学会所有:
python
from sklearn.xxx import SomeModel
# 1. 创建模型(实例化,设置超参数)
model = SomeModel(hyperparam1=value1, ...)
# 2. 训练(拟合)
model.fit(X_train, y_train)
# 3. 预测
y_pred = model.predict(X_test)
# 4. 评估
score = model.score(X_test, y_test)
三大类对象:
- Estimator(估计器) :所有模型,都有
fit()方法。 - Transformer(转换器) :数据预处理,有
fit()+transform()(或fit_transform())。 - Predictor(预测器) :有
predict()方法,用于预测。
3.2.3 完整示例:鸢尾花分类
python
# ===== 完整的机器学习流程 =====
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score, classification_report
# 1. 加载数据
iris = load_iris()
X = iris.data # 特征矩阵 (150, 4)
y = iris.target # 标签 (150,)
# 2. 划分训练集和测试集(70%训练,30%测试)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42, stratify=y
)
# 3. 数据预处理(标准化)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train) # 只用训练集fit!
X_test = scaler.transform(X_test) # 测试集只transform
# 4. 创建并训练模型
model = KNeighborsClassifier(n_neighbors=5)
model.fit(X_train, y_train)
# 5. 预测
y_pred = model.predict(X_test)
# 6. 评估
print("准确率:", accuracy_score(y_test, y_pred))
print(classification_report(y_test, y_pred, target_names=iris.target_names))
3.2.4 常用模型速查
python
# 回归
from sklearn.linear_model import LinearRegression, Ridge, Lasso
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
from sklearn.svm import SVR
# 分类
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
# 聚类
from sklearn.cluster import KMeans
# 降维
from sklearn.decomposition import PCA
3.2.5 模型保存与加载
python
import joblib
# 保存模型
joblib.dump(model, "model.pkl")
# 加载模型
loaded_model = joblib.load("model.pkl")
print(loaded_model.predict(X_test))
3.2.6 常见坑(重要提醒)
- 数据泄露(Data Leakage) :
StandardScaler只能用训练集fit,测试集只能transform。 - 测试集绝不能参与训练 :
fit只对X_train。 - random_state 固定:保证实验可复现。
- 类别不均衡 :用
class_weight='balanced'或过采样。 - 特征量纲差异大:使用 StandardScaler / MinMaxScaler 标准化。
3.3 绘图库 Matplotlib
3.3.1 Matplotlib 简介
- Matplotlib 是 Python 最基础的绑图库,能绘制出版级图表。
- 核心模块:
matplotlib.pyplot(约定别名plt)。 - 支持:折线图、散点图、柱状图、直方图、饼图、箱线图、热力图等。
python
import matplotlib.pyplot as plt
import numpy as np
# 中文显示问题的解决(常见坑!)
plt.rcParams["font.sans-serif"] = ["SimHei"] # 用黑体显示中文
plt.rcParams["axes.unicode_minus"] = False # 解决负号 '-' 显示问题
3.3.2 折线图(最常用)
python
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2 * np.pi, 100)
y1 = np.sin(x)
y2 = np.cos(x)
plt.figure(figsize=(10, 6)) # 设置画布大小
plt.plot(x, y1, label="sin(x)", color="blue", linewidth=2, linestyle="-")
plt.plot(x, y2, label="cos(x)", color="red", linewidth=2, linestyle="--")
plt.title("正弦与余弦函数", fontsize=16) # 标题
plt.xlabel("x", fontsize=12) # x 轴标签
plt.ylabel("y", fontsize=12) # y 轴标签
plt.legend(fontsize=12) # 显示图例
plt.grid(True, linestyle=":", alpha=0.6) # 网格
plt.xlim(0, 2 * np.pi) # x 轴范围
plt.ylim(-1.2, 1.2) # y 轴范围
plt.tight_layout() # 自动调整布局
plt.savefig("sine_cosine.png", dpi=150) # 保存图片(dpi 越大越清晰)
plt.show() # 显示图片
3.3.3 常用图形
python
fig, axes = plt.subplots(2, 2, figsize=(12, 10)) # 2×2 子图
# (1) 散点图 ------ 观察两变量关系
rng = np.random.default_rng(0)
x = rng.normal(50, 10, 100)
y = 2 * x + rng.normal(0, 20, 100)
axes[0, 0].scatter(x, y, c="steelblue", alpha=0.6, edgecolors="k")
axes[0, 0].set_title("散点图")
# (2) 柱状图 ------ 比较分类数据
names = ["Python", "Java", "C++", "Go"]
values = [85, 70, 60, 45]
axes[0, 1].bar(names, values, color=["#e4572e", "#2e86ab", "#f3a712", "#6a994e"])
axes[0, 1].set_title("语言流行度")
# (3) 直方图 ------ 观察数据分布
data = rng.normal(0, 1, 1000)
axes[1, 0].hist(data, bins=30, color="steelblue", edgecolor="white", density=True)
axes[1, 0].set_title("正态分布直方图")
# (4) 饼图 ------ 展示占比
sizes = [35, 30, 20, 15]
axes[1, 1].pie(sizes, labels=names, autopct="%1.1f%%", startangle=90)
axes[1, 1].set_title("市场份额")
plt.tight_layout()
plt.savefig("charts.png", dpi=150)
plt.show()
3.3.4 常用图形适用场景(速查)
| 图形 | 适用场景 | 函数 |
|---|---|---|
| 折线图 | 趋势变化(时间序列) | plt.plot() |
| 散点图 | 两变量相关性 | plt.scatter() |
| 柱状图 | 分类数据比较 | plt.bar() |
| 直方图 | 数据分布 | plt.hist() |
| 饼图 | 占比构成 | plt.pie() |
| 箱线图 | 分布与异常值 | plt.boxplot() |
| 热力图 | 矩阵/相关系数 | plt.imshow() |
3.3.5 常用参数速查
python
# 颜色:'r'红 'g'绿 'b'蓝 'k'黑 'y'黄,或十六进制 '#1f77b4'
# 线型:'-'实线 '--'虚线 '-.'点划线 ':'点线
# 标记:'o'圆点 's'方块 '^'三角 '*'星形 'x'叉
plt.plot(x, y, 'r--o') # 红色虚线 + 圆点标记
# 关键函数
plt.figure(figsize=(w, h)) # 创建画布
plt.subplot(2, 2, 1) # 2行2列第1个子图
plt.title() / plt.xlabel() / plt.ylabel()
plt.legend() # 图例
plt.grid() # 网格
plt.xlim() / plt.ylim() # 轴范围
plt.savefig("name.png") # 保存
plt.show() # 显示(Jupyter 中可省略)
3.4 图像处理库 PIL 与 Torchvision
3.4.1 PIL(Pillow)简介
- PIL(Python Imaging Library) 的现代分支叫 Pillow (安装命令:
pip install pillow)。 - 用于图像的打开、保存、裁剪、缩放、旋转、滤镜、格式转换等。
import PIL中统一用from PIL import Image。
python
from PIL import Image
# 1. 打开与显示图像
img = Image.open("cat.jpg")
print(img.size) # (宽, 高) 如 (800, 600)
print(img.mode) # 'RGB'、'L'(灰度)、'RGBA'(带透明通道)
img.show() # 系统默认看图器打开
# 2. 保存图像(可转换格式)
img.save("cat.png") # jpg → png
img.save("cat.jpg", quality=95) # 控制 jpg 质量(1-95)
3.4.2 PIL 常用图像操作
python
from PIL import Image, ImageFilter, ImageEnhance
img = Image.open("cat.jpg")
# ---- 几何变换 ----
resized = img.resize((224, 224)) # 缩放到 224×224
cropped = img.crop((100, 100, 400, 400)) # 裁剪 (left, upper, right, lower)
rotated = img.rotate(45, expand=True) # 旋转45度
flipped_h = img.transpose(Image.FLIP_LEFT_RIGHT) # 水平翻转
flipped_v = img.transpose(Image.FLIP_TOP_BOTTOM) # 垂直翻转
# ---- 颜色转换 ----
gray = img.convert("L") # 转灰度图
rgba = img.convert("RGBA") # 转带透明通道
rgb = rgba.convert("RGB")
# ---- 滤镜与增强 ----
blurred = img.filter(ImageFilter.GaussianBlur(radius=3)) # 高斯模糊
sharpened = img.filter(ImageFilter.SHARPEN) # 锐化
edges = img.filter(ImageFilter.FIND_EDGES) # 边缘检测
enhancer = ImageEnhance.Brightness(img)
bright = enhancer.enhance(1.5) # 亮度提升 1.5 倍
contrast = ImageEnhance.Contrast(img).enhance(1.2) # 对比度
# ---- 像素级操作 ----
import numpy as np
arr = np.array(img) # PIL Image → NumPy 数组 (H, W, 3)
print(arr.shape, arr.dtype) # (600, 800, 3) uint8
img_back = Image.fromarray(arr) # NumPy 数组 → PIL Image
# ---- 新建与粘贴 ----
canvas = Image.new("RGB", (300, 200), color=(255, 255, 255)) # 新建白色画布
canvas.paste(resized, (10, 10)) # 粘贴图像
canvas.save("result.jpg")
3.4.3 Torchvision 简介
- Torchvision 是 PyTorch 生态中处理图像的库,与
torch配合使用。 - 主要内容:数据集(datasets)、模型(models)、图像变换(transforms)、工具(utils)。
- 安装:
pip install torch torchvision。
python
import torch
from torchvision import datasets, transforms, models
from torch.utils.data import DataLoader
3.4.4 Torchvision 常用模块
(1)transforms ------ 图像预处理与数据增强(重点)
python
from torchvision import transforms
# 常用预处理流程
transform = transforms.Compose([
transforms.Resize((224, 224)), # 缩放
transforms.RandomHorizontalFlip(p=0.5), # 50% 概率水平翻转(数据增强)
transforms.RandomRotation(15), # 随机旋转 ±15 度
transforms.ColorJitter(brightness=0.2, contrast=0.2), # 颜色抖动
transforms.ToTensor(), # 转成 Tensor,并归一化到 [0,1]
transforms.Normalize(mean=[0.485, 0.456, 0.406], # ImageNet 均值
std=[0.229, 0.224, 0.225]) # ImageNet 标准差
])
# 常用 transforms 速查:
# Resize(size) 缩放
# CenterCrop(size) 中心裁剪
# RandomCrop(size) 随机裁剪
# RandomHorizontalFlip() 水平翻转
# RandomVerticalFlip() 垂直翻转
# Grayscale(num_channels) 转灰度
# ToTensor() PIL/ndarray → FloatTensor [C,H,W],像素值归一到 [0,1]
# ToPILImage() Tensor → PIL Image
# Normalize(mean, std) 标准化:(x - mean) / std
ToTensor() 的关键变化(面试常问):
- 输入:PIL Image,形状
(H, W, C),像素值0~255的 uint8 - 输出:Tensor,形状
(C, H, W)(通道维提前!),像素值0~1的 float32
(2)datasets ------ 内置数据集
python
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))
])
# MNIST 手写数字数据集(自动下载)
train_dataset = datasets.MNIST(
root="./data", # 存放路径
train=True, # 训练集
download=True, # 没有就下载
transform=transform # 预处理
)
test_dataset = datasets.MNIST(root="./data", train=False, transform=transform)
# DataLoader:按批次(batch)加载数据(深度学习必需)
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)
# 遍历一个批次
for images, labels in train_loader:
print(images.shape) # torch.Size([64, 1, 28, 28]) → batch=64, 通道=1
print(labels.shape) # torch.Size([64])
break
其他常用数据集: datasets.CIFAR10、datasets.CIFAR100、datasets.ImageFolder(自定义图片文件夹)。
(3)models ------ 预训练模型(迁移学习)
python
from torchvision import models
# 加载预训练的 ResNet18(ImageNet 训练好的权重)
model = models.resnet18(pretrained=True)
# 冻结所有参数(迁移学习常用)
for param in model.parameters():
param.requires_grad = False
# 替换最后一层,适配自己的分类任务(如 10 类)
import torch.nn as nn
model.fc = nn.Linear(model.fc.in_features, 10)
# 其他常用模型:
# models.resnet50() models.vgg16() models.mobilenet_v2()
# models.alexnet() models.densenet121() models.efficientnet_b0()
(4)utils ------ 图像可视化工具
python
from torchvision.utils import make_grid, save_image
import matplotlib.pyplot as plt
import numpy as np
# 取一个批次的图像拼成网格
images, _ = next(iter(train_loader))
grid = make_grid(images, nrow=8, normalize=True)
# 转成 numpy 显示
img = grid.permute(1, 2, 0).numpy() # (C,H,W) → (H,W,C)
plt.imshow(img)
plt.axis("off")
plt.show()
# 保存图像网格
save_image(images, "grid.png", nrow=8, normalize=True)
3.4.5 PIL 与 Torchvision 对比总结
| 对比项 | PIL (Pillow) | Torchvision |
|---|---|---|
| 定位 | 通用图像处理 | PyTorch 深度学习图像处理 |
| 核心对象 | PIL.Image |
torch.Tensor |
| 典型用途 | 裁剪、缩放、格式转换、滤镜 | 数据增强、构建数据集、加载预训练模型 |
| 与 NumPy | np.array(img) 互转 |
ToTensor() / ToPILImage() 互转 |
| 与深度学习 | 单张图像处理 | DataLoader 批量加载 + GPU 训练 |
典型工作流:
磁盘图片 → PIL.Image 打开 → torchvision.transforms 处理 → Tensor → 模型训练
python
from PIL import Image
from torchvision import transforms
img = Image.open("cat.jpg").convert("RGB")
transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
tensor = transform(img)
print(tensor.shape) # torch.Size([3, 224, 224])
附录 A:本章核心知识速查表
| 主题 | 必记要点 |
|---|---|
| 机器学习定义 | 任务 T + 性能 P + 经验 E,从数据学规律 |
| 学习类型 | 监督(有标签)/ 无监督(无标签)/ 强化(奖励) |
| 数据集划分 | 训练集 / 验证集 / 测试集;k 折交叉验证 |
| 过拟合 | 训练好测试差 → 加数据、正则化、简化模型 |
| 欠拟合 | 训练都拟合不好 → 加特征、加复杂度 |
| 评估指标 | 分类:Accuracy/Precision/Recall/F1;回归:MSE/RMSE/R² |
| 数学本质 | 选函数族 → 定损失函数 → 求 argmin(梯度下降) |
| Python 基础 | 缩进定层级、动态类型、f-string、列表/字典 |
| NumPy | ndarray、向量化、广播、shape/dtype、布尔索引 |
| Scikit-learn | fit / predict / score 三部曲;train_test_split |
| Matplotlib | plot/scatter/bar/hist;中文用 SimHei;savefig 保存 |
| PIL | Image.open/resize/crop/convert/save;np.array 互转 |
| Torchvision | transforms / datasets / models;ToTensor() 形状 (C,H,W) |
附录 B:常见易错点清单
input()返回的是字符串 ,比较数字前要int()/float()转换。- 列表切片含头不含尾 :
[1,2,3][0:2]→[1,2]。 - 字符串和元组不可变 ,列表、字典可变。
==比较值,is比较身份(判断 None 用is)。- 默认参数不要用
[](可变对象会共享)。 - 浮点数比较要留误差:
abs(a-b) < 1e-9。 - sklearn 预处理只用训练集
fit,防止数据泄露。 - NumPy 切片是视图 不是副本,需要副本用
.copy()。 - Matplotlib 中文乱码 → 设置
SimHei字体。 ToTensor()会把(H,W,C)变成(C,H,W)并归一化到[0,1]。
学习建议: 先把 Python 基础语法和 NumPy 练熟(动手敲代码),再通过 sklearn 走一遍完整的"加载数据 → 预处理 → 训练 → 评估"流程,最后用 Matplotlib 把结果画出来。机器学习是实践学科,看十遍不如敲一遍。