机器学习教程
机器学习(Machine Learning)是人工智能的核心分支:让计算机从数据中自动学习规律,而不需要显式编程。它已广泛应用于推荐系统、图像识别、语音助手、风控等场景。
学习本教程你将掌握
| 模块 | 内容 |
|---|---|
| 基础概念 | 模型、特征、标签、训练/测试 |
| 经典算法 | 线性回归、决策树、SVM、KNN、聚类 |
| 模型评估 | 准确率、精确率、交叉验证 |
| 实践项目 | 房价预测、客户分群、泰坦尼克预测 |
机器学习简介
机器学习(Machine Learning, ML)指通过算法让计算机从数据中学习规律并进行预测或决策。传统编程是人写规则,机器学习是数据 + 算法 → 自动产生规则。
与传统编程的区别
| 传统编程 | 机器学习 |
|---|---|
| 人工定义规则 | 算法自动学习规则 |
| 输入数据 + 规则 → 输出 | 输入数据 + 输出 → 学习规则 |
| 规则固定 | 规则随数据更新 |
# 传统编程:手写规则
def is_spam(msg):
return '中奖' in msg or '点击链接' in msg
# 机器学习:从标注数据学习
from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier()
model.fit(X_train, y_train) # 自动学习
pred = model.predict(X_test)三大类型
| 类型 | 任务 | 示例 |
|---|---|---|
| 监督学习 | 有标签数据 | 分类、回归 |
| 无监督学习 | 无标签数据 | 聚类、降维 |
| 强化学习 | 试错 + 奖励 | 游戏、机器人控制 |
机器学习学习路线
学习机器学习建议按以下路线循序渐进,先重实践、后深理论:
| 阶段 | 内容 | 目标 |
|---|---|---|
| 1. 语言基础 | Python + NumPy + Pandas | 能处理数据 |
| 2. 可视化 | Matplotlib + Seaborn | 能看懂数据 |
| 3. 经典算法 | 回归/分类/聚类/降维 | 掌握 sklearn |
| 4. 模型评估 | 交叉验证/指标/调参 | 能评估模型 |
| 5. 实践项目 | Kaggle 入门竞赛 | 完整流程 |
| 6. 深度学习 | 神经网络/PyTorch | 进阶方向 |
机器学习生命周期
一个完整的机器学习项目遵循生命周期(ML Lifecycle):
| 阶段 | 关键工作 |
|---|---|
| 1. 问题定义 | 明确业务目标与成功指标 |
| 2. 数据收集 | 采集、标注、整合数据 |
| 3. 数据清洗 | 缺失值、重复值、异常值 |
| 4. 特征工程 | 构造、选择、缩放特征 |
| 5. 建模 | 选择算法并训练 |
| 6. 评估 | 交叉验证、指标分析 |
| 7. 部署监控 | 上线、监控、迭代 |
机器学习如何工作
机器学习如何工作?用一个简单例子理解核心机制——线性回归:
import numpy as np
import matplotlib.pyplot as plt
# 数据:房屋面积 -> 价格
X = np.array([50, 60, 70, 80, 90, 100]) # 面积(m²)
y = np.array([150, 180, 210, 240, 270, 300]) # 价格(万)
# 训练线性模型:y = w*x + b
from sklearn.linear_model import LinearRegression
model = LinearRegression()
model.fit(X.reshape(-1, 1), y)
# 预测 75m² 的价格
print(model.predict([[75]])) # ~225 万
# 学习到的参数
print(model.coef_, model.intercept_) # w≈3, b≈0核心思想:模型先随机猜测 w、b,通过损失函数衡量预测误差,再用梯度下降反复调整参数,直到误差最小。
机器学习基础术语
机器学习的基础术语必须清晰:
| 术语 | 含义 | 示例 |
|---|---|---|
| 样本(Sample) | 一条数据 | 一个用户、一笔订单 |
| 特征(Feature) | 输入变量 | 年龄、收入、地区 |
| 标签(Label) | 要预测的目标 | 是否购买、房价 |
| 训练集 | 用于学习的样本 | 80% 数据 |
| 测试集 | 用于评估的样本 | 20% 数据 |
| 模型(Model) | 学习到的函数 | f(x) → y |
| 过拟合 | 学得太死,泛化差 | 训练好测试差 |
| 欠拟合 | 没学好 | 训练测试都差 |
Python 入门机器学习
用 Python 入门机器学习,环境准备三步:
# 1. 安装核心库
pip install numpy pandas scikit-learn matplotlib seaborn
# 2. 验证环境
python -c "import sklearn; print(sklearn.__version__)"# 3. 一个最小可运行示例
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
# 加载鸢尾花数据集
iris = load_iris()
X, y = iris.data, iris.target
# 划分训练/测试集
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42)
# 训练决策树
model = DecisionTreeClassifier()
model.fit(X_train, y_train)
# 评估
print('准确率:', model.score(X_test, y_test))Python 机器学习库
Python 机器学习生态核心库:
| 库 | 用途 |
|---|---|
| NumPy | 数值计算、数组 |
| Pandas | 数据处理、表格 |
| Matplotlib | 绘图可视化 |
| Seaborn | 统计可视化(更美观) |
| Scikit-learn | 经典机器学习算法(主力) |
| PyTorch / TensorFlow | 深度学习 |
| XGBoost / LightGBM | 梯度提升树(竞赛利器) |
常用数据类型
机器学习中常用的数据表示:
import numpy as np
import pandas as pd
# 特征矩阵 X:二维数组(样本 × 特征)
X = np.array([
[25, 5000], # 年龄, 收入
[30, 8000],
[35, 10000]
])
# 标签向量 y:一维数组
y = np.array([0, 1, 1]) # 0 否 1 是
# 更常用:Pandas DataFrame
df = pd.DataFrame(X, columns=['age', 'income'])
df['buy'] = y
print(df)
# 提取特征与标签
X = df[['age', 'income']].values
y = df['buy'].values机器学习应用
机器学习在各行业的典型应用:
| 领域 | 应用 | 算法 |
|---|---|---|
| 电商 | 推荐系统、销量预测 | 协同过滤、回归 |
| 金融 | 信用评分、反欺诈 | 逻辑回归、XGBoost |
| 医疗 | 疾病诊断、影像识别 | CNN、决策树 |
| 制造 | 设备故障预测 | 异常检测 |
| 自动驾驶 | 目标检测、路径规划 | 深度学习 |
| NLP | 翻译、客服机器人 | Transformer |
数据理解
数据理解(EDA)是建模前的必修课,目标是把数据"看透":
import pandas as pd
df = pd.read_csv('data.csv')
# 1. 整体概览
df.info() # 列类型、缺失
df.describe() # 数值分布
df.shape # 规模
# 2. 缺失值
df.isnull().sum()
# 3. 目标变量分布
df['label'].value_counts()
df['label'].value_counts(normalize=True) # 占比
# 4. 特征分布(直方图)
df.hist(bins=30, figsize=(12, 8))
# 5. 相关性
df.corr()['label'].sort_values(ascending=False)数据清洗
数据清洗决定模型上限:
import pandas as pd
df = pd.read_csv('raw.csv')
# 1. 缺失值
df['age'].fillna(df['age'].median(), inplace=True)
df.dropna(subset=['label'], inplace=True) # 标签不能缺
# 2. 重复值
df.drop_duplicates(inplace=True)
# 3. 异常值(箱线图法:超出 1.5 倍 IQR)
q1, q3 = df['amount'].quantile([0.25, 0.75])
iqr = q3 - q1
df = df[(df['amount'] >= q1 - 1.5*iqr) &
(df['amount'] <= q3 + 1.5*iqr)]
# 4. 统一文本
df['city'] = df['city'].str.strip().str.upper()特征工程
特征工程是"用领域知识创造更好特征"的过程,常比模型选择更影响效果:
import pandas as pd
df = pd.DataFrame({
'注册日期': ['2025-01-15', '2025-03-20'],
'总消费': [1000, 2000],
'订单数': [5, 10],
})
# 1. 构造衍生特征
df['注册年'] = pd.to_datetime(df['注册日期']).dt.year
df['客单价'] = df['总消费'] / df['订单数']
# 2. 分箱
df['消费等级'] = pd.cut(df['总消费'], bins=[0, 500, 1500, 9999],
labels=['低', '中', '高'])
# 3. 数值特征缩放(标准化)
from sklearn.preprocessing import StandardScaler
X = StandardScaler().fit_transform(df[['总消费', '订单数']])数据可视化
数据可视化让你在建模前就发现模式与问题:
import matplotlib.pyplot as plt
import seaborn as sns
# 1. 目标变量分布
sns.countplot(x='label', data=df)
# 2. 特征与目标关系(箱线图)
sns.boxplot(x='label', y='amount', data=df)
# 3. 相关性热力图
sns.heatmap(df.corr(), annot=True, cmap='RdBu')
# 4. 散点图看两个特征关系
sns.scatterplot(x='age', y='income', hue='label', data=df)
# 5. 缺失值可视化
sns.heatmap(df.isnull(), cbar=False)
plt.show()训练集测试集划分
训练集/测试集划分是评估模型泛化能力的基石:
from sklearn.model_selection import train_test_split
# 基础划分(7:3)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42)
# 分层抽样(保持类别比例,分类必用)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42, stratify=y)
# 时间序列:不能乱序切分!
train = df[df['date'] < '2026-06-01']
test = df[df['date'] >= '2026-06-01']统计学基础
机器学习需要的基础统计学知识:
import numpy as np
import pandas as pd
data = np.array([3, 5, 7, 8, 12, 15, 20])
# 描述统计
mean = np.mean(data) # 均值
median = np.median(data) # 中位数
std = np.std(data) # 标准差
var = np.var(data) # 方差
# 分位数
q1, q3 = np.percentile(data, [25, 75])
# 分布:正态分布(很多模型假设)
import scipy.stats as stats
# 生成正态分布样本
samples = np.random.normal(0, 1, 1000)| 概念 | 作用 |
|---|---|
| 均值/中位数 | 数据中心位置 |
| 方差/标准差 | 数据离散程度 |
| 正态分布 | 统计检验的基础假设 |
| 相关系数 | 变量间线性关系 |
概率思维
概率思维是理解机器学习算法的钥匙:
| 概念 | 含义 | ML 应用 |
|---|---|---|
| 概率 P(A) | 事件发生可能性 | 预测置信度 |
| 条件概率 P(A|B) | B 发生下 A 的概率 | 朴素贝叶斯 |
| 贝叶斯公式 | 由果推因 | 垃圾邮件过滤 |
| 似然 | 数据对参数的拟合度 | 最大似然估计 |
# 贝叶斯公式:P(垃圾|含"中奖")
# = P(含"中奖"|垃圾) * P(垃圾) / P(含"中奖")
# 用统计估计
# P(垃圾) = 垃圾邮件数 / 总邮件数
# P(含"中奖"|垃圾) = 垃圾中命中数 / 垃圾总数损失函数与梯度
损失函数衡量预测与真实值的差距,梯度下降用来最小化它:
import numpy as np
# 均方误差损失(回归常用)
def mse(y_true, y_pred):
return np.mean((y_true - y_pred) ** 2)
# 梯度下降示意(手动实现一元线性回归)
X = np.array([1, 2, 3, 4, 5])
y = np.array([2, 4, 5, 4, 6])
w, b, lr, epochs = 0.0, 0.0, 0.01, 500
for _ in range(epochs):
y_pred = w * X + b
dw = np.mean(2 * (y_pred - y) * X) # 对 w 求梯度
db = np.mean(2 * (y_pred - y)) # 对 b 求梯度
w -= lr * dw # 更新参数
b -= lr * db
print(f'w={w:.2f}, b={b:.2f}')| 损失函数 | 适用 | 公式 |
|---|---|---|
| MSE | 回归 | (y-ŷ)² 的均值 |
| MAE | 回归(抗离群) | |y-ŷ| 的均值 |
| 交叉熵 | 分类 | -Σy·log(ŷ) |
过拟合、欠拟合、偏差与方差
过拟合/欠拟合、偏差/方差是模型诊断的核心概念:
| 现象 | 表现 | 解决 |
|---|---|---|
| 欠拟合 | 训练、测试都差(模型太简单) | 加特征、换复杂模型 |
| 过拟合 | 训练好、测试差(模型太复杂) | 正则化、加数据、早停 |
| 高偏差 | 欠拟合(假设太强) | 换模型、加特征 |
| 高方差 | 过拟合(对数据太敏感) | 正则化、交叉验证 |
from sklearn.learning_curve import learning_curve # 新版用 sklearn.model_selection
from sklearn.model_selection import learning_curve
import numpy as np
# 学习曲线:观察训练/验证分数随数据量变化
train_sizes, train_scores, val_scores = learning_curve(
model, X, y, cv=5, train_sizes=np.linspace(0.1, 1.0, 5))
# 训练分高、验证分低 -> 过拟合(高方差)
# 两者都低 -> 欠拟合(高偏差)机器学习算法
经典机器学习算法全景图:
| 问题类型 | 算法 |
|---|---|
| 回归 | 线性回归、岭回归、Lasso、SVR |
| 分类 | 逻辑回归、决策树、SVM、KNN、朴素贝叶斯、随机森林、XGBoost |
| 聚类 | K-Means、层次聚类、DBSCAN |
| 降维 | PCA、t-SNE、LDA |
| 关联 | Apriori、FP-Growth |
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import RandomForestClassifier
# sklearn 统一接口:fit / predict / score
models = {
'逻辑回归': LogisticRegression(),
'决策树': DecisionTreeClassifier(),
'SVM': SVC(),
'KNN': KNeighborsClassifier(),
'随机森林': RandomForestClassifier()
}
for name, m in models.items():
m.fit(X_train, y_train)
print(name, m.score(X_test, y_test))线性回归
线性回归预测连续数值,是最基础也最可解释的模型:
import numpy as np
from sklearn.linear_model import LinearRegression
# 数据:面积 -> 价格
X = np.array([50, 60, 70, 80, 90]).reshape(-1, 1)
y = np.array([150, 180, 210, 240, 270])
model = LinearRegression()
model.fit(X, y)
# 参数
print('斜率 w:', model.coef_[0]) # 3.0
print('截距 b:', model.intercept_) # 0.0
print('预测 75m²:', model.predict([[75]])) # 225
# R² 决定系数(越接近 1 越好)
print('R²:', model.score(X, y))w 是斜率(每平米价格),b 是截距。可解释性极强。多元线性回归
多元线性回归考虑多个特征:
import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
# 多个特征:面积、房龄、楼层
data = pd.DataFrame({
'area': [50, 60, 70, 80, 90, 100],
'age': [20, 15, 10, 5, 3, 1],
'floor': [1, 3, 5, 8, 12, 20],
'price': [120, 165, 210, 255, 300, 360]
})
X = data[['area', 'age', 'floor']]
y = data['price']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
model = LinearRegression()
model.fit(X_train, y_train)
# 每个特征的权重(解释特征影响方向)
for col, coef in zip(X.columns, model.coef_):
print(f'{col}: {coef:.2f}')
print('R²:', model.score(X_test, y_test))多项式回归
多项式回归用多项式拟合非线性关系:
import numpy as np
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
# 非线性数据(二次关系)
X = np.linspace(0, 10, 50).reshape(-1, 1)
y = 2 * X.ravel()**2 + 3 * X.ravel() + 1 + np.random.randn(50) * 10
# 构造多项式特征(x, x², x³...)
poly = PolynomialFeatures(degree=2, include_bias=False)
X_poly = poly.fit_transform(X)
model = LinearRegression()
model.fit(X_poly, y)
print('R²:', model.score(X_poly, y))逻辑回归
逻辑回归名字带"回归",实际是分类算法(输出概率):
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer
data = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
data.data, data.target, test_size=0.3, random_state=42, stratify=data.target)
model = LogisticRegression(max_iter=1000)
model.fit(X_train, y_train)
# 输出概率而非仅类别
prob = model.predict_proba(X_test)[:3]
print('概率:', prob)
# 类别与准确率
print('预测:', model.predict(X_test[:3]))
print('准确率:', model.score(X_test, y_test))P(y=1|x),通过 sigmoid 函数把线性结果映射到 [0,1],天然适合二分类。回归模型评估
回归模型评估指标:
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
y_true = [100, 120, 130, 150]
y_pred = [105, 115, 140, 145]
mse = mean_squared_error(y_true, y_pred)
rmse = mse ** 0.5
mae = mean_absolute_error(y_true, y_pred)
r2 = r2_score(y_true, y_pred)
print(f'MSE={mse:.1f}, RMSE={rmse:.1f}, MAE={mae:.1f}, R²={r2:.3f}')| 指标 | 含义 | 优劣 |
|---|---|---|
| MSE | 误差平方均值 | 大误差惩罚重 |
| RMSE | MSE 开方 | 单位与 y 一致,常用 |
| MAE | 绝对误差均值 | 抗离群点 |
| R² | 决定系数 | 越接近 1 越好 |
决策树
决策树通过一系列"如果...那么..."规则做预测,可解释性强:
from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
iris = load_iris()
model = DecisionTreeClassifier(max_depth=3, random_state=42)
model.fit(iris.data, iris.target)
# 可视化树结构
plt.figure(figsize=(12, 8))
plot_tree(model, feature_names=iris.feature_names,
class_names=iris.target_names, filled=True)
plt.show()
# 特征重要性
for name, imp in zip(iris.feature_names, model.feature_importances_):
print(f'{name}: {imp:.3f}')max_depth 控制树深度防止过拟合;决策树对缺失值、量纲不敏感,适合表格数据。支持向量机
支持向量机(SVM)通过寻找最大间隔超平面分类,擅长高维数据:
from sklearn.svm import SVC
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
data = load_iris()
# 二分类演示
X, y = data.data[:100], data.target[:100]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# RBF 核(默认,适合非线性)
model = SVC(kernel='rbf', C=1.0, gamma='scale')
model.fit(X_train, y_train)
print('SVM 准确率:', model.score(X_test, y_test))| 核函数 | 特点 |
|---|---|
| linear | 线性可分,快 |
| rbf | 默认,非线性强 |
| poly | 多项式核 |
| sigmoid | 类似神经网络 |
K 近邻算法
K 近邻(KNN)是"物以类聚"的惰性算法:预测样本看它最近的 K 个邻居:
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
data = load_iris()
X_train, X_test, y_train, y_test = train_test_split(
data.data, data.target, test_size=0.3, random_state=42)
# KNN 对尺度敏感,必须标准化
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
model = KNeighborsClassifier(n_neighbors=5)
model.fit(X_train, y_train)
print('KNN 准确率:', model.score(X_test, y_test))集成学习
集成学习组合多个弱模型获得强模型,是竞赛常胜将军:
| 方法 | 原理 | 代表 |
|---|---|---|
| Bagging | 并行训练 + 投票平均 | 随机森林 |
| Boosting | 串行训练,纠正前轮错误 | AdaBoost、GBDT、XGBoost |
| Stacking | 用元模型组合多个模型 | 多模型融合 |
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
data = load_iris()
X_train, X_test, y_train, y_test = train_test_split(
data.data, data.target, test_size=0.3, random_state=42)
rf = RandomForestClassifier(n_estimators=100)
gb = GradientBoostingClassifier()
for name, m in [('随机森林', rf), ('梯度提升', gb)]:
m.fit(X_train, y_train)
print(name, m.score(X_test, y_test))朴素贝叶斯
朴素贝叶斯基于贝叶斯定理 + 特征独立假设,轻量高效:
from sklearn.naive_bayes import GaussianNB, MultinomialNB
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.model_selection import train_test_split
# 文本分类(垃圾邮件检测)
texts = ['免费领取大奖', '本周促销', '重要会议通知', '点击链接领红包']
labels = [1, 0, 0, 1] # 1 垃圾
vec = CountVectorizer()
X = vec.fit_transform(texts)
model = MultinomialNB()
model.fit(X, labels)
print('预测:', model.predict(vec.transform(['中奖点击链接'])))随机森林
随机森林 = Bagging + 决策树,最稳健的入门级集成模型:
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import cross_val_score
data = load_iris()
model = RandomForestClassifier(
n_estimators=200, # 树的数量
max_depth=5, # 树深
max_features='sqrt', # 每次分裂随机选特征数
random_state=42
)
# 交叉验证(比单次切分更可靠)
scores = cross_val_score(model, data.data, data.target, cv=5)
print('5折交叉验证:', scores)
print('平均准确率:', scores.mean())
# 特征重要性
model.fit(data.data, data.target)
for name, imp in zip(data.feature_names, model.feature_importances_):
print(f'{name}: {imp:.3f}')分类指标
分类指标(不止看准确率):
from sklearn.metrics import (accuracy_score, precision_score,
recall_score, f1_score, confusion_matrix, classification_report)
y_true = [1, 0, 1, 1, 0, 1, 0, 0]
y_pred = [1, 0, 0, 1, 0, 1, 1, 0]
print('准确率:', accuracy_score(y_true, y_pred))
print('精确率:', precision_score(y_true, y_pred)) # 预测为正中真的比例
print('召回率:', recall_score(y_true, y_pred)) # 正样本被找到的比例
print('F1:', f1_score(y_true, y_pred))
print(confusion_matrix(y_true, y_pred))
print(classification_report(y_true, y_pred))| 指标 | 场景 |
|---|---|
| 准确率 | 类别均衡时 |
| 精确率 | 误报代价高(垃圾邮件) |
| 召回率 | 漏报代价高(癌症筛查) |
| F1 | 精确率召回率兼顾 |
聚类
聚类是无监督学习的核心任务:把相似样本自动分组:
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
# 生成模拟数据(3 簇)
X, _ = make_blobs(n_samples=300, centers=3, random_state=42)
# K-Means 聚类
model = KMeans(n_clusters=3, random_state=42, n_init=10)
labels = model.fit_predict(X)
# 可视化
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis')
plt.scatter(model.cluster_centers_[:, 0],
model.cluster_centers_[:, 1],
marker='X', s=200, color='red')
plt.show()
# 用肘部法选 K
import numpy as np
inertias = [KMeans(n_clusters=k, n_init=10).fit(X).inertia_ for k in range(1, 8)]
plt.plot(range(1, 8), inertias, marker='o') # 拐点即合适 K
plt.show()降维
降维在保留主要信息的前提下减少特征数量,利于可视化与加速:
from sklearn.decomposition import PCA
from sklearn.datasets import load_digits
import matplotlib.pyplot as plt
digits = load_digits() # 64 维手写数字
# PCA 降到 2 维(用于可视化)
pca = PCA(n_components=2)
X_2d = pca.fit_transform(digits.data)
plt.scatter(X_2d[:, 0], X_2d[:, 1],
c=digits.target, cmap='tab10', s=5)
plt.colorbar()
plt.show()
# 方差解释率(信息保留程度)
print('解释方差占比:', pca.explained_variance_ratio_)
print('累计:', pca.explained_variance_ratio_.sum())强化学习基本框架
强化学习(RL)让智能体在环境中试错学习,通过奖励信号优化决策:
| 要素 | 说明 |
|---|---|
| 智能体(Agent) | 做出决策的主体 |
| 环境(Environment) | 智能体交互的对象 |
| 状态(State) | 环境的当前情况 |
| 动作(Action) | 智能体的选择 |
| 奖励(Reward) | 对动作的即时反馈 |
| 策略(Policy) | 状态 → 动作的映射 |
# 强化学习循环示意
state = env.reset()
while not done:
action = agent.select_action(state) # 根据策略选动作
next_state, reward, done = env.step(action) # 环境反馈
agent.update(state, action, reward, next_state) # 更新策略
state = next_state强化学习探索vs开采
强化学习中的探索 vs 开采(Exploration vs Exploitation)是核心权衡:
| 策略 | 含义 | 风险 |
|---|---|---|
| 探索 | 尝试未知动作发现更好选择 | 短期收益可能下降 |
| 开采 | 选择当前已知最优动作 | 可能错过更优策略 |
import numpy as np
# Epsilon-Greedy 策略(经典折中)
epsilon = 0.1 # 10% 概率探索
def select_action(q_values, epsilon):
if np.random.random() < epsilon:
return np.random.randint(len(q_values)) # 探索
return np.argmax(q_values) # 开采
# epsilon 可随时间衰减:前期多探索,后期多开采
epsilon = max(0.01, epsilon * 0.995)强化学习 Q-learning 与 SARSA
Q-Learning 与 SARSA是两种经典的免模型时序差分算法:
import numpy as np
# Q-Learning:更新 Q(s,a)
# Q(s,a) <- Q(s,a) + α[r + γ*max(Q(s',a')) - Q(s,a)]
def q_learning_update(q, s, a, r, s_next, alpha=0.1, gamma=0.9):
best_next = np.max(q[s_next]) # 贪心看下一步最优
q[s, a] += alpha * (r + gamma * best_next - q[s, a])
return q
# SARSA:与 Q-Learning 区别在于用"实际执行的动作"更新
# Q(s,a) <- Q(s,a) + α[r + γ*Q(s',a') - Q(s,a)]
def sarsa_update(q, s, a, r, s_next, a_next, alpha=0.1, gamma=0.9):
q[s, a] += alpha * (r + gamma * q[s_next, a_next] - q[s, a])
return q| 算法 | 更新方式 | 特点 |
|---|---|---|
| Q-Learning | 取 max(离线策略) | 更激进、探索更充分 |
| SARSA | 按当前策略(在线策略) | 更保守、更安全 |
深度强化学习
深度强化学习(DRL)= 深度学习 + 强化学习,用神经网络近似 Q 值或策略:
| 代表算法 | 核心思想 |
|---|---|
| DQN | 用神经网络近似 Q 函数,引入经验回放与目标网络 |
| Policy Gradient | 直接优化策略,适合连续动作 |
| PPO | 策略梯度 + 截断,稳定高效(当下主流) |
| DDPG / SAC | 连续动作控制 |
# DQN 核心组件示意
import torch.nn as nn
class DQN(nn.Module):
def __init__(self, state_dim, action_dim):
super().__init__()
self.net = nn.Sequential(
nn.Linear(state_dim, 128), nn.ReLU(),
nn.Linear(128, 128), nn.ReLU(),
nn.Linear(128, action_dim) # 输出每个动作的 Q 值
)
def forward(self, x):
return self.net(x)神经网络的基本结构
神经网络的基本结构:输入层 → 隐藏层 → 输出层,层间通过权重连接:
import torch.nn as nn
# 一个三层全连接神经网络(PyTorch)
model = nn.Sequential(
nn.Linear(4, 16), # 输入 4 -> 隐藏 16
nn.ReLU(), # 激活函数
nn.Linear(16, 16),
nn.ReLU(),
nn.Linear(16, 3) # 隐藏 -> 输出 3 类
)
# 参数量
total = sum(p.numel() for p in model.parameters())
print('参数总数:', total)| 组成 | 作用 |
|---|---|
| 神经元 | 加权求和 + 激活 |
| 权重/偏置 | 可学习参数 |
| 激活函数 | 引入非线性(ReLU/sigmoid/tanh) |
| 损失函数 | 衡量预测误差 |
前向传播与反向传播
前向传播与反向传播是神经网络训练的两个阶段:
| 阶段 | 过程 |
|---|---|
| 前向传播 | 输入 → 逐层计算 → 输出预测值 |
| 反向传播 | 损失 → 链式法则求梯度 → 逐层回传 |
| 参数更新 | w = w - 学习率 × 梯度 |
import torch
# 手写一个极小网络演示两个阶段
x = torch.tensor([1.0, 2.0])
w = torch.tensor([0.5, -0.3], requires_grad=True)
b = torch.tensor(0.1, requires_grad=True)
# 前向传播
y_pred = (x * w).sum() + b
# 计算损失(假设真实值为 1)
loss = (y_pred - 1) ** 2
print('损失:', loss.item())
# 反向传播(自动求梯度)
loss.backward()
print('梯度 w:', w.grad) # 损失对 w 的偏导
# 参数更新
with torch.no_grad():
w -= 0.01 * w.grad
b -= 0.01 * b.grad深度学习vs传统机器学习
深度学习 vs 传统机器学习:
| 维度 | 传统机器学习 | 深度学习 |
|---|---|---|
| 特征 | 人工特征工程 | 自动学习特征 |
| 数据量 | 千~万级 | 万~亿级(越大越强) |
| 硬件 | CPU 即可 | 需要 GPU |
| 可解释性 | 较好 | 较差(黑盒) |
| 适用 | 表格数据、中小样本 | 图像、语音、文本 |
# 传统 ML:表格数据(sklearn)
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier().fit(X, y)
# 深度学习:图像分类(PyTorch)
import torch.nn as nn
cnn = nn.Sequential(
nn.Conv2d(3, 32, 3), nn.ReLU(), nn.MaxPool2d(2),
nn.Flatten(), nn.Linear(32*13*13, 10)
)常见网络类型
常见网络类型:
| 网络 | 全称 | 适用 |
|---|---|---|
| CNN | 卷积神经网络 | 图像、视频 |
| RNN / LSTM | 循环神经网络 | 序列(文本、时间序列) |
| Transformer | 注意力机制 | NLP、多模态(主流) |
| GAN | 生成对抗网络 | 图像生成 |
| AutoEncoder | 自编码器 | 降维、异常检测 |
# CNN 图像分类示意
import torch.nn as nn
class CNN(nn.Module):
def __init__(self):
super().__init__()
self.conv = nn.Sequential(
nn.Conv2d(1, 32, kernel_size=3, padding=1), nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(32, 64, kernel_size=3, padding=1), nn.ReLU(),
nn.MaxPool2d(2)
)
self.fc = nn.Linear(64*7*7, 10)
def forward(self, x):
x = self.conv(x)
return self.fc(x.flatten(1))交叉验证
交叉验证比单次切分更可靠地评估模型泛化能力:
from sklearn.model_selection import cross_val_score, KFold
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
data = load_iris()
model = RandomForestClassifier(random_state=42)
# 5 折交叉验证
scores = cross_val_score(model, data.data, data.target, cv=5)
print('每折分数:', scores)
print('平均:', scores.mean().round(3), '±', scores.std().round(3))
# 自定义 K 折(可打乱)
kf = KFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(model, data.data, data.target, cv=kf)
# 分层 K 折(分类推荐)
from sklearn.model_selection import StratifiedKFold
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(model, data.data, data.target, cv=skf)正则化
正则化通过在损失函数中加入惩罚项抑制过拟合:
| 方法 | 惩罚 | 效果 |
|---|---|---|
| L1(Lasso) | Σ|w| | 稀疏权重,可做特征选择 |
| L2(Ridge) | Σw² | 权重趋小但非零,更平滑 |
| ElasticNet | L1+L2 组合 | 兼有两者 |
from sklearn.linear_model import Ridge, Lasso
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
X, y = make_regression(n_samples=100, n_features=20, noise=0.1, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
ridge = Ridge(alpha=1.0) # alpha 控制惩罚强度
lasso = Lasso(alpha=0.1)
for name, m in [('岭回归', ridge), ('Lasso', lasso)]:
m.fit(X_train, y_train)
print(name, 'R²:', m.score(X_test, y_test).round(3))
# Lasso 会把不重要的系数压成 0
print('Lasso 非零系数数:', (lasso.coef_ != 0).sum())数据泄漏
数据泄漏(Data Leakage)是建模中隐蔽而致命的错误:测试集信息混入训练,导致评估虚高、上线失效:
| 泄漏来源 | 例子 |
|---|---|
| 预处理泄漏 | 用全量数据做标准化/填充后再切分 |
| 特征泄漏 | 使用未来信息或目标派生特征 |
| 重复样本 | 同一用户多条记录出现在训练和测试 |
# 错误示范:先 fit 全量再切分(泄漏!)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X) # 用了测试集信息
X_train, X_test = train_test_split(X_scaled)
# 正确做法:只 fit 训练集
X_train, X_test = train_test_split(X)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test) # 用训练集的参数集成方法
集成方法实战对比:
from sklearn.ensemble import (RandomForestClassifier,
GradientBoostingClassifier, VotingClassifier)
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.datasets import load_iris
from sklearn.model_selection import cross_val_score
data = load_iris()
# 三个基础模型
lr = LogisticRegression(max_iter=1000)
rf = RandomForestClassifier(n_estimators=100, random_state=42)
svm = SVC(probability=True, random_state=42)
# 硬投票:多数表决
voting_hard = VotingClassifier([('lr', lr), ('rf', rf), ('svm', svm)],
voting='hard')
# 软投票:概率加权平均
voting_soft = VotingClassifier([('lr', lr), ('rf', rf), ('svm', svm)],
voting='soft')
for name, m in [('逻辑回归', lr), ('随机森林', rf), ('硬投票', voting_hard), ('软投票', voting_soft)]:
s = cross_val_score(m, data.data, data.target, cv=5).mean()
print(f'{name}: {s:.3f}')超参搜索
超参数搜索:模型之外的可调参数(树的深度、C、K)需要系统搜索:
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
data = load_iris()
model = RandomForestClassifier(random_state=42)
# 网格搜索(全组合穷举)
param_grid = {
'n_estimators': [50, 100, 200],
'max_depth': [None, 5, 10],
'min_samples_split': [2, 5]
}
grid = GridSearchCV(model, param_grid, cv=5, n_jobs=-1)
grid.fit(data.data, data.target)
print('最优参数:', grid.best_params_)
print('最优得分:', grid.best_score_.round(3))
# 随机搜索(大数据量时更快)
random_search = RandomizedSearchCV(
model, param_grid, n_iter=20, cv=5, random_state=42)
random_search.fit(data.data, data.target)MLOps 概念
MLOps 是把机器学习模型从实验推向生产的工程实践:
| 环节 | 工具/实践 |
|---|---|
| 版本管理 | 代码 Git、数据 DVC、模型 MLflow |
| 训练调度 | Airflow、Kubeflow |
| 模型服务 | FastAPI、Triton、TorchServe |
| 监控 | 数据漂移、性能回退检测 |
| CI/CD | 自动化测试与发布流水线 |
# 用 FastAPI 部署模型示例
from fastapi import FastAPI
import joblib
app = FastAPI()
model = joblib.load('model.pkl') # 训练后保存的模型
@app.post('/predict')
def predict(features: list[float]):
pred = model.predict([features])
return {'prediction': int(pred[0])}
# 启动: uvicorn main:app --port 8000常见问题排查
常见问题排查清单:
| 症状 | 可能原因 | 解决 |
|---|---|---|
| 准确率≈多数类比例 | 类别不平衡 | 重采样/换指标 |
| 训练好测试差 | 过拟合 | 正则化/更多数据 |
| 训练测试都差 | 欠拟合/特征差 | 加特征/换模型 |
| 损失不下降 | 学习率太大/数据未归一 | 调学习率/归一化 |
| 结果不稳定 | 随机种子未固定 | 固定 random_state |
| 预测为常数 | 数据泄漏/特征无效 | 检查泄漏与特征 |
可解释性问题
可解释性(Explainability):模型为什么这么预测?业务落地常需要解释:
# 1. 特征重要性(树模型自带)
rf.feature_importances_
# 2. SHAP 值(统一解释框架,推荐)
import shap
explainer = shap.TreeExplainer(rf)
shap_values = explainer.shap_values(X_test)
shap.summary_plot(shap_values, X_test)
# 3. LIME(局部解释单个样本)
from lime.lime_tabular import LimeTabularExplainer
explainer = LimeTabularExplainer(X_train, feature_names=feature_names)
exp = explainer.explain_instance(X_test[0], rf.predict_proba)
exp.show_in_notebook()假设限制
机器学习模型的假设与限制:
| 假设 | 限制 |
|---|---|
| 独立同分布 | 数据漂移时失效 |
| 特征充分 | 缺失关键特征则上限低 |
| 数据无偏 | 抽样偏差导致模型偏差 |
| 平稳性 | 环境变化需重训 |
# 检查数据分布漂移的简单方法
import numpy as np
# 训练集与线上新数据的特征分布对比
train_mean = np.mean(X_train, axis=0) axis=0)
drift = np.abs(train_mean - online_mean) / np.std(X_train, axis=0)
print('漂移程度(>2 需关注):', drift.round(2))数据偏差
数据偏差(Bias)会让模型"学习"社会的偏见:
| 偏差类型 | 例子 |
|---|---|
| 抽样偏差 | 只采集某地区数据 |
| 标注偏差 | 标注者主观标准不一 |
| 历史偏差 | 过去数据含歧视 |
| 代理偏差 | 用不完美代理变量 |
模型的现实成本
评估模型的现实成本,不只是准确率:
| 成本 | 说明 |
|---|---|
| 误报成本 | 把好人当坏人(客服投诉) |
| 漏报成本 | 放走坏人(资金损失) |
| 训练成本 | GPU/时间/人力 |
| 推理成本 | 线上 QPS 与延迟 |
# 用成本矩阵选择阈值(以风控为例)
import numpy as np
from sklearn.metrics import confusion_matrix
# 假设:漏报代价 100 元,误报代价 5 元
fn_cost, fp_cost = 100, 5
y_prob = model.predict_proba(X_test)[:, 1]
best_th, best_cost = 0.5, float('inf')
for th in np.arange(0.3, 0.8, 0.05):
y_pred = (y_prob >= th).astype(int)
tn, fp, fn, tp = confusion_matrix(y_test, y_pred).ravel()
cost = fn * fn_cost + fp * fp_cost
if cost < best_cost:
best_cost, best_th = cost, th
print(f'最优阈值 {best_th:.2f}, 最小成本 {best_cost}')泰坦尼克号生存预测
经典入门项目:泰坦尼克号生存预测(Kaggle 首战):
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
# 加载数据(Kaggle 提供)
train = pd.read_csv('titanic_train.csv')
# 特征工程
train['Sex'] = train['Sex'].map({'male': 0, 'female': 1})
train['Age'].fillna(train['Age'].median(), inplace=True)
train['Embarked'].fillna('S', inplace=True)
train['Embarked'] = train['Embarked'].map({'S': 0, 'C': 1, 'Q': 2})
train['FamilySize'] = train['SibSp'] + train['Parch'] + 1
# 选择特征
features = ['Pclass', 'Sex', 'Age', 'Fare', 'Embarked', 'FamilySize']
X = train[features]
y = train['Survived']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
model = RandomForestClassifier(n_estimators=200, max_depth=5, random_state=42)
model.fit(X_train, y_train)
print('准确率:', model.score(X_test, y_test).round(3))
# 重要发现:女性/头等舱生存率更高
print(model.feature_importances_.round(3))房价预测
回归实战:房价预测(波士顿/加州房价):
import pandas as pd
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
# 加州房价数据集(sklearn 内置)
from sklearn.datasets import fetch_california_housing
data = fetch_california_housing()
X, y = data.data, data.target
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42)
model = GradientBoostingRegressor(random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
rmse = mean_squared_error(y_test, y_pred) ** 0.5
print('RMSE:', rmse.round(3))
print('R²:', model.score(X_test, y_test).round(3))
# 特征重要性
for name, imp in sorted(zip(data.feature_names, model.feature_importances_),
key=lambda x: -x[1]):
print(f'{name}: {imp:.3f}')机器学习 - 客户分群
无监督实战:客户分群(RFM 分析 + K-Means):
import pandas as pd
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
# 客户数据:最近购买(Recency)、频次(Frequency)、金额(Monetary)
df = pd.DataFrame({
'customer_id': range(1, 101),
'recency': [30 - i % 30 for i in range(100)],
'frequency': [i % 10 + 1 for i in range(100)],
'monetary': [(i % 20 + 1) * 100 for i in range(100)]
})
# 标准化(聚类对尺度敏感)
X = StandardScaler().fit_transform(df[['recency', 'frequency', 'monetary']])
# K-Means 分 4 群
model = KMeans(n_clusters=4, random_state=42, n_init=10)
df['segment'] = model.fit_predict(X)
# 各群特征画像
print(df.groupby('segment')[['recency', 'frequency', 'monetary']].mean().round(1))PCA 可视化
降维可视化实战:PCA 可视化高维数据:
from sklearn.decomposition import PCA
from sklearn.datasets import load_digits
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
digits = load_digits() # 8x8=64 维手写数字
X_scaled = StandardScaler().fit_transform(digits.data)
pca = PCA(n_components=2)
X_2d = pca.fit_transform(X_scaled)
plt.figure(figsize=(10, 8))
scatter = plt.scatter(X_2d[:, 0], X_2d[:, 1],
c=digits.target, cmap='tab10', s=10, alpha=0.7)
plt.colorbar(scatter)
plt.title('手写数字 PCA 二维可视化')
plt.xlabel('PC1')
plt.ylabel('PC2')
plt.show()
# 观察:同类数字在低维空间中聚集 => 数据本身可分强化学习示例
强化学习示例:用 Q-Learning 解决经典迷宫/网格世界问题:
import numpy as np
# 4x4 网格世界:从 (0,0) 走到 (3,3),-1 为障碍
# 状态 = 16,动作 = 4(上下左右)
n_states, n_actions = 16, 4
q = np.zeros((n_states, n_actions))
# 简单转移函数:state -> 新 state(含边界限制,省略细节)
def step(state, action):
r, c = divmod(state, 4)
nr, nc = r, c
if action == 0: nr = max(0, r-1) # 上
if action == 1: nr = min(3, r+1) # 下
if action == 2: nc = max(0, c-1) # 左
if action == 3: nc = min(3, c+1) # 右
nxt = nr * 4 + nc
reward = 1.0 if nxt == 15 else 0.0 # 到达终点奖励
done = (nxt == 15)
return nxt, reward, done
# Q-Learning 训练
alpha, gamma, epsilon = 0.1, 0.9, 0.1
for episode in range(500):
state = 0
while True:
if np.random.random() < epsilon:
action = np.random.randint(4)
else:
action = np.argmax(q[state])
nxt, reward, done = step(state, action)
q[state, action] += alpha * (reward + gamma * np.max(q[nxt]) - q[state, action])
state = nxt
if done: break
# 打印学到的策略(每个格子的最优动作)
print(q.argmax(axis=1).reshape(4, 4))机器 教程
机器学习教程总结与进阶路线:
| 已掌握 | 下一步 |
|---|---|
| 数据清洗与 EDA | 数据竞赛实战(Kaggle) |
| 经典算法全家桶 | 深度学习(PyTorch 官方教程) |
| 模型评估与调参 | AutoML、大模型微调 |
| 基础项目 | 真实业务项目落地 |