机器学习基础知识
目录
一、什么是机器学习
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 可用数据集来源
| 来源 | 网址 | 特点 |
|---|---|---|
| Kaggle | Checking your browser - reCAPTCHA | 竞赛数据集丰富,含真实业务数据 |
| UCI | UCI Machine Learning Repository | 经典学术数据集,种类多 |
| Scikit-learn | scikit-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 值选择: 最近邻居的数量
- 距离度量: 常用欧氏距离
- 决策规则: 多数表决(分类)或均值(回归)
算法流程
- 计算测试对象到训练集中每个对象的距离
- 按照距离的远近排序
- 选取距离最近的 k 个训练对象作为邻居
- 统计这 k 个邻居的类别频次
- 频次最高的类别即为预测类别

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 个不重叠的组,使簇内点尽可能相似,簇间尽可能分离。

算法流程
- 选择 K 个点作为初始质心
- 将每个点指派到最近的质心,形成 K 个簇
- 对每个簇进行平均计算,得出新的聚类中心
- 重复步骤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、随机森林等) |
| pickle | Python内置,通用性好 | 较小模型或常规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保存加载 |
如果本文对你有帮助,欢迎点赞收藏,也欢迎在评论区交流讨论!
更多推荐


所有评论(0)