机器学习基础一文速通:理清概念——实践代码任务

简介: 本文为机器学习期末复习整理,涵盖AI/ML/DL关系、KNN、SVM、决策树、K-Means、PCA及CNN/RNN等核心算法,配大量代码实践与图示,适合入门到进阶学习。资料可私信获取。

前言

本文为期末周复习时候顺手整理,内容较长,如果能全部看完的话一定会对机器学习乃至深度学习有一个比较基本的了解。感谢大家支持! 文章中涉及资料及实践用数据可以私信博主获取,或直接联系邮箱:chenai_tgf@163.com


1. 绪论:人工智能与机器学习

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

人工智能(AI) 是研究、开发用于模拟、延伸和扩展人类智能的理论、方法、技术及应用系统的综合性交叉学科。它包含感知能力、决策能力与行动能力,涵盖机器学习、自动推理、知识表示、语音识别、视觉识别等方向。

机器学习(ML) 是 AI 的子集。Tom Mitchell 给出经典定义:机器学习是一门研究算法的学科,这些算法能够——

  • 在任务 T
  • 通过经验 E(数据)
  • 提升性能 P(指标)

即学习任务由三元组 <T, P, E> 定义。

深度学习(DL) 是机器学习的子集,通过多层神经网络自动学习层次化特征表示。关系为:人工智能 ⊃ 机器学习 ⊃ 深度学习

1.2 机器学习简单例子:西瓜分类

训练数据包含特征(色泽、根蒂、敲声)与标签(好瓜/坏瓜)。学习算法从训练数据归纳出模型,再对新样本 (浅白, 蜷缩, 浊响, ?) 预测标签。

1.3 基本术语

术语 含义
数据集 训练集、测试集
样本 (sample) 一条观测记录
特征 (feature) / 属性 (attribute) 描述样本的变量
标签 (label) 监督学习中的目标值
特征向量 将各特征组成向量表示样本

1.4 监督学习 vs 无监督学习

监督学习:训练数据同时有特征和标签,学习「特征→标签」的映射。包括:

  • 分类:输出离散值(KNN、决策树、SVM、神经网络等)
  • 回归:输出连续值

无监督学习:只有特征、无标签,发现数据内在结构。包括聚类(K-Means)、降维(PCA)、关联规则(Apriori)等。

1.5 损失函数、梯度下降与泛化

监督学习的数学形式:给定数据集 $D = {(x_i, y_i)}_{i=1}^n$,学习映射 $f_\theta(x) \approx y$。

常见损失函数(回归):平方误差

$$\mathcal{L}(y, f_\theta(x)) = \frac{1}{2}(y - f_\theta(x))^2$$

通过 梯度下降 最小化损失,更新参数 $\theta$。

过拟合与欠拟合

  • 欠拟合:模型过于简单,无法捕捉数据趋势(如用直线拟合明显曲线)
  • 过拟合:模型过于复杂,把噪声也学进去(如高阶多项式)

1.6 代码练习 0:理解训练/测试划分

"""练习 0:手动实现 train/test 划分,理解监督学习基本流程"""
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
# 模拟数据:y = 2x + 噪声
rng = np.random.default_rng(42)
X = rng.uniform(0, 10, size=(100, 1))
y = 2 * X.ravel() + rng.normal(0, 1, size=100)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)
model = LinearRegression()
model.fit(X_train, y_train)
pred = model.predict(X_test)
print(f"测试集 MSE: {mean_squared_error(y_test, pred):.4f}")
print(f"学到的斜率≈2: {model.coef_[0]:.4f}")

2. Python 与 NumPy 基础

机器学习实践离不开 Python。本章要点:

  • 数据结构:列表、字典、元组、集合
  • NumPy:向量化运算、矩阵操作
  • Matplotlib:数据可视化

2.1 NumPy 数组与矩阵运算

2.2 代码练习 1:NumPy 距离计算(KNN 预备)

第 3 章会用到多种距离度量,先用 NumPy 实现:

"""练习 1:实现欧氏距离、曼哈顿距离、闵可夫斯基距离"""
import numpy as np
def euclidean(a: np.ndarray, b: np.ndarray) -> float:
    return np.sqrt(np.sum((a - b) ** 2))
def manhattan(a: np.ndarray, b: np.ndarray) -> float:
    return np.sum(np.abs(a - b))
def minkowski(a: np.ndarray, b: np.ndarray, p: int = 3) -> float:
    return np.sum(np.abs(a - b) ** p) ** (1 / p)
# 电影分类例子:接吻次数、打斗次数
train = np.array([
    [104, 3], [100, 2], [81, 1],   # 爱情
    [10, 101], [5, 99], [2, 98],   # 动作
])
labels = ["爱情", "爱情", "爱情", "动作", "动作", "动作"]
unknown = np.array([18, 90])
distances = [euclidean(unknown, x) for x in train]
k = 3
idx = np.argsort(distances)[:k]
votes = [labels[i] for i in idx]
from collections import Counter
print("K=3 预测:", Counter(votes).most_common(1)[0][0])

2.3 代码练习 2:数据归一化(0-1 标准化)

量纲大的特征会主导距离。使用 0-1 标准化:

"""练习 2:0-1 归一化(课件 datingTestSet 同款思路)"""
import numpy as np
def min_max_norm(data: np.ndarray) -> np.ndarray:
    min_vals = data.min(axis=0)
    max_vals = data.max(axis=0)
    return (data - min_vals) / (max_vals - min_vals + 1e-8)
raw = np.array([[40920, 8.3, 0.95], [14488, 7.2, 1.67]])
print("归一化后:\n", min_max_norm(raw))

2.4 代码练习 3:Matplotlib 绘图基础

由于本博客强调机器学习,固对matplotlib不过多赘述,大家感兴趣可以自行了解

"""练习 3:绘制 K 值-准确率折线图模板"""
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"] = ["Microsoft YaHei", "SimHei"]
plt.rcParams["axes.unicode_minus"] = False
ks = [1, 3, 5, 7, 9, 11]
acc = [0.92, 0.96, 0.97, 0.965, 0.96, 0.955]
plt.figure(figsize=(8, 5))
plt.plot(ks, acc, "o-", linewidth=2)
plt.xlabel("K(邻居数)")
plt.ylabel("测试准确率")
plt.title("K 值与分类准确率")
plt.grid(alpha=0.3)
plt.savefig("k_vs_accuracy_demo.png", dpi=150, bbox_inches="tight")
plt.close()

3. K 近邻(KNN)

3.1 分类基本思想

分类解决「这是什么」的问题。核心思想:相似的样本,标签也相似——用距离衡量相似度。

3.2 距离度量

距离 公式要点 sklearn 参数
欧氏距离 $\sqrt{\sum(x_i-y_i)^2}$ metric='euclidean'
曼哈顿距离 $\sum|x_i-y_i|$ metric='manhattan'
闵可夫斯基 $(\sum|x_i-y_i|^p)^{1/p}$ metric='minkowski', p=3
余弦距离 向量夹角 metric='cosine'

3.3 KNN 算法原理

  1. 计算测试样本与所有训练样本的距离
  2. 按距离升序,取前 K 个邻居
  3. 多数表决决定类别

最近邻(NN, K=1) 对噪声敏感;K 近邻 通过扩大投票范围提高鲁棒性。

3.4 KNN 优缺点

优点:简单直观、无需训练阶段(惰性学习)、适合多分类。

缺点

  • 预测时需与全部训练样本算距离,计算量大
  • K 值难选:K 过小易过拟合,K 过大易欠拟合
  • 对高维数据效果下降(维度灾难)

3.5 代码练习 4:手写数字 KNN识别

数据格式:32×32 文本文件,每行 32 个 0/1,文件名 标签_序号.txt

精简练习代码:

"""练习 4:sklearn KNN 手写数字识别"""
from pathlib import Path
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score, classification_report
def load_digit_folder(folder: Path):
    xs, ys = [], []
    for path in sorted(folder.glob("*.txt")):
        label = int(path.stem.split("_")[0])
        rows = []
        with path.open(encoding="utf-8") as f:
            for line in f:
                line = line.strip()
                if line:
                    rows.append([int(ch) for ch in line])
        xs.append(np.asarray(rows, dtype=float).reshape(-1))
        ys.append(label)
    return np.asarray(xs), np.asarray(ys)
# 修改为你的数据路径
root = Path("机器学习作业/机器学习作业1/数据集")
X_train, y_train = load_digit_folder(root / "trainingDigits")
X_test, y_test = load_digit_folder(root / "testDigits")
# Baseline:sklearn 默认 K=5, 欧氏距离
clf = KNeighborsClassifier()
clf.fit(X_train, y_train)
pred = clf.predict(X_test)
print(f"Baseline 准确率: {accuracy_score(y_test, pred):.4f}")
print(classification_report(y_test, pred))
# 对比不同距离度量
for name, kw in [
    ("欧氏", {"metric": "euclidean"}),
    ("曼哈顿", {"metric": "manhattan"}),
    ("余弦", {"metric": "cosine"}),
]:
    model = KNeighborsClassifier(n_neighbors=5, **kw)
    model.fit(X_train, y_train)
    acc = accuracy_score(y_test, model.predict(X_test))
    print(f"{name}距离 K=5 准确率: {acc:.4f}")

3.6 代码练习 5:K 值与距离度量网格搜索

"""练习 5:K 值 × 距离度量对比(对应作业1 grid 实验)"""
import pandas as pd
rows = []
for metric_name, kw in [
    ("euclidean", {"metric": "euclidean"}),
    ("manhattan", {"metric": "manhattan"}),
]:
    for k in range(1, 16, 2):
        m = KNeighborsClassifier(n_neighbors=k, **kw)
        m.fit(X_train, y_train)
        acc = accuracy_score(y_test, m.predict(X_test))
        rows.append({"metric": metric_name, "k": k, "accuracy": acc})
df = pd.DataFrame(rows)
best = df.loc[df["accuracy"].idxmax()]
print("最优组合:\n", best)

3.7 代码练习 6:PCA + KNN 降维实验

"""练习 6:PCA 降维 + KNN 管线"""
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
for n_comp in [10, 20, 50, 100, 200, 512]:
    pipe = Pipeline([
        ("scaler", StandardScaler()),
        ("pca", PCA(n_components=n_comp, random_state=42)),
        ("knn", KNeighborsClassifier(n_neighbors=5, metric="euclidean")),
    ])
    pipe.fit(X_train, y_train)
    acc = accuracy_score(y_test, pipe.predict(X_test))
    print(f"PCA n={n_comp:3d} → 准确率 {acc:.4f}")


4. 支持向量机(SVM)

4.1 核心思想:最大间隔

SVM 寻找能将两类分开的 超平面,使得 间隔(margin) 最大。距离分界最近的样本点称为 支持向量(Support Vector)

优化目标(硬间隔):最小化 $|w|^2$,约束 $y_i(w^Tx_i+b) \geq 1$。

4.2 软间隔与核函数

软间隔:引入松弛变量,允许部分样本分错,惩罚系数 C 控制容忍度。C 越大越不容错,易过拟合;C 越小间隔越大,易欠拟合。

非线性可分:通过核函数 $K(x_i, x_j) = \phi(x_i)^T \phi(x_j)$ 隐式映射到高维空间,无需显式计算 $\phi(x)$。

常用核函数:

核函数 sklearn 参数 特点
线性核 kernel='linear' 线性可分数据
RBF 高斯核 kernel='rbf' 最常用,处理非线性
多项式核 kernel='poly' 多项式决策边界
Sigmoid 核 kernel='sigmoid' 类神经网络

4.3 SVM vs KNN

SVM 训练后只需支持向量参与预测,预测复杂度低;KNN 预测需遍历全部训练样本。

4.4 代码练习 7:SVM 手写数字识别

"""练习 7:SVM 手写数字 Baseline + 网格搜索"""
from pathlib import Path
import numpy as np
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score, classification_report
from sklearn.model_selection import GridSearchCV
# 复用练习4的 load_digit_folder
root = Path("机器学习作业/机器学习作业2/手写数字数据集")
X_train, y_train = load_digit_folder(root / "trainingDigits")
X_test, y_test = load_digit_folder(root / "testDigits")
# Baseline SVM (RBF)
baseline = SVC(cache_size=100)
baseline.fit(X_train, y_train)
pred = baseline.predict(X_test)
print(f"Baseline SVM 准确率: {accuracy_score(y_test, pred):.4f}")
# 网格搜索 C × gamma
param_grid = {
    "C": [0.1, 1, 10, 100],
    "gamma": ["scale", 0.001, 0.01, 0.1],
    "kernel": ["rbf"],
}
grid = GridSearchCV(SVC(cache_size=100), param_grid, cv=3, n_jobs=1)
grid.fit(X_train, y_train)
print("最优参数:", grid.best_params_)
print(f"最优测试准确率: {accuracy_score(y_test, grid.predict(X_test)):.4f}")

4.5 代码练习 8:双螺旋数据 KNN vs SVM

双螺旋 spiral.csv 是典型 非线性可分 数据,线性 SVM 无法胜任,RBF 核 SVM 可以。

"""练习 8:双螺旋数据集上的 KNN / SVM 决策边界"""
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
df = pd.read_csv("机器学习作业/机器学习作业2/双螺旋/spiral.csv")
X = df[["x", "y"]].values
y = df["label"].values
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.25, random_state=42, stratify=y
)
scaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train)
X_test_s = scaler.transform(X_test)
for name, clf in [
    ("KNN k=5", KNeighborsClassifier(n_neighbors=5)),
    ("SVM linear", SVC(kernel="linear")),
    ("SVM RBF", SVC(kernel="rbf", gamma="scale")),
]:
    clf.fit(X_train_s, y_train)
    acc = accuracy_score(y_test, clf.predict(X_test_s))
    print(f"{name}: {acc:.4f}")
# 可视化决策边界(简化版)
xx, yy = np.meshgrid(
    np.linspace(X_train_s[:, 0].min() - 0.5, X_train_s[:, 0].max() + 0.5, 200),
    np.linspace(X_train_s[:, 1].min() - 0.5, X_train_s[:, 1].max() + 0.5, 200),
)
svm = SVC(kernel="rbf", gamma="scale")
svm.fit(X_train_s, y_train)
Z = svm.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)
plt.contourf(xx, yy, Z, alpha=0.3, cmap="coolwarm")
plt.scatter(X_train_s[:, 0], X_train_s[:, 1], c=y_train, cmap="coolwarm", edgecolors="k", s=20)
plt.title("双螺旋:RBF-SVM 决策边界")
plt.savefig("spiral_svm_boundary.png", dpi=150)
plt.close()


5. 决策树

5.1 决策树结构

决策树由 根节点内部节点(属性测试)、叶节点(类别输出)组成。学习过程是 自上而下分而治之 的递归划分。

停止条件:

  1. 当前节点样本全属同一类
  2. 属性集为空或所有样本属性取值相同
  3. 样本集合为空

5.2 信息熵与信息增益(ID3)

信息熵 衡量纯度:

$$\text{Ent}(D) = -\sum_{k=1}^{K} p_k \log_2 p_k$$

信息增益:选择使划分后熵下降最大的属性。ID3 算法用信息增益选特征。

5.3 剪枝与缺失值

预剪枝 / 后剪枝:控制树深度,防止过拟合。sklearn 中 max_depthmin_samples_leaf 等参数实现预剪枝。

缺失值处理:对含缺失样本赋权,在划分时按无缺失子集计算信息增益(课件 6.2 节)。

5.4 决策树本质

决策树产生 轴平行(axis-parallel) 分类边界——每个划分对应一个特征阈值。复杂边界需要很多段划分。

5.5 代码练习 9:泰坦尼克号 Age 缺失值填补

  1. 用 KNN / SVR 回归预测 Age,比较不同特征组合
  2. 用不同 Age 填补策略训练决策树,预测 Survived
"""练习 9:泰坦尼克 Age 缺失值 KNN 回归填补"""
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.neighbors import KNeighborsRegressor
from sklearn.metrics import mean_absolute_error
df = pd.read_csv("机器学习作业/机器学习作业3/泰坦尼克号/train.csv")
known = df[df["Age"].notna()].copy()
feature_cols = ["Pclass", "Sex", "SibSp", "Parch", "Fare", "Embarked"]
X = known[feature_cols]
y = known["Age"].values
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)
pre = ColumnTransformer([
    ("num", Pipeline([
        ("imputer", SimpleImputer(strategy="median")),
        ("scaler", StandardScaler()),
    ]), ["Pclass", "SibSp", "Parch", "Fare"]),
    ("cat", Pipeline([
        ("imputer", SimpleImputer(strategy="most_frequent")),
        ("encoder", OneHotEncoder(handle_unknown="ignore", sparse_output=False)),
    ]), ["Sex", "Embarked"]),
])
pipe = Pipeline([
    ("pre", pre),
    ("model", KNeighborsRegressor(n_neighbors=5, weights="distance")),
])
pipe.fit(X_train, y_train)
pred = pipe.predict(X_test)
print(f"Age 预测 MAE: {mean_absolute_error(y_test, pred):.3f} 岁")

5.6 代码练习 10:决策树生存预测

"""练习 10:决策树预测泰坦尼克生存"""
from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.metrics import accuracy_score, classification_report
from sklearn.model_selection import cross_val_score
# 用 KNN 填补后的 Age
def impute_age_knn(df, feature_cols):
    data = df.copy()
    known = data[data["Age"].notna()]
    missing = data[data["Age"].isna()]
    if missing.empty:
        return data["Age"]
    pre = ColumnTransformer([
        ("num", Pipeline([
            ("imputer", SimpleImputer(strategy="median")),
            ("scaler", StandardScaler()),
        ]), [c for c in feature_cols if c not in ("Sex", "Embarked")]),
        ("cat", Pipeline([
            ("imputer", SimpleImputer(strategy="most_frequent")),
            ("encoder", OneHotEncoder(handle_unknown="ignore", sparse_output=False)),
        ]), [c for c in feature_cols if c in ("Sex", "Embarked")]),
    ])
    reg_pipe = Pipeline([("pre", pre), ("model", KNeighborsRegressor(n_neighbors=5))])
    reg_pipe.fit(known[feature_cols], known["Age"])
    data.loc[missing.index, "Age"] = reg_pipe.predict(missing[feature_cols])
    return data["Age"]
features = ["Pclass", "Sex", "Age", "SibSp", "Parch", "Fare", "Embarked"]
df = pd.read_csv("机器学习作业/机器学习作业3/泰坦尼克号/train.csv")
df["Age"] = impute_age_knn(df, ["Pclass", "Sex", "SibSp", "Parch", "Fare", "Embarked"])
X = df[features]
y = df["Survived"]
dt_pipe = Pipeline([
    ("pre", ColumnTransformer([
        ("num", Pipeline([
            ("imputer", SimpleImputer(strategy="median")),
            ("scaler", StandardScaler()),
        ]), ["Pclass", "Age", "SibSp", "Parch", "Fare"]),
        ("cat", Pipeline([
            ("imputer", SimpleImputer(strategy="most_frequent")),
            ("encoder", OneHotEncoder(handle_unknown="ignore", sparse_output=False)),
        ]), ["Sex", "Embarked"]),
    ])),
    ("clf", DecisionTreeClassifier(max_depth=5, min_samples_leaf=5, random_state=42)),
])
cv = cross_val_score(dt_pipe, X, y, cv=5, scoring="accuracy")
print(f"5折CV准确率: {cv.mean():.4f} ± {cv.std():.4f}")
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42, stratify=y)
dt_pipe.fit(X_train, y_train)
print(classification_report(y_test, dt_pipe.predict(X_test), target_names=["未生还", "生还"]))


6. K-Means 聚类

6.1 聚类与无监督学习

聚类 将样本划分为若干簇,使簇内相似、簇间相异。与分类不同:类别不是事先给定的。

6.2 K-Means 算法

目标:最小化簇内平方和 SSE( inertia )

Lloyd 迭代

  1. 初始化 K 个质心(推荐 k-means++
  2. 分配:每个样本归入最近质心
  3. 更新:重新计算各簇均值作为新质心
  4. 重复 2–3 直到收敛

……….

6.3 K 值选择

方法 说明
肘部法 SSE 随 K 增大而下降,选下降率突变(拐点)处
轮廓系数 SC 越大越好,K 取 SC 最大值

6.4 注意事项

  • 标准化:各特征量纲差异大时必须 StandardScaler
  • 初值敏感:使用 init='k-means++'
  • 异常点:均值质心易受离群点影响(K-Medoids 更鲁棒)

6.5 代码练习 11:连锁餐饮 K-Means

数据:restaurant.csv,V1=地区,V2–V9 为经营指标。

"""练习 11:连锁餐饮 K-Means 聚类(作业4核心)"""
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
from sklearn.decomposition import PCA
df = pd.read_csv("机器学习作业/机器学习作业4/restaurant.csv")
CLUSTER_FEATURES = ["V3", "V4", "V5", "V6", "V7"]  # 门店数、人数、面积、餐位、营业额
X_raw = df[CLUSTER_FEATURES].astype(float).values
X = StandardScaler().fit_transform(X_raw)
# K 值评估:肘部法 + 轮廓系数
sse_list, sil_list = [], []
for k in range(2, 9):
    km = KMeans(n_clusters=k, init="k-means++", n_init=10, random_state=42)
    labels = km.fit_predict(X)
    sse_list.append(km.inertia_)
    sil_list.append(silhouette_score(X, labels))
    print(f"K={k}  SSE={km.inertia_:.2f}  SC={sil_list[-1]:.4f}")
chosen_k = range(2, 9)[int(np.argmax(sil_list))]
km = KMeans(n_clusters=chosen_k, init="k-means++", n_init=10, random_state=42)
labels = km.fit_predict(X)
df["cluster"] = labels
print("\n各地区聚类结果:")
print(df[["V1", "cluster"] + CLUSTER_FEATURES].sort_values("cluster"))
# PCA 二维可视化
pca = PCA(n_components=2, random_state=42)
X2 = pca.fit_transform(X)
plt.figure(figsize=(8, 6))
plt.scatter(X2[:, 0], X2[:, 1], c=labels, cmap="viridis", s=80, edgecolors="k")
for i, name in enumerate(df["V1"]):
    plt.annotate(name, (X2[i, 0], X2[i, 1]), fontsize=7)
plt.xlabel(f"PC1 ({pca.explained_variance_ratio_[0]*100:.1f}%)")
plt.ylabel(f"PC2 ({pca.explained_variance_ratio_[1]*100:.1f}%)")
plt.title(f"连锁餐饮 PCA 聚类可视化 (K={chosen_k})")
plt.savefig("restaurant_clusters.png", dpi=150, bbox_inches="tight")
plt.close()


7. 主成分分析(PCA)

7.1 降维动机

高维数据带来 维数灾难:计算量大、易过拟合、难以可视化。降维分为:

  • 特征选择:保留原始特征子集
  • 特征提取:通过变换得到新特征(PCA 属于此类)

7.2 PCA 原理

PCA 通过 正交变换 将数据投影到方差最大的方向:

  • 第一主成分 PC1:数据方差最大的方向
  • 第二主成分 PC2:与 PC1 正交且方差次大的方向
  • 保留前 k 个主成分,尽可能保留原始信息

几何解释:找到数据分布椭圆的 长轴 方向作为主成分。

7.3 代码练习 12:PCA 降维与方差解释比

"""练习 12:PCA 方差解释比与二维可视化"""
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
df = pd.read_csv("机器学习作业/机器学习作业4/restaurant.csv")
cols = ["V3", "V4", "V5", "V6", "V7", "V8", "V9"]
X = StandardScaler().fit_transform(df[cols].astype(float))
pca = PCA()
pca.fit(X)
print("各主成分方差解释比:", np.round(pca.explained_variance_ratio_, 4))
print("累计解释比:", np.round(np.cumsum(pca.explained_variance_ratio_), 4))
# 碎石图
plt.figure(figsize=(8, 4))
plt.bar(range(1, len(cols)+1), pca.explained_variance_ratio_, label="单个")
plt.plot(range(1, len(cols)+1), np.cumsum(pca.explained_variance_ratio_), "ro-", label="累计")
plt.xlabel("主成分编号")
plt.ylabel("方差解释比")
plt.legend()
plt.title("PCA 碎石图")
plt.savefig("pca_scree_plot.png", dpi=150)
plt.close()

8. 卷积神经网络(CNN)

8.1 深度学习两大本质

  1. 特征自动学习:替代 SIFT、HOG 等手工特征
  2. 层次网络结构:低层→高层,特征越来越抽象(模拟人脑视觉层次)

8.2 卷积神经网络核心组件

组件 作用
卷积层 (Conv) 局部感受野,提取空间特征
激活函数 (ReLU) 引入非线性
池化层 (Pool) 降采样,增强平移不变性
全连接层 (FC) 分类决策

8.3 PyTorch 基础

8.4 代码练习 13:PyTorch 简单 CNN(MNIST 风格)

"""练习 13:PyTorch 简易 CNN 图像分类框架"""
import torch
import torch.nn as nn
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
class SimpleCNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.net = nn.Sequential(
            nn.Conv2d(1, 16, 3, padding=1), nn.ReLU(),
            nn.MaxPool2d(2),
            nn.Conv2d(16, 32, 3, padding=1), nn.ReLU(),
            nn.MaxPool2d(2),
            nn.Flatten(),
            nn.Linear(32 * 7 * 7, 128), nn.ReLU(),
            nn.Linear(128, 10),
        )
    def forward(self, x):
        return self.net(x)
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.1307,), (0.3081,)),
])
train_set = datasets.MNIST("./data", train=True, download=True, transform=transform)
test_set = datasets.MNIST("./data", train=False, transform=transform)
train_loader = DataLoader(train_set, batch_size=64, shuffle=True)
model = SimpleCNN().to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
criterion = nn.CrossEntropyLoss()
model.train()
for epoch in range(3):  # 演示用 3 epoch,实际需更多
    total_loss = 0.0
    for x, y in train_loader:
        x, y = x.to(device), y.to(device)
        optimizer.zero_grad()
        loss = criterion(model(x), y)
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
    print(f"Epoch {epoch+1} loss: {total_loss/len(train_loader):.4f}")


9. 循环神经网络(RNN / LSTM)

9.1 RNN 概述

RNN 通过 隐藏状态 传递序列信息,适合时间序列、文本等有序数据。

结构类型

类型 输入→输出 应用
many-to-one 序列→单个 情感分析
one-to-many 单个→序列 图像描述
many-to-many 序列→序列 机器翻译

9.2 长期依赖问题

普通 RNN 在长序列上会出现 梯度消失($W<1$)和 梯度爆炸($W>1$),难以捕获远距离依赖。

9.3 LSTM

LSTM 引入 细胞状态 和三个门:

  • 遗忘门:决定丢弃哪些旧信息
  • 输入门:决定写入哪些新信息
  • 输出门:决定输出什么

9.4 GRU

GRU 是 LSTM 的简化版,合并遗忘门与输入门为 更新门,参数更少、训练更快。

9.5 代码练习 14:PyTorch LSTM 文本分类框架

"""练习 14:PyTorch LSTM 序列分类骨架(many-to-one)"""
import torch
import torch.nn as nn
class LSTMClassifier(nn.Module):
    def __init__(self, vocab_size, embed_dim=64, hidden_dim=128, num_classes=2):
        super().__init__()
        self.embed = nn.Embedding(vocab_size, embed_dim)
        self.lstm = nn.LSTM(embed_dim, hidden_dim, batch_first=True)
        self.fc = nn.Linear(hidden_dim, num_classes)
    def forward(self, x):
        # x: (batch, seq_len)
        emb = self.embed(x)           # (batch, seq_len, embed_dim)
        _, (h_n, _) = self.lstm(emb)  # h_n: (1, batch, hidden)
        return self.fc(h_n.squeeze(0))
# 模拟 batch
model = LSTMClassifier(vocab_size=5000)
dummy_x = torch.randint(0, 5000, (32, 20))  # 32 句,每句 20 token
logits = model(dummy_x)
print("输出形状:", logits.shape)  # (32, 2)

10. 总结与学习路线

10.1 算法对比速查

算法 类型 核心思想 关键超参数 对应作业
KNN 监督/分类 距离 + 多数表决 K, metric 作业1
SVM 监督/分类 最大间隔 + 核技巧 C, kernel, gamma 作业2
决策树 监督/分类 信息增益划分 max_depth, min_samples_leaf 作业3
K-Means 无监督/聚类 最小化 SSE K, init 作业4
PCA 无监督/降维 最大方差投影 n_components 作业1/4
CNN 深度学习/分类 卷积 + 层次特征 lr, batch_size, epochs 课件第8章
LSTM 深度学习/序列 门控记忆 hidden_dim, layers 课件第9章

10.2 机器学习实施流程

  1. 问题定义:明确 T、P、E
  2. 数据准备:采集、清洗、划分 train/val/test
  3. 特征工程:选择、变换、标准化
  4. 模型选择与训练:选算法、调参、交叉验证
  5. 评估与诊断:准确率、混淆矩阵、过拟合检查
  6. 部署与迭代

10.3 推荐实践顺序

第1章 绪论(概念)
第2章 Python/NumPy(工具)
作业1:KNN 手写数字(监督分类入门)
作业2:SVM + 双螺旋(非线性分类)
作业3:决策树 + 缺失值(数据预处理 + 可解释模型)
作业4:K-Means + PCA(无监督学习)
第8–9章 CNN / RNN(深度学习进阶)

目录
相关文章
|
5天前
|
人工智能 定位技术 SEO
我学 GEO 第 15 天:终于知道AI GEO该如何做?
我是暴走的莉莉酱,边旅行边研究AI GEO的数字游民。专注普通人如何提升“AI可见度”——让AI在回答用户问题时准确识别、理解并推荐你。不讲玄学,只做可测、可调、可持续的GEO实践。
403 125
|
7天前
|
机器学习/深度学习 人工智能 调度
🐴 HappyHorse 1.1 现已上线阿里云百炼!快来查收模型使用指南,现在调用享 6 折~
HappyHorse 1.1 是新一代视频生成大模型,全面升级动态表现力、角色一致性、指令遵循、视觉质感与音画协同能力。支持I2V/T2V/R2V三类生成,适配短剧、电商广告、品牌营销等场景,提供高质、流畅、可控的AI视频生产力。
688 4
🐴 HappyHorse 1.1 现已上线阿里云百炼!快来查收模型使用指南,现在调用享 6 折~
|
5天前
|
缓存 人工智能 运维
阿里云618百炼大模型Qwen3.7-Max功能、免费试用、订阅计费、配置接入详解
Qwen3.7-MAX是阿里云百炼平台推出的通义千问3.7系列旗舰大语言模型,专为智能体时代复杂任务打造,依托阿里云全域算力与自研技术,在逻辑推理、长文本处理、代码工程、长周期自主执行等领域达到行业顶尖水平。2026年618期间,该模型推出多重免费试用权益、按量计费5折、订阅套餐优惠等专属福利,覆盖个人开发者、团队与企业全场景需求,以下从核心功能、免费试用、订阅计费、配置接入四方面展开详细解析。
398 123
|
3天前
|
人工智能 自然语言处理 API
阿里云Token Plan团队版解析:功能、三档套餐与省钱订阅指南
阿里云百炼平台推出的Token Plan团队版,是面向企业与团队的AI大模型订阅服务,以Credits为统一计量单位,整合文本与图像生成模型,提供团队管理、数据安全、多工具兼容等核心能力,解决团队零散订阅AI服务的管理混乱、成本失控、数据安全等痛点。本文将从核心定位、套餐详情、计费规则、团队管理、工具兼容、便宜订阅技巧等方面,全面解析Token Plan团队版,帮助企业与团队高效、低成本地使用AI服务。
298 108
|
18天前
|
缓存 测试技术 API
Qwen 3.7 Plus 与 Max 实测:性价比与多模态能力差异解析(2026)
2026 年 6 月 1 日,阿里悄无声息地发布了 Qwen 3.7 Plus,距 Qwen 3.7 Max 上线刚好 11 天。同样的 1M 上下文,同样的 35 小时自治上限。但价格才是头条:Plus 是 0.40/M输入,Max是 2.50/M——便宜约 6 倍——并且还能看图、看视频。Vision Arena 上 Plus 已经排到 #16。所以这周真正值得讨论的问题不是”要不要为视觉能力买单”,而是”Max 凭什么用 6 倍价格换来 2 个百分点的 benchmark 领先”。
|
4天前
|
存储 人工智能 数据可视化
别再手动复制 Skill 了:多 Agent 时代的 Skill 管理方案
多 Agent 场景下 Skill 的统一管理与同步。
236 124
|
11天前
|
缓存 人工智能 运维
GLM 5.2自托管全流程实战:硬件选型、vLLM/SGLang部署与成本盈亏测算
2026年智谱发布GLM 5.2超大混合专家模型,区别于以往仅开放API的闭源大模型,该模型权重以MIT开源协议对外发布,企业与开发者可完整下载、本地审计、私有化部署,实现数据不出环境、自定义微调、自主调度推理资源。GLM 5.2拥有753B总参数,原生支持百万级上下文窗口,在代码生成、长文档推理、数学逻辑等多项基准测试中对标国际顶尖商用模型,是首款可完整自托管的前沿代码向大模型。
888 0
|
4天前
|
SQL 存储 运维
日志能不能改?SLS LogStore 原生支持更新和删除了
随着日志承载的业务语义越来越多,数据订正、回填、清理等需求变得越来越常见。SLS 现已为 LogStore 提供原生 update/delete 能力——支持按 RowID 精确修改,按查询条件批量操作,类似计费调账、标签刷新、反馈回填等场景都可以直接在 LogStore 内完成闭环。
206 124