机器学习教程,从入门到精通,机器学习概述 + Python 语言基础 · 知识点详解(1)

机器学习概述 + 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 发展趋势
  1. 大模型与预训练:一个超大模型在海量数据上预训练,再适配到各种下游任务(如 BERT、GPT)。
  2. 多模态融合:同时处理文本、图像、语音、视频。
  3. AutoML(自动化机器学习):自动选择模型、调参,降低使用门槛。
  4. 可解释性 AI(XAI):让"黑箱"模型的决策可理解、可追溯。
  5. 边缘计算与模型轻量化:把模型部署到手机、IoT 设备上。
  6. 小样本/零样本学习:用极少的数据学会新任务。
  7. 隐私保护与联邦学习:数据不出本地,多方协同训练。
  8. 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;θ))

③ 模型求解 :找到使损失最小的参数 θ∗=arg⁡min⁡θ∑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∑yilog⁡y\^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(θ) 定义目标函数
模型求解 θ∗=arg⁡min⁡θ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:

  1. 语法简单,上手快,适合快速实验。
  2. 生态丰富:NumPy、Pandas、Scikit-learn、PyTorch、TensorFlow 全在 Python 生态。
  3. 底层关键计算用 C/C++ 实现,速度不慢。
  4. 跨平台、开源、社区庞大。

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 常见坑(重要提醒)
  1. 数据泄露(Data Leakage) :StandardScaler 只能用训练集 fit,测试集只能 transform。
  2. 测试集绝不能参与训练 :fit 只对 X_train。
  3. random_state 固定:保证实验可复现。
  4. 类别不均衡 :用 class_weight='balanced' 或过采样。
  5. 特征量纲差异大:使用 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:常见易错点清单

  1. input() 返回的是字符串 ,比较数字前要 int()/float() 转换。
  2. 列表切片含头不含尾 :[1,2,3][0:2] → [1,2]。
  3. 字符串和元组不可变 ,列表、字典可变。
  4. == 比较值,is 比较身份(判断 None 用 is)。
  5. 默认参数不要用 [](可变对象会共享)。
  6. 浮点数比较要留误差:abs(a-b) < 1e-9。
  7. sklearn 预处理只用训练集 fit,防止数据泄露。
  8. NumPy 切片是视图 不是副本,需要副本用 .copy()。
  9. Matplotlib 中文乱码 → 设置 SimHei 字体。
  10. ToTensor() 会把 (H,W,C) 变成 (C,H,W) 并归一化到 [0,1]。

学习建议: 先把 Python 基础语法和 NumPy 练熟(动手敲代码),再通过 sklearn 走一遍完整的"加载数据 → 预处理 → 训练 → 评估"流程,最后用 Matplotlib 把结果画出来。机器学习是实践学科,看十遍不如敲一遍。

相关推荐
程序员清风1 小时前
Claude Code 新手快速上手指南
人工智能·程序人生·ai
FII工业富联科技服务1 小时前
服务器开始按柜交付 数据中心需要具备怎样的承接能力
大数据·运维·服务器·人工智能·自动化·制造
ndsc_d1 小时前
AI生成UI如何兼顾电脑端和手机端?一份需求检查布局、组件与页面状态
人工智能·智能手机·电脑
博谷1 小时前
什么是GEO监测?核心指标、工作原理与AI搜索诊断监测全解析
人工智能·机器学习·自然语言处理
郝学胜-神的一滴1 小时前
AI 编程智能体 16:从零基础搭建到精细化优化
人工智能·python·算法·语言模型·langchain·pip
等一个人的@1 小时前
数睿通2.0更新:新增高质量数据集模块,UI全面调整优化
大数据·人工智能
喜欢打篮球的普通人1 小时前
AI 编译器内存分配算法:从静态/动态划分到内存复用
人工智能·算法
又蓝1 小时前
【元宝搜索开发者征文大赛】用 FastAPI + Vue3 做了个 AI 炒股工具,接了六个分析师和腾讯元宝搜索
人工智能·python·ai·fastapi
2601_966949651 小时前
为什么不应该把 QuantDash API Key 直接写进公开代码仓库?从 Git 提交历史理解凭证泄露风险
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash