目录

一、什么是机器学习

1.1 定义与核心概念

1.2 人工智能、机器学习与深度学习的关系

1.3 机器学习算法分类

二、机器学习开发流程

三、数据集与 Scikit-learn

3.2 可用数据集来源

3.3 Scikit-learn 数据集 API

3.4 数据集划分

四、特征工程

4.1 特征提取

4.1.1 字典特征提取

4.1.2 文本特征提取(CountVectorizer)

4.1.3 TF-IDF 文本特征提取

4.2 特征预处理

4.2.1 归一化(MinMaxScaler)

4.2.2 标准化(StandardScaler)

4.3 特征降维

4.3.1 维数灾难

4.3.2 低方差特征过滤(Filter)

4.3.3 主成分分析(PCA)

五、核心算法讲解

5.1 K-近邻算法(KNN)

算法原理

KNN 三要素

算法流程

API 与代码示例

实战:预测签到位置

5.2 K-means 聚类算法

算法概述

算法流程

K 值的选择:肘部法则

性能评估:轮廓系数

完整代码示例

5.3 决策树算法

算法原理

信息熵与信息增益

API

实战一:鸢尾花分类

实战二:银行贷款分类

5.4 随机森林算法

集成学习与 Bagging

随机森林原理

算法步骤

API

实战:鸢尾花分类

进阶实战:乳腺癌预测

5.5 专家系统

概念

正向推理(数据驱动)

逆向推理(目标驱动)

专家系统的核心挑战

六、模型优化

6.1 模型选择与调优

交叉验证(Cross Validation)

超参数搜索 — 网格搜索(Grid Search)

代码示例

6.2 模型保存与加载

使用 joblib

使用 pickle

总结


一、什么是机器学习

1.1 定义与核心概念

机器学习是从数据中自动分析获得模型,并利用模型对未知数据进行预测的方法。正如人类从大量日常经验中归纳规律,当面临新问题时利用以往总结的规律去分析现实状况一样,机器学习让计算机从数据(如大量猫和狗的图片)中自动获得辨别规律的能力。

数据集构成:

  • 结构:特征值 + 目标值
  • 每一行数据称为一个样本
  • 有些数据集可以没有目标值(无监督学习场景)

1.2 人工智能、机器学习与深度学习的关系

  • 人工智能(AI): 机器展现的人类智能
  • 机器学习(ML): 计算机利用已有的数据(经验),得出某种模型,并利用此模型预测未来的一种方法 —— 是 AI 的一个实现途径
  • 深度学习(DL): 实现机器学习的一种技术 —— 是机器学习的一个方法发展而来

历史背景: 1956年8月,达特茅斯会议上约翰·麦卡锡、马文·闵斯基、克劳德·香农等科学家首次提出"人工智能"概念,1956年因此成为人工智能元年。

1.3 机器学习算法分类

任务学习方式是否需要标签输出
分类监督学习需要离散类别(A/B/C)
回归监督学习需要连续数值(小数)
聚类无监督学习不需要自动分组
问题类型特征值示例目标值典型问题
分类(Classification)猫/狗图片;肿瘤体积+年龄类别(离散)肥胖判断?肿瘤良性/恶性?
回归(Regression)房屋属性信息连续型数据房价预测?股票走势?
聚类(Clustering)人物属性信息无目标值按爱好/身高将学生分5类

二、机器学习开发流程

机器学习项目的成功不仅依赖算法选择,更在于系统化的开发流程。完整流程涵盖数据获取 → 数据处理 → 特征工程 → 模型训练 → 模型评估 → 部署监控六大阶段。

阶段核心任务常用工具/方法注意事项
数据获取收集、划分数据集(训练70%/验证15%/测试15%)Pandas, SQL, Kaggle确保数据隐私与合规性
数据处理清洗缺失值、异常值,标准化数据Scikit-learn, Imbalanced-learn避免测试集信息泄露到训练集
特征工程构造、选择、降维特征PCA, Feature-engine, XGBoost结合业务理解设计特征
模型训练算法选型、超参数调优Scikit-learn, LightGBM, AutoML优先选择简单可解释的模型
模型评估验证泛化能力,对比业务指标Matplotlib, SHAP, MLflow避免过拟合,关注负样本表现
部署与监控发布API、监控性能、定期迭代Docker, Prometheus, Grafana记录模型版本和预测日志

核心原则: 数据质量 > 算法复杂度(90%的模型问题源于数据缺陷);模型服务于业务(评估指标需与商业目标对齐);工程化是关键(从 Notebook 到生产需严谨封装和测试)。


三、数据集与 Scikit-learn

3.1 数据集基本概念

要进行机器学习,先要有数据。数据集是机器学习的基础。一条数据(一行)就是一个样本,数据的每一列属性就是一个特征,而需要预测的目标列就是标签。

3.2 可用数据集来源

来源网址特点
KaggleChecking your browser - reCAPTCHA竞赛数据集丰富,含真实业务数据
UCIUCI Machine Learning Repository经典学术数据集,种类多
Scikit-learnscikit-learn: machine learning in Python — scikit-learn 0.16.1 documentation内置小规模数据集,方便快速实验

3.3 Scikit-learn 数据集 API

from sklearn.datasets import load_iris
# 获取鸢尾花数据集
iris = load_iris()
print("鸢尾花的特征值:\n", iris["data"])
print("鸢尾花的目标值:\n", iris.target)
print("鸢尾花特征的名字:\n", iris.feature_names)
print("鸢尾花目标值的名字:\n", iris.target_names)
print("鸢尾花的描述:\n", iris.DESCR)

返回值类型为 Bunch(继承自字典),包含以下字段:

  • data:特征数据数组 [n_samples × n_features]
  • target:标签数组 [n_samples]
  • feature_names:特征名列表
  • target_names:标签名列表
  • DESCR:数据描述

3.4 数据集划分

拿到的数据不能全部用来训练模型,需要划分为训练集和测试集:

  • 训练集(70%~80%):用于训练,构建模型
  • 测试集(20%~30%):用于评估模型是否有效
from sklearn.model_selection import train_test_split

# 划分:训练集特征/测试集特征/训练集标签/测试集标签
x_train, x_test, y_train, y_test = train_test_split(
    iris.data, iris.target, random_state=22
)
print("x_train:", x_train.shape)


四、特征工程

业界名言(Andrew Ng): "数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已。"

特征工程是使用专业背景知识和技巧处理数据,使得特征能在机器学习算法上发挥更好作用的过程。它包含三大内容:特征抽取、特征预处理、特征降维

4.1 特征提取

将任意数据(如文本或图像)转换为可用于机器学习的数字特征。

4.1.1 字典特征提取

对字典数据进行 one-hot 编码式的特征值化:

from sklearn.feature_extraction import DictVectorizer

data = [
    {'city': '北京', 'temperature': 100},
    {'city': '上海', 'temperature': 60},
    {'city': '深圳', 'temperature': 30}
]
# 实例化转换器
transfer = DictVectorizer(sparse=False)
data = transfer.fit_transform(data)
print("返回的结果:\n", data)
print("特征名字:\n", transfer.get_feature_names())

结果:

4.1.2 文本特征提取(CountVectorizer)

from sklearn.feature_extraction.text import CountVectorizer

data = ["life is short,i like python",
        "life is too long,i dislike python"]
transfer = CountVectorizer()
data = transfer.fit_transform(data)
print("文本特征抽取的结果:\n", data.toarray())
print("返回特征名字:\n", transfer.get_feature_names())

输出:

文本特征抽取的结果:
 [[0 1 1 1 1 0 1 0]
 [1 1 1 0 0 1 1 1]]
返回特征名字:
 ['dislike', 'is', 'life', 'like', 'python', 'long', 'short', 'too']

每一列代表一个单词,句子里有这个词填 1,没有就填 0。

中文分词注意: 英文默认以空格分词,中文需借助 jieba 库进行分词处理后再传入 CountVectorizer。

import jieba

def cut_word(text):
    text = " ".join(list(jieba.cut(text)))
    return text

data = ["一种还是一种今天很残酷,明天更残酷,后天很美好……",
        "我们看到的从很远星系来的光是在几百万年之前发出的……",
        "如果只用一种方式了解某样事物,你就不会真正了解它。……"]

text_list = [cut_word(sent) for sent in data]
transfer = CountVectorizer()
data = transfer.fit_transform(text_list)

输出:

['不会', '一种', '今天', '几百万年', '发出', '后天', '如果', '我们', '星系', '就不会', '很远', '方式', '明天', '是在', '看到', '残酷', '了解', '事物', '用来', '真正', '美好', '之前']
[[0 2 1 0 0 1 0 0 0 0 0 0 1 0 0 2 0 0 0 0 1 0]
 [0 0 0 1 1 0 0 1 1 0 1 0 0 1 1 0 0 0 0 0 0 1]
 [1 1 0 0 0 0 1 0 0 1 0 1 0 0 0 0 2 1 1 1 0 0]]

先用 jieba 把中文切成词语,再 CountVectorizer 统计每个词出现多少次,输出词频矩阵。

4.1.3 TF-IDF 文本特征提取

TF-IDF 的核心思想: 如果某个词在一篇文章中出现的概率高,并且在其他文章中很少出现,则认为此词具有很好的类别区分能力。

  • TF(词频): 某词在该文件中出现的频率
  • IDF(逆向文档频率): 总文件数 ÷ 包含该词的文件数,取对数
  • TF-IDF = TF × IDF,值越大表示该词对文档越重要
  • TF‑IDF 高 = 本篇经常出现,其他文档很少出现 → 区分度强,就是关键词。
from sklearn.feature_extraction.text import TfidfVectorizer

transfer = TfidfVectorizer(stop_words=['一种', '不会', '不要'])
data = transfer.fit_transform(text_list)
print("文本特征抽取的结果:\n", data.toarray())
print("返回特征名字:\n", transfer.get_feature_names())

4.2 特征预处理

通过转换函数将特征数据转换成更适合算法模型的数据。核心目标:无量纲化,避免数值范围大的特征主导模型。

4.2.1 归一化(MinMaxScaler)

将数据映射到 [0, 1](或指定区间):

from sklearn.preprocessing import MinMaxScaler

data = pd.read_csv("dating.txt")
transfer = MinMaxScaler(feature_range=(2, 3))
data = transfer.fit_transform(data[['milage', 'Liters', 'Consumtime'])
print("归一化处理的结果:\n", data)

输出是 numpy 二维数组,每一行是一条样本,三列分别对应 milage、Liters、Consumtime,所有数值都落在 [2, 3]

归一化的局限: 最大值和最小值非常容易受异常点影响,鲁棒性较差,只适合传统精确小数据场景。

4.2.2 标准化(StandardScaler)

将数据变换为均值为 0、标准差为 1 的范围:

from sklearn.preprocessing import StandardScaler

data = pd.read_csv("dating.txt")
transfer = StandardScaler()
data = transfer.fit_transform(data[['milage', 'Liters', 'Consumtime']])
print("标准化的结果:\n", data)
print("每一列特征的平均值:\n", transfer.mean_)
print("每一列特征的方差:\n", transfer.var_)
方法公式对异常值的鲁棒性适用场景
归一化(x - min) / (max - min)差(受极值影响大)传统精确小数据
标准化(x - mean) / σ好(少量异常点影响小)现代嘈杂大数据场景

4.3 特征降维

4.3.1 维数灾难

随着特征维数增加,计算量呈指数倍增长,模型的性能会先上升后下降。降维能减少冗余特征、降低计算难度、增加数据可读性。

4.3.2 低方差特征过滤(Filter)

方差小 → 特征值大多相近 → 信息量少 → 可删除。

from sklearn.feature_selection import VarianceThreshold

X = [[0, 2, 0, 3], [0, 1, 4, 3], [0, 1, 1, 3]]
selector = VarianceThreshold(threshold=0)
selector.fit_transform(X)
# 删除所有样本中具有相同值的特征(方差为0的列)

4.3.3 主成分分析(PCA)

将高维数据转化为低维数据,通过找到一个合适的直线/平面进行矩阵运算,舍弃部分信息但保留大部分方差。

from sklearn.decomposition import PCA

data = np.array([
    (-1, -2), (-1, 0), (0, 0), (2, 1), (0, 1)
])
pca = PCA(n_components=1)  # 降到1维
data_reduced = pca.fit_transform(data)
print("降维后数据:\n", data_reduced)

将一个二维的平面的点映射到一条一维的直线上面

n_components 参数:维度,小数表示保留百分之多少的信息,整数表示减少到多少特征。


五、核心算法讲解

5.1 K-近邻算法(KNN)

算法原理

如果一个样本在特征空间中与 k 个最相似的样本中的大多数属于某一类别,则该样本也属于该类别。"邻居"来推断你的类别。

KNN 三要素
  • k 值选择: 最近邻居的数量
  • 距离度量: 常用欧氏距离
  • 决策规则: 多数表决(分类)或均值(回归)
算法流程
  1. 计算测试对象到训练集中每个对象的距离
  2. 按照距离的远近排序
  3. 选取距离最近的 k 个训练对象作为邻居
  4. 统计这 k 个邻居的类别频次
  5. 频次最高的类别即为预测类别

API 与代码示例
from sklearn.neighbors import KNeighborsClassifier

# 定义电影数据集:特征(打斗镜头, 接吻镜头), 标签
movies = [
    {"features": (3, 104), "label": "爱情片"},
    {"features": (2, 100), "label": "爱情片"},
    {"features": (1, 81),  "label": "爱情片"},
    {"features": (101, 10), "label": "动作片"},
    {"features": (99, 5),   "label": "动作片"},
    {"features": (98, 2),   "label": "动作片"},
]

movies_df = pd.DataFrame(movies)
X = np.array(movies_df["features"].tolist())  # 特征矩阵:6行2列
y = movies_df["label"]

new_movie = np.array([[18, 90]])  # 新电影特征,必须是二维数组

knn = KNeighborsClassifier(n_neighbors=3, algorithm='auto')
knn.fit(X, y)
predicted_label = knn.predict(new_movie)
print(f"新电影的预测类型是: {predicted_label[0]}")

API: sklearn.neighbors.KNeighborsClassifier(n_neighbors=5, algorithm='auto')

algorithm 可选 'auto''ball_tree''kd_tree''brute',不同实现方式影响效率。

实战:预测签到位置
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier

def knncls():
    # 1. 读取数据,缩小数据范围
    data = pd.read_csv("train.csv")
    data = data.query("x > 1.0 & x < 1.25 & y > 2.5 & y < 2.75")
    data = data.drop(['time'], axis=1)

    # 2. 删除签到次数少于3次的位置
    place_count = data.groupby('place_id').count()
    tf = place_count[place_count.row_id > 3].reset_index()
    data = data[data['place_id'].isin(tf.place_id)]

    # 3. 取出特征值和目标值
    y = data['place_id']
    x = data.drop(['place_id', 'row_id'], axis=1)

    # 4. 数据分割与标准化
    x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3)
    std = StandardScaler()
    x_train = std.fit_transform(x_train)
    x_test = std.transform(x_test)  # 测试集用训练集的参数标准化

    # 5. KNN 训练与预测
    knn = KNeighborsClassifier(n_neighbors=10)
    knn.fit(x_train, y_train)
    print("准确率为:", knn.score(x_test, y_test))

关键细节: 测试集必须使用 transform(而非 fit_transform),否则会造成信息泄露。K 值理论上取 √(样本数),实际通过参数调优试出最优值。


5.2 K-means 聚类算法

算法概述

K-means 是最普及的无监督学习聚类算法。它使用没有标签的数据,将数据聚类成 K 个不重叠的组,使簇内点尽可能相似,簇间尽可能分离。

算法流程
  1. 选择 K 个点作为初始质心
  2. 将每个点指派到最近的质心,形成 K 个簇
  3. 对每个簇进行平均计算,得出新的聚类中心
  4. 重复步骤2-3,直到质心不发生变化

K 值的选择:肘部法则

遍历不同 K 值,绘制 inertia(簇内平方和)曲线。当代价函数值下降速率骤减的拐点即为最优 K。

性能评估:轮廓系数

  • 轮廓系数越接近 1:聚类越合理
  • 接近 0:样本在边界上
  • 接近 -1:应该分类到其他簇
完整代码示例
import pandas as pd
import numpy as np
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
import matplotlib.pyplot as plt

# ===================== 1. 数据加载 =====================
np.random.seed(0)
data = pd.read_csv('data.csv')
X = data.drop(['labels'], axis=1)
y = data['labels']

# ===================== 2. 肘部法则选最优k =====================
loss = []
k_range = range(2, 10)
for k in k_range:
    model = KMeans(n_clusters=k, random_state=0)
    model.fit(X)
    loss.append(model.inertia_)

plt.figure(figsize=(8, 4))
plt.plot(k_range, loss, marker='o', color='b', linewidth=1.5)
plt.xlabel('聚类数 k')
plt.ylabel('惯性值(Inertia)')
plt.title('肘部法则选择最优k')
plt.grid(alpha=0.3)
plt.show()

# ===================== 3. K-means模型训练 =====================
km_model = KMeans(n_clusters=3, random_state=0)
km_model.fit(X)
centers = km_model.cluster_centers_

# ===================== 4. 预测与标签矫正 =====================
test_sample = np.array([[80, 60]])
y_predict_test = km_model.predict(test_sample)
y_predict = km_model.predict(X)

# K-means标签是随机编号,需和真实标签匹配矫正
y_corrected = [1 if i==0 else 2 if i==1 else 0 for i in y_predict]
y_corrected = np.array(y_corrected)

# ===================== 5. 模型评估 =====================
sil_score = silhouette_score(X, km_model.labels_)
print(f"聚类轮廓系数:{sil_score:.4f}")

# ===================== 6. 对比可视化 =====================
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
ax1.scatter(X['V1'][y_corrected==0], X['V2'][y_corrected==0], label='label0', alpha=0.6, s=20)
ax1.scatter(X['V1'][y_corrected==1], X['V2'][y_corrected==1], label='label1', alpha=0.6, s=20)
ax1.scatter(X['V1'][y_corrected==2], X['V2'][y_corrected==2], label='label2', alpha=0.6, s=20)
ax1.scatter(centers[:, 0], centers[:, 1], c='red', marker='*', s=200, label='聚类中心')
ax1.set_title("矫正后预测标签")
ax1.legend(); ax1.grid(alpha=0.3)

ax2.scatter(X['V1'][y==0], X['V2'][y==0], label='label0', alpha=0.6, s=20)
ax2.scatter(X['V1'][y==1], X['V2'][y==1], label='label1', alpha=0.6, s=20)
ax2.scatter(X['V1'][y==2], X['V2'][y==2], label='label2', alpha=0.6, s=20)
ax2.set_title("真实标签")
ax2.legend(); ax2.grid(alpha=0.3)
plt.tight_layout()
plt.show()

K-means API: sklearn.cluster.KMeans(n_clusters=8, init='k-means++')

关键属性:labels_(聚类标签)、cluster_centers_(聚类中心)、inertia_(总惯性值)

评估 API:sklearn.metrics.silhouette_score(X, labels)


5.3 决策树算法

算法原理

决策树思想的来源非常朴素 —— 程序设计中的 if-then 条件分支结构。它不再依赖领域专家,而是直接从数据中自动归纳总结分类规则。

信息熵与信息增益

以猜 32 支球队冠军为例:不知任何信息时需要 log₂32 = 5 比特的代价。信息和消除不确定性是相联系的 —— 获得的信息越多,不确定性越小。

  • 信息熵: 衡量信息的不确定程度
  • 信息增益: 得知某个特征后,事件不确定性下降的程度。信息增益越大,该特征的分类能力越强

决策树的优劣: 优点 — 简单易懂、可可视化、无需归一化;缺点 — 容易过拟合。改进方向 — 随机森林。

API
class sklearn.tree.DecisionTreeClassifier(
    criterion='gini',       # 'gini'基尼系数 或 'entropy'信息增益
    max_depth=None,         # 树的深度
    random_state=None       # 随机数种子
)
实战一:鸢尾花分类
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier, plot_tree
import matplotlib.pyplot as plt

iris = load_iris()
X = iris['data']
y = iris['target']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

tree = DecisionTreeClassifier(max_depth=5, random_state=42)
tree.fit(X_train, y_train)

# 预测与准确率
a = tree.predict(X_test)
b = tree.score(X_test, y_test)

# 决策树可视化
plt.figure(figsize=(12, 8))
plot_tree(tree, feature_names=['sepal length', 'sepal width',
           'petal length', 'petal width'],
          class_names=['0', '1', '2'], filled=True, rounded=True)
实战二:银行贷款分类
import pandas as pd
from sklearn.tree import DecisionTreeClassifier, export_text, plot_tree
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report
from sklearn.preprocessing import LabelEncoder

# 创建数据
data = {
    'ID': [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],
    '年龄': ['青年','青年','青年','青年','青年','中年','中年','中年','中年','中年','老年','老年','老年','老年','老年'],
    '有工作': ['否','否','是','是','否','否','否','是','否','否','否','否','是','是','否'],
    '有自己的房子': ['否','否','否','是','否','否','否','是','是','是','是','是','否','否','否'],
    '信贷情况': ['一般','好','好','一般','一般','一般','好','好','非常好','非常好','非常好','好','好','非常好','一般'],
    '类别': ['否','否','是','是','否','否','否','是','是','是','是','是','是','是','否']
}
df = pd.DataFrame(data)

# LabelEncoder 编码分类特征
le_age = LabelEncoder()
le_work = LabelEncoder()
le_house = LabelEncoder()
le_credit = LabelEncoder()
le_target = LabelEncoder()

df['年龄'] = le_age.fit_transform(df['年龄'])
df['有工作'] = le_work.fit_transform(df['有工作'])
df['有自己的房子'] = le_house.fit_transform(df['有自己的房子'])
df['信贷情况'] = le_credit.fit_transform(df['信贷情况'])
df['类别'] = le_target.fit_transform(df['类别'])

X = df.drop(['ID', '类别'], axis=1)
y = df['类别']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 创建并训练决策树(使用信息增益)
dt = DecisionTreeClassifier(criterion='entropy', max_depth=3, random_state=42)
dt.fit(X_train, y_train)

# 评估
y_pred = dt.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"模型准确率: {accuracy:.2f}")
print(classification_report(y_test, y_pred))

# 可视化
plt.figure(figsize=(12, 8))
plot_tree(dt, feature_names=list(X.columns), class_names=['否', '是'], filled=True)
plt.title("银行贷款决策树")
plt.show()

# 示例预测
sample = pd.DataFrame({
    '年龄': [le_age.transform(['中年'])[0]],
    '有工作': [le_work.transform(['是'])[0]],
    '有自己的房子': [le_house.transform(['否'])[0]],
    '信贷情况': [le_credit.transform(['一般'])[0]]
})
prediction = dt.predict(sample)
print(f"预测结果: {'批准' if prediction[0] == 1 else '不批准'}")

5.4 随机森林算法

集成学习与 Bagging

集成学习通过训练多个估计器,结合器整合多个结果作为最终输出。Bagging(自助聚集)是其中一种:从训练集中有放回抽样生成多个子训练集,分别训练基模型后综合预测。

随机森林原理

随机森林 = 以决策树为基估计器的 Bagging 算法。每次数据集是随机有放回选出,同时随机选出部分特征作为输入,因此称为"随机森林"。

两个"为什么": ① 为什么随机抽样?如果不抽样,每棵树训练集相同,结果完全一样。 ② 为什么有放回?保证每棵树有差异,最终通过投票降低关联性,缓解过拟合。

目的是很多棵不一样的决策树,一起投票做预测,双重随机,抗过拟合!

算法步骤
遍历随机森林大小 K 次:
    从训练集 T 中有放回抽样 N 次,形成新子训练集 D
    随机选择 m 个特征(m < M)
    使用 D 和 m 个特征,学习出一棵完整的决策树
得到随机森林

m 的选择:分类问题取 √M 个特征,回归问题取 M/3(不少于5个)。

API
class sklearn.ensemble.RandomForestClassifier(
    n_estimators=10,       # 森林中树木数量
    criterion='gini',      # 分割特征测量方法
    max_depth=None,        # 树的最大深度
    max_features='auto',   # 每棵树的最大特征数 sqrt(n_features)
    bootstrap=True,        # 是否放回抽样
    random_state=None,
    min_samples_split=2    # 节点划分最少样本数
)
实战:鸢尾花分类
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split

iris = load_iris()
X = iris.data
y = iris.target

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=4)
model.fit(X_train, y_train)

predictions = model.predict(X_test)
acc = model.score(X_test, y_test)

# 特征重要性分析
import matplotlib.pyplot as plt
print(model.feature_importances_)
plt.barh(iris.feature_names, model.feature_importances_)

进阶实战:乳腺癌预测
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.metrics import (accuracy_score, confusion_matrix,
                            classification_report, roc_curve, auc)
from sklearn.preprocessing import StandardScaler

# 569病例(212恶性/357良性),30个细胞特征
data = load_breast_cancer()
X = pd.DataFrame(data.data, columns=data.feature_names)
y = data.target

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

# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(
    X_scaled, y, test_size=0.2, random_state=42)

# 初始化随机森林(100棵树,深度5)
rf = RandomForestClassifier(n_estimators=100, max_depth=5, random_state=42)

# 5折交叉验证
cv_scores = cross_val_score(rf, X_train, y_train, cv=5)
print(f"Mean CV Accuracy: {np.mean(cv_scores):.2f}")

# 正式训练
rf.fit(X_train, y_train)

# 测试集评估
y_pred = rf.predict(X_test)
y_proba = rf.predict_proba(X_test)[:, 1]
accuracy = accuracy_score(y_test, y_pred)
print(f"Test Accuracy: {accuracy:.2f}")

# 混淆矩阵
cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
           xticklabels=['Benign', 'Malignant'],
           yticklabels=['Benign', 'Malignant'])

# ROC曲线
fpr, tpr, thresholds = roc_curve(y_test, y_proba)
roc_auc = auc(fpr, tpr)
plt.plot(fpr, tpr, label=f'ROC curve (area = {roc_auc:.2f})')

# 特征重要性排序
importances = rf.feature_importances_
indices = np.argsort(importances)[::-1]
plt.bar(range(X.shape[1]), importances[indices], align="center")
plt.xticks(range(X.shape[1]), data.feature_names[indices], rotation=90)

医疗场景提醒: 混淆矩阵中假阴性(恶性判为良性)比假阳性更危险!AUC接近1表示模型区分能力极强。

随机森林优点随机森林缺点
• 高准确度分类器• 牺牲了决策树的可解释性
• 可处理大量输入变量• 噪声大时可能过拟合
• 可评估变量重要性• 多分类变量问题中可能无法提升基学习器准确性
• 内部估计泛化误差
• 可处理缺失数据
• 对不平衡数据可平衡误差
• 学习过程快速

5.5 专家系统

概念

专家系统是最早的通用人工智能系统,将人类专家的领域知识转化为形式化的知识库模型,依托基础逻辑推导规则开展推理运算,模拟人类专家的推理思路与决策过程。

正向推理(数据驱动)
# 定义产生式规则
rules = [
    '有羽毛 => 鸟类',
    '产乳 => 哺乳动物',
    '鸟类 and 会飞行 => 飞禽',
    '飞禽 and 脖子长 => 仙鹤',
    '哺乳动物 and 吃草 => 食草动物',
    '食草动物 and 脖子长 => 长颈鹿'
]

def parse_rules(rules):
    parsed_rules = []
    for rule in rules:
        conditions, result = rule.split(' => ')
        conditions = conditions.split(' and ')
        parsed_rules.append((conditions, result))
    return parsed_rules

def forward_chain(rules, facts):
    has_new_fact = True
    while has_new_fact:
        has_new_fact = False
        for rule in rules:
            condition_met = all([x in facts for x in rule[0]])
            if not condition_met:
                continue
            has_new_fact = rule[1] not in facts
            if has_new_fact:
                facts.append(rule[1])
                print(rule[1])
                break

forward_chain(parse_rules(rules), ['会飞行', '有羽毛', '脖子长'])
# 输出:鸟类 → 飞禽 → 仙鹤
逆向推理(目标驱动)
def backward_chain(rules, facts, hypo):
    # 终止条件1:假设已在事实中
    if hypo in facts:
        return
    some_rule_applies = False
    for rule in rules:
        if rule[1] != hypo:
            continue
        some_rule_applies = True
        condition_met = all([x in facts for x in rule[0]])
        if condition_met:
            facts.append(rule[1])
            return
        # 条件不满足,递归验证子条件
        for fact in rule[0]:
            if fact in facts:
                continue
            backward_chain(rules, facts, fact)
    # 终止条件2:无规则能推导假设
    if not some_rule_applies:
        print('{0}?'.format(hypo))

backward_chain(parse_rules(rules), ['脖子长'], '长颈鹿')

专家系统的核心挑战
  • 知识获取难题: 领域专家时间成本高,知识库一致性和完备性难保障
  • 系统性能瓶颈: 基于LISP等语言,解释执行效率低
  • 计算复杂度困境: 规则验证本质为NP完全问题,计算复杂度随规则数指数增长

正因上述局限,传统专家系统逐渐被基于统计理论的机器学习方法取代。


六、模型优化

6.1 模型选择与调优

交叉验证(Cross Validation)

将训练数据分为训练集和验证集,多次更换验证集取平均结果,使模型评估更准确可信。

使用验证集目的是防止过拟合,每训练一部分模型就进行测试

超参数搜索 — 网格搜索(Grid Search)

对模型预设几种超参数组合,每组用交叉验证评估,最后选出最优参数。

API: sklearn.model_selection.GridSearchCV(estimator, param_grid, cv)

  • estimator:估计器对象
  • param_grid:参数字典,如 {"n_neighbors": [1, 3, 5]}
  • cv:几折交叉验证
  • 结果属性:best_score_(最佳得分)、best_estimator_(最优模型)、cv_results_(每次验证结果)
代码示例
import numpy as np
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.neighbors import KNeighborsClassifier

# 电影数据集(扩展至16条)
movies = [
    {"features": (3, 104), "label": "爱情片"},
    {"features": (2, 100), "label": "爱情片"},
    # ...(省略部分数据)
    {"features": (76, 1), "label": "动作片"},
]
movies_df = pd.DataFrame(movies)
X = np.array(movies_df["features"].tolist())
y = movies_df["label"]
new_movie = np.array([[18, 90]])

# 网格搜索 + 交叉验证
knn = KNeighborsClassifier()
param = {"n_neighbors": [3, 5, 7]}
gc = GridSearchCV(knn, param_grid=param, cv=2)
gc.fit(X, y)

predicted_label = gc.predict(new_movie)
print(f"新电影的预测类型是: {predicted_label[0]}")
print("交叉验证最好结果:", gc.best_score_)
print("最优K值:", gc.best_estimator_)
print("每次交叉验证结果:", gc.cv_results_)

6.2 模型保存与加载

训练完成后保存模型参数,可避免重复训练、便于部署迁移、支持版本控制。

方法特点适用场景
joblib对大型数值数组处理高效含大量numpy数组的模型(SVM、随机森林等)
picklePython内置,通用性好较小模型或常规Python对象
使用 joblib
import joblib
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC

# 加载数据
data = load_iris()
X, y = data.data, data.target
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42)

# 训练模型
model = SVC(kernel='linear')
model.fit(X_train, y_train)

# 保存模型
joblib.dump(model, 'svm_model.joblib')

# 加载模型
loaded_model = joblib.load('svm_model.joblib')
y_pred = loaded_model.predict(X_test)
print("Predictions:", y_pred)
使用 pickle
import pickle

# 保存
with open('svm_model.pkl', 'wb') as f:
    pickle.dump(model, f)

# 加载
with open('svm_model.pkl', 'rb') as f:
    loaded_model = pickle.load(f)

y_pred = loaded_model.predict(X_test)
print("Predictions:", y_pred)

总结

本篇博客系统梳理了机器学习从概念定义 → 开发流程 → 数据集准备 → 特征工程 → 核心算法(KNN、K-means、决策树、随机森林、专家系统)→ 模型优化(交叉验证、网格搜索、模型持久化)的完整知识链条。

核心要点回顾:

模块核心内容
什么是机器学习定义、AI/ML/DL关系、算法分类(分类/回归/聚类)
开发流程6阶段全景表(数据获取→处理→特征工程→训练→评估→部署)
数据集与sklearn数据集概念、来源、API用法、训练集/测试集划分
特征工程字典/文本(TF-IDF)提取、归一化vs标准化、方差过滤与PCA
核心算法KNN、K-means、决策树、随机森林、专家系统
模型优化交叉验证、网格搜索(GridSearchCV)、joblib/pickle保存加载

如果本文对你有帮助,欢迎点赞收藏,也欢迎在评论区交流讨论!

更多推荐