一、机器学习概述

获取数据、数据处理、特征工程后,就可以交给预估器进行机器学习,流程和常用API如下。

1.实例化预估器(估计器)对象(estimator), 预估器对象很多,都是estimator的子类

(1)用于分类的预估器

sklearn.neighbors.KNeighborsClassifier k-近邻
sklearn.naive_bayes.MultinomialNB 贝叶斯
sklearn.linear_model.LogisticRegressioon 逻辑回归
sklearn.tree.DecisionTreeClassifier 决策树
sklearn.ensemble.RandomForestClassifier 随机森林
  • KNeighborsClassifier:k-近邻分类器

    • 基于距离度量,通过邻居投票决定类别

    • 适用于小数据集、特征间距离有意义的场景

  • MultinomialNB:多项式朴素贝叶斯

    • 基于贝叶斯定理,假设特征条件独立

    • 适用于文本分类等离散特征场景

  • LogisticRegression:逻辑回归

    • 线性分类模型,输出概率值

    • 适用于二分类和多分类问题

  • DecisionTreeClassifier:决策树分类器

    • 基于树结构的if-then规则

    • 可解释性强,容易过拟合

  • RandomForestClassifier:随机森林分类器

    • 多个决策树的集成方法

    • 抗过拟合,适用于大多数分类问题

(2)用于回归的预估器

sklearn.linear_model.LinearRegression线性回归
sklearn.linear_model.Ridge岭回归
  • LinearRegression:线性回归

    • 拟合线性关系:y = wTx + b

    • 适用于特征与目标呈线性关系的场景

  • Ridge:岭回归(L2正则化线性回归)

    • 在线性回归基础上加入L2正则项

    • 适用于特征存在共线性的情况

(3)用于无监督学习的预估器

    sklearn.cluster.KMeans 聚类
  • KMeans:K均值聚类

    • 将数据划分为K个簇

    • 适用于客户分群、图像分割等场景

二、KNN算法 - 分类

K-近邻算法(K-Nearest Neighbors,简称KNN)是一种基本的分类和回归方法。它的核心思想是"近朱者赤,近墨者黑"——通过计算待分类样本与训练集中各个样本的距离,找出距离最近的K个邻居,然后根据这K个邻居的类别来判断待分类样本的类别。

K-近邻算法(K-Nearest Neighbors,简称KNN),根据K个邻居样本的类别来判断当前样本的类别;

如果一个样本在特征空间中的k个最相似(最邻近)样本中的大多数属于某个类别,则该类本也属于这个类别。

比如: 有10000个样本,选出7个到样本A的距离最近的,然后这7个样本中假设:类别1有2个,类别2有3个,类别3有2个.那么就认为A样本属于类别2,因为它的7个邻居中 类别2最多(近朱者赤近墨者黑)

1.工作原理

  1. 计算待分类样本与训练集中所有样本的距离

  2. 选取距离最近的K个样本作为邻居

  3. 统计这K个邻居中各类别的数量

  4. 将待分类样本归为数量最多的那个类别

2.距离度量方式

明可夫斯基距离 欧式距离,明可夫斯基距离的特殊情况 曼哈顿距离,明可夫斯基距离的特殊情况

  1. 欧式距离:最常用的距离度量方式,是明可夫斯基距离在p=2时的特例

    • 公式:√(Σ(x_i - y_i)²)

  2. 曼哈顿距离:明可夫斯基距离在p=1时的特例

    • 公式:Σ|x_i - y_i|

  3. 明可夫斯基距离:更一般的距离公式

    • 公式:(Σ|x_i - y_i|p)(1/p)

3.KNN缺点

  1. 计算量大:对于大规模数据集,需要计算测试样本与所有训练样本的距离

  2. 维度灾难:在高维空间中,距离度量可能变得不那么有意义

  3. 需要选择合适的K值:K值过小容易过拟合,K值过大容易欠拟合

  4. 对不平衡数据敏感:少数类样本容易被多数类淹没

  5. 需要特征缩放:不同量纲的特征会影响距离计算

4.API

class sklearn.neighbors.KNeighborsClassifier(n_neighbors=5, algorithm='auto')
  • n_neighbors: int, default=5, 默认情况下用于kneighbors查询的近邻数,就是K

  • algorithm:{‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’}, default=’auto’。找到近邻的方式,注意不是计算距离的方式,与机器学习算法没有什么关系,开发中请使用默认值'auto'。方法:

    • fit(x, y) 使用X作为训练数据和y作为目标数据

    • (2) predict(X) 预测提供的数据,得到预测数据

示例:

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
​
# 1. 加载数据
iris = load_iris()
X = iris.data  # 特征 (萼片长宽、花瓣长宽)
y = iris.target  # 目标 (三种鸢尾花)
​
# 2. 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
​
# 3. 创建KNN分类器 (使用默认参数:n_neighbors=5)
knn = KNeighborsClassifier()
​
# 4. 训练模型
knn.fit(X_train, y_train)
​
# 5. 预测测试集
y_pred = knn.predict(X_test)
​
# 6. 评估模型
accuracy = accuracy_score(y_test, y_pred)
print(f"模型准确率: {accuracy:.2f}")
​
# 7. 预测新样本
new_sample = [[5.1, 3.5, 1.4, 0.2]]  # 新花的特征
predicted_class = knn.predict(new_sample)
print(f"预测类别: {iris.target_names[predicted_class][0]}")
​
# 输出:
# 模型准确率: 1.00
# 预测类别: setosa

三、模型选择与调优

1.交叉验证

交叉验证:避免"考试作弊"的验证方法

什么是交叉验证?

想象你是一名学生,老师想测试你的真实水平。如果只用一次考试,可能刚好考到你会的题目,不能反映真实水平。交叉验证就像让你参加多次不同题目的考试,最后取平均成绩。

(1)保留交叉验证HoldOut

(1) 简单划分法(HoldOut)

  • 做法:把数据分成两份,比如70%用于学习(训练集),30%用于考试(测试集)

  • 例子:就像老师随机抽30道题作为期末考试题

  • 缺点

    • 如果题目抽得不好(比如全是难题),成绩就不准确

    • 一大块数据被剥夺了训练模型的机会。

(2)步骤:

  • 随机打乱数据集(避免数据顺序影响划分)。

  • 按比例划分(如 train_size=0.7test_size=0.3)。

  • 在训练集上训练模型

  • 在测试集上评估模型性能(如准确率、F1-score等)。

示例:

#HoldOut 交叉验证的代码示例
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
​
# 加载数据集(以鸢尾花数据集为例)
data = load_iris()
X, y = data.data, data.target
​
# 按 70% 训练集,30% 测试集划分(stratify=y 保证类别比例一致)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, 
    test_size=0.3, 
    random_state=42,  # 固定随机种子,确保可复现
    stratify=y       # 分层抽样(适用于分类任务)
)
​
# 训练模型(随机森林为例)
model = RandomForestClassifier()
model.fit(X_train, y_train)
​
# 预测并评估
y_pred = model.predict(X_test)
print("Accuracy:", accuracy_score(y_test, y_pred))
​
# 输出:
# Accuracy: 0.8888888888888888

(2)K-折交叉验证(K-fold)

K-折交叉验证(K-Fold CV)是一种更稳健的交叉验证方法,通过 多次划分训练集和验证集,充分利用所有数据进行模型训练和评估,适用于 中小规模数据集需要更准确评估模型性能 的场景。

(1)步骤:

  • 将数据集随机划分为 K 个大小相等的子集(Fold)(通常 K=5 或 10)。

  • 进行 K 次训练和验证

    • 每次选取 1 个 Fold 作为验证集,其余 K-1 个 Fold 作为训练集

    • 训练模型并在验证集上评估性能(如准确率、F1-score)。

  • 计算最终性能:取 K 次验证结果的平均值作为模型的最终评估指标。

(2)优点:

  • 数据利用率高:所有数据都参与训练和验证,适合小数据集。

  • 评估更稳健:通过多次实验取平均,减少随机划分带来的偏差。

  • 适用于不平衡数据:可使用 分层K折(Stratified K-Fold) 保持类别比例。

(3)缺点:

  • 计算成本高:需要训练 K 次模型,耗时较长(大数据集不适用)。

  • 不适合时间序列数据:随机划分会破坏时间依赖性(需用时间序列交叉验证)。

示例:

#K-折交叉验证(K-fold)
from sklearn.model_selection import KFold
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
import numpy as np
​
# 示例数据(10个样本)
X = np.arange(10).reshape(10, 1)  # 特征
y = np.array([0, 0, 0, 0, 1, 1, 1, 1, 1, 1])  # 标签
​
# 初始化 K-Fold (K=5)
kf = KFold(n_splits=5, shuffle=True, random_state=42)
​
# 存储每次的准确率
accuracies = []
​
for train_idx, test_idx in kf.split(X):
    X_train, X_test = X[train_idx], X[test_idx]
    y_train, y_test = y[train_idx], y[test_idx]
    
    # 训练模型(随机森林为例)
    model = RandomForestClassifier(random_state=42)
    model.fit(X_train, y_train)
    
    # 预测并计算准确率
    y_pred = model.predict(X_test)
    acc = accuracy_score(y_test, y_pred)
    accuracies.append(acc)
    print(f"验证集索引: {test_idx}, 准确率: {acc:.2f}")
​
# 输出平均准确率
print(f"平均准确率: {np.mean(accuracies):.2f}")
​
# 输出:
# 验证集索引: [1 8], 准确率: 1.00
# 验证集索引: [0 5], 准确率: 1.00
# 验证集索引: [2 7], 准确率: 1.00
# 验证集索引: [4 9], 准确率: 0.50
# 验证集索引: [3 6], 准确率: 1.00
# 平均准确率: 0.90

(3)分层K-交叉验证

分层K-折交叉验证是 K-折交叉验证的改进版,专门用于 分类任务,确保每一折(Fold)中的 类别比例与原始数据集一致,从而避免因随机划分导致某些类别在训练集或验证集中比例失衡的问题。

  • 保持类别比例:每一折的样本类别分布与原始数据集相同(例如原始数据中类别A:B:C=3:2:1,则每一折中也是3:2:1)。

  • 解决数据不平衡问题:尤其适用于 类别不均衡 的数据集(如医疗诊断、欺诈检测等)。

步骤:

  • 统计原始数据的类别比例(如类别A占60%,类别B占40%)。

  • 划分K折:确保每一折中各类别比例与原始数据一致。

  • 训练与验证:依次用每一折作为验证集,其余作为训练集,共进行K次。

  • 计算最终指标:取K次验证结果的平均值(如平均准确率)。

示例:

#分层K-折交叉验证
from sklearn.model_selection import StratifiedKFold
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
import numpy as np
​
# 示例数据(类别比例 1:2:1)
X = np.array([[i] for i in range(12)])  # 特征
y = np.array([0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2])  # 标签(4个类别0,6个类别1,2个类别2)
​
# 初始化分层K折(K=3)
skf = StratifiedKFold(n_splits=3, shuffle=True, random_state=42)
​
# 存储每次的准确率
accuracies = []
​
for fold_idx, (train_idx, test_idx) in enumerate(skf.split(X, y)):
    X_train, X_test = X[train_idx], X[test_idx]
    y_train, y_test = y[train_idx], y[test_idx]
    
    # 打印当前折的类别分布
    print(f"\nFold {fold_idx + 1}:")
    print("训练集类别分布:", np.bincount(y_train))
    print("验证集类别分布:", np.bincount(y_test))
    
    # 训练模型(随机森林为例)
    model = RandomForestClassifier(random_state=42)
    model.fit(X_train, y_train)
    
    # 预测并计算准确率
    y_pred = model.predict(X_test)
    acc = accuracy_score(y_test, y_pred)
    accuracies.append(acc)
    print(f"准确率: {acc:.2f}")
​
# 输出平均准确率
print(f"\n平均准确率: {np.mean(accuracies):.2f}")
​
# 输出:
# Fold 1:
# 训练集类别分布: [2 4 2]
# 验证集类别分布: [1 2 1]
# 准确率: 0.50
​
# Fold 2:
# 训练集类别分布: [2 4 2]
# 验证集类别分布: [1 2 1]
# 准确率: 1.00
​
# Fold 3:
# 训练集类别分布: [2 4 2]
# 验证集类别分布: [1 2 1]
# 准确率: 1.00
​
# 平均准确率: 0.83

(4)其他验证

去除p交叉验证) 留一交叉验证) 蒙特卡罗交叉验证 时间序列交叉验证

(5)API

from sklearn.model_selection import StratifiedKFold

说明:普通K折交叉验证和分层K折交叉验证的使用是一样的 只是引入的类不同

from sklearn.model_selection import KFold

使用时只是KFold这个类名不一样其他代码完全一样

特性 StratifiedKFold KFold
设计目标 分类任务(保持类别比例) 通用任务(回归/分类)
数据划分策略 每折中类别比例与原始数据一致 简单随机划分
输入要求 必须传入标签 y(用于计算类别比例) 只需特征 X
适用场景 不均衡分类数据集 均衡数据或回归任务
from sklearn.model_selection import StratifiedKFold, KFold
​
# 共同参数
strat_kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
kfold = KFold(n_splits=5, shuffle=True, random_state=42)
  • n_splits (int):

    • 折叠次数(默认5),即K值。

  • shuffle (bool):

    • True:划分前打乱数据顺序(避免原始数据分布影响)。

    • False:按原始顺序划分(适用于时间序列数据)。

  • random_state (int):

    • 随机种子,固定后保证每次划分结果一致(可复现性)。

何时用 shuffle=True

  • 当数据本身有顺序规律(如按类别排序)时,需打乱避免偏差。

为什么 StratifiedKFold 需要 y

  • 需计算每折的类别比例,确保与原始数据一致。

回归任务能用分层K折吗?

  • 不能!回归目标为连续值,无法分层。使用 KFoldTimeSeriesSplit(时序数据)。

2.超参数搜索

1. 核心概念

  • 超参数(Hyperparameter): 在模型训练前需要手动设定的参数(如KNN中的k、随机森林的n_estimators),无法通过训练数据自动学习

  • 网格搜索(Grid Search): 通过遍历所有可能的超参数组合,找到最优参数值的自动化方法。

2. 工作原理

  1. 定义参数网格:列出待调参数的候选值(如 k=[1, 3, 5])。

  2. 暴力搜索所有组合:对每一组参数训练模型并评估性能。

  3. 选择最优参数:根据评估指标(如准确率、F1-score)选择最佳组合。

3. 使用场景

  • 模型有多个超参数需要优化(如SVM的Cgamma)。

  • 计算资源充足(参数组合较多时计算成本高)。

示例:

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.neighbors import KNeighborsClassifier
​
# 加载数据
iris = load_iris()
X, y = iris.data, iris.target
​
# 分割数据(保持类别比例)
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y)
​
# 设置参数搜索范围
param_grid = {'n_neighbors': [1, 3, 5, 7, 9, 11]}
​
# 创建搜索器(内置5折交叉验证)
grid = GridSearchCV(KNeighborsClassifier(), param_grid, cv=5)
​
# 执行搜索
grid.fit(X_train, y_train)
​
# 查看结果
print(f"最佳K值: {grid.best_params_}")  # 比如输出:{'n_neighbors': 7}
print(f"验证集平均准确率: {grid.best_score_:.2f}")
​
# 用最佳模型测试
test_score = grid.score(X_test, y_test)
print(f"测试集准确率: {test_score:.2f}")
​
# 输出:
# 最佳K值: {'n_neighbors': 7}
# 验证集平均准确率: 0.98
# 测试集准确率: 0.95

3.sklearn API

class sklearn.model_selection.GridSearchCV(estimator, param_grid)
​
说明:
同时进行交叉验证(CV)、和网格搜索(GridSearch),GridSearchCV实际上也是一个估计器(estimator),同时它有几个重要属性:
      best_params_  最佳参数
      best_score_ 在训练集中的准确率
      best_estimator_ 最佳估计器
      cv_results_ 交叉验证过程描述
      best_index_最佳k在列表中的下标
参数:
    estimator: scikit-learn估计器实例
    param_grid:以参数名称(str)作为键,将参数设置列表尝试作为值的字典
        示例: {"n_neighbors": [1, 3, 5, 7, 9, 11]}
    cv: 确定交叉验证切分策略,值为:
        (1)None  默认5折
        (2)integer  设置多少折
        如果估计器是分类器,使用"分层k-折交叉验证(StratifiedKFold)"。在所有其他情况下,使用KFold。

四、朴素贝叶斯分类

1、贝叶斯分类理论

我们现在用p1(x,y)表示数据点(x,y)属于类别1的概率,用p2(x,y)表示数据点(x,y)属于类别2的概率,那么对于一个新数据点(x,y),可以用下面的规则来判断它的类别:

  • 如果p1(x,y)>p2(x,y),那么类别为1

  • 如果p1(x,y)<p2(x,y),那么类别为2

也就是说,我们会选择高概率对应的类别。这就是贝叶斯决策理论的核心思想,即选择具有最高概率的决策。已经了解了贝叶斯决策理论的核心思想,那么接下来,就是学习如何计算p1和p2概率。

一、机器学习概述

获取数据、数据处理、特征工程后,就可以交给预估器进行机器学习,流程和常用API如下。

1.实例化预估器(估计器)对象(estimator), 预估器对象很多,都是estimator的子类

(1)用于分类的预估器

sklearn.neighbors.KNeighborsClassifier k-近邻
sklearn.naive_bayes.MultinomialNB 贝叶斯
sklearn.linear_model.LogisticRegressioon 逻辑回归
sklearn.tree.DecisionTreeClassifier 决策树
sklearn.ensemble.RandomForestClassifier 随机森林
  • KNeighborsClassifier:k-近邻分类器

    • 基于距离度量,通过邻居投票决定类别

    • 适用于小数据集、特征间距离有意义的场景

  • MultinomialNB:多项式朴素贝叶斯

    • 基于贝叶斯定理,假设特征条件独立

    • 适用于文本分类等离散特征场景

  • LogisticRegression:逻辑回归

    • 线性分类模型,输出概率值

    • 适用于二分类和多分类问题

  • DecisionTreeClassifier:决策树分类器

    • 基于树结构的if-then规则

    • 可解释性强,容易过拟合

  • RandomForestClassifier:随机森林分类器

    • 多个决策树的集成方法

    • 抗过拟合,适用于大多数分类问题

(2)用于回归的预估器

sklearn.linear_model.LinearRegression线性回归
sklearn.linear_model.Ridge岭回归
  • LinearRegression:线性回归

    • 拟合线性关系:y = wTx + b

    • 适用于特征与目标呈线性关系的场景

  • Ridge:岭回归(L2正则化线性回归)

    • 在线性回归基础上加入L2正则项

    • 适用于特征存在共线性的情况

(3)用于无监督学习的预估器

    sklearn.cluster.KMeans 聚类
  • KMeans:K均值聚类

    • 将数据划分为K个簇

    • 适用于客户分群、图像分割等场景

二、KNN算法 - 分类

K-近邻算法(K-Nearest Neighbors,简称KNN)是一种基本的分类和回归方法。它的核心思想是"近朱者赤,近墨者黑"——通过计算待分类样本与训练集中各个样本的距离,找出距离最近的K个邻居,然后根据这K个邻居的类别来判断待分类样本的类别。

K-近邻算法(K-Nearest Neighbors,简称KNN),根据K个邻居样本的类别来判断当前样本的类别;

如果一个样本在特征空间中的k个最相似(最邻近)样本中的大多数属于某个类别,则该类本也属于这个类别。

比如: 有10000个样本,选出7个到样本A的距离最近的,然后这7个样本中假设:类别1有2个,类别2有3个,类别3有2个.那么就认为A样本属于类别2,因为它的7个邻居中 类别2最多(近朱者赤近墨者黑)

1.工作原理

  1. 计算待分类样本与训练集中所有样本的距离

  2. 选取距离最近的K个样本作为邻居

  3. 统计这K个邻居中各类别的数量

  4. 将待分类样本归为数量最多的那个类别

2.距离度量方式

明可夫斯基距离 欧式距离,明可夫斯基距离的特殊情况 曼哈顿距离,明可夫斯基距离的特殊情况

  1. 欧式距离:最常用的距离度量方式,是明可夫斯基距离在p=2时的特例

    • 公式:√(Σ(x_i - y_i)²)

  2. 曼哈顿距离:明可夫斯基距离在p=1时的特例

    • 公式:Σ|x_i - y_i|

  3. 明可夫斯基距离:更一般的距离公式

    • 公式:(Σ|x_i - y_i|p)(1/p)

3.KNN缺点

  1. 计算量大:对于大规模数据集,需要计算测试样本与所有训练样本的距离

  2. 维度灾难:在高维空间中,距离度量可能变得不那么有意义

  3. 需要选择合适的K值:K值过小容易过拟合,K值过大容易欠拟合

  4. 对不平衡数据敏感:少数类样本容易被多数类淹没

  5. 需要特征缩放:不同量纲的特征会影响距离计算

4.API

class sklearn.neighbors.KNeighborsClassifier(n_neighbors=5, algorithm='auto')
  • n_neighbors: int, default=5, 默认情况下用于kneighbors查询的近邻数,就是K

  • algorithm:{‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’}, default=’auto’。找到近邻的方式,注意不是计算距离的方式,与机器学习算法没有什么关系,开发中请使用默认值'auto'。方法:

    • fit(x, y) 使用X作为训练数据和y作为目标数据

    • (2) predict(X) 预测提供的数据,得到预测数据

示例:

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
​
# 1. 加载数据
iris = load_iris()
X = iris.data  # 特征 (萼片长宽、花瓣长宽)
y = iris.target  # 目标 (三种鸢尾花)
​
# 2. 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
​
# 3. 创建KNN分类器 (使用默认参数:n_neighbors=5)
knn = KNeighborsClassifier()
​
# 4. 训练模型
knn.fit(X_train, y_train)
​
# 5. 预测测试集
y_pred = knn.predict(X_test)
​
# 6. 评估模型
accuracy = accuracy_score(y_test, y_pred)
print(f"模型准确率: {accuracy:.2f}")
​
# 7. 预测新样本
new_sample = [[5.1, 3.5, 1.4, 0.2]]  # 新花的特征
predicted_class = knn.predict(new_sample)
print(f"预测类别: {iris.target_names[predicted_class][0]}")
​
# 输出:
# 模型准确率: 1.00
# 预测类别: setosa

三、模型选择与调优

1.交叉验证

交叉验证:避免"考试作弊"的验证方法

什么是交叉验证?

想象你是一名学生,老师想测试你的真实水平。如果只用一次考试,可能刚好考到你会的题目,不能反映真实水平。交叉验证就像让你参加多次不同题目的考试,最后取平均成绩。

(1)保留交叉验证HoldOut

(1) 简单划分法(HoldOut)

  • 做法:把数据分成两份,比如70%用于学习(训练集),30%用于考试(测试集)

  • 例子:就像老师随机抽30道题作为期末考试题

  • 缺点

    • 如果题目抽得不好(比如全是难题),成绩就不准确

    • 一大块数据被剥夺了训练模型的机会。

(2)步骤:

  • 随机打乱数据集(避免数据顺序影响划分)。

  • 按比例划分(如 train_size=0.7test_size=0.3)。

  • 在训练集上训练模型

  • 在测试集上评估模型性能(如准确率、F1-score等)。

示例:

#HoldOut 交叉验证的代码示例
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
​
# 加载数据集(以鸢尾花数据集为例)
data = load_iris()
X, y = data.data, data.target
​
# 按 70% 训练集,30% 测试集划分(stratify=y 保证类别比例一致)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, 
    test_size=0.3, 
    random_state=42,  # 固定随机种子,确保可复现
    stratify=y       # 分层抽样(适用于分类任务)
)
​
# 训练模型(随机森林为例)
model = RandomForestClassifier()
model.fit(X_train, y_train)
​
# 预测并评估
y_pred = model.predict(X_test)
print("Accuracy:", accuracy_score(y_test, y_pred))
​
# 输出:
# Accuracy: 0.8888888888888888

(2)K-折交叉验证(K-fold)

K-折交叉验证(K-Fold CV)是一种更稳健的交叉验证方法,通过 多次划分训练集和验证集,充分利用所有数据进行模型训练和评估,适用于 中小规模数据集需要更准确评估模型性能 的场景。

(1)步骤:

  • 将数据集随机划分为 K 个大小相等的子集(Fold)(通常 K=5 或 10)。

  • 进行 K 次训练和验证

    • 每次选取 1 个 Fold 作为验证集,其余 K-1 个 Fold 作为训练集

    • 训练模型并在验证集上评估性能(如准确率、F1-score)。

  • 计算最终性能:取 K 次验证结果的平均值作为模型的最终评估指标。

(2)优点:

  • 数据利用率高:所有数据都参与训练和验证,适合小数据集。

  • 评估更稳健:通过多次实验取平均,减少随机划分带来的偏差。

  • 适用于不平衡数据:可使用 分层K折(Stratified K-Fold) 保持类别比例。

(3)缺点:

  • 计算成本高:需要训练 K 次模型,耗时较长(大数据集不适用)。

  • 不适合时间序列数据:随机划分会破坏时间依赖性(需用时间序列交叉验证)。

示例:

#K-折交叉验证(K-fold)
from sklearn.model_selection import KFold
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
import numpy as np
​
# 示例数据(10个样本)
X = np.arange(10).reshape(10, 1)  # 特征
y = np.array([0, 0, 0, 0, 1, 1, 1, 1, 1, 1])  # 标签
​
# 初始化 K-Fold (K=5)
kf = KFold(n_splits=5, shuffle=True, random_state=42)
​
# 存储每次的准确率
accuracies = []
​
for train_idx, test_idx in kf.split(X):
    X_train, X_test = X[train_idx], X[test_idx]
    y_train, y_test = y[train_idx], y[test_idx]
    
    # 训练模型(随机森林为例)
    model = RandomForestClassifier(random_state=42)
    model.fit(X_train, y_train)
    
    # 预测并计算准确率
    y_pred = model.predict(X_test)
    acc = accuracy_score(y_test, y_pred)
    accuracies.append(acc)
    print(f"验证集索引: {test_idx}, 准确率: {acc:.2f}")
​
# 输出平均准确率
print(f"平均准确率: {np.mean(accuracies):.2f}")
​
# 输出:
# 验证集索引: [1 8], 准确率: 1.00
# 验证集索引: [0 5], 准确率: 1.00
# 验证集索引: [2 7], 准确率: 1.00
# 验证集索引: [4 9], 准确率: 0.50
# 验证集索引: [3 6], 准确率: 1.00
# 平均准确率: 0.90

(3)分层K-交叉验证

分层K-折交叉验证是 K-折交叉验证的改进版,专门用于 分类任务,确保每一折(Fold)中的 类别比例与原始数据集一致,从而避免因随机划分导致某些类别在训练集或验证集中比例失衡的问题。

  • 保持类别比例:每一折的样本类别分布与原始数据集相同(例如原始数据中类别A:B:C=3:2:1,则每一折中也是3:2:1)。

  • 解决数据不平衡问题:尤其适用于 类别不均衡 的数据集(如医疗诊断、欺诈检测等)。

步骤:

  • 统计原始数据的类别比例(如类别A占60%,类别B占40%)。

  • 划分K折:确保每一折中各类别比例与原始数据一致。

  • 训练与验证:依次用每一折作为验证集,其余作为训练集,共进行K次。

  • 计算最终指标:取K次验证结果的平均值(如平均准确率)。

示例:

#分层K-折交叉验证
from sklearn.model_selection import StratifiedKFold
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
import numpy as np
​
# 示例数据(类别比例 1:2:1)
X = np.array([[i] for i in range(12)])  # 特征
y = np.array([0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2])  # 标签(4个类别0,6个类别1,2个类别2)
​
# 初始化分层K折(K=3)
skf = StratifiedKFold(n_splits=3, shuffle=True, random_state=42)
​
# 存储每次的准确率
accuracies = []
​
for fold_idx, (train_idx, test_idx) in enumerate(skf.split(X, y)):
    X_train, X_test = X[train_idx], X[test_idx]
    y_train, y_test = y[train_idx], y[test_idx]
    
    # 打印当前折的类别分布
    print(f"\nFold {fold_idx + 1}:")
    print("训练集类别分布:", np.bincount(y_train))
    print("验证集类别分布:", np.bincount(y_test))
    
    # 训练模型(随机森林为例)
    model = RandomForestClassifier(random_state=42)
    model.fit(X_train, y_train)
    
    # 预测并计算准确率
    y_pred = model.predict(X_test)
    acc = accuracy_score(y_test, y_pred)
    accuracies.append(acc)
    print(f"准确率: {acc:.2f}")
​
# 输出平均准确率
print(f"\n平均准确率: {np.mean(accuracies):.2f}")
​
# 输出:
# Fold 1:
# 训练集类别分布: [2 4 2]
# 验证集类别分布: [1 2 1]
# 准确率: 0.50
​
# Fold 2:
# 训练集类别分布: [2 4 2]
# 验证集类别分布: [1 2 1]
# 准确率: 1.00
​
# Fold 3:
# 训练集类别分布: [2 4 2]
# 验证集类别分布: [1 2 1]
# 准确率: 1.00
​
# 平均准确率: 0.83

(4)其他验证

去除p交叉验证) 留一交叉验证) 蒙特卡罗交叉验证 时间序列交叉验证

(5)API

from sklearn.model_selection import StratifiedKFold

说明:普通K折交叉验证和分层K折交叉验证的使用是一样的 只是引入的类不同

from sklearn.model_selection import KFold

使用时只是KFold这个类名不一样其他代码完全一样

特性 StratifiedKFold KFold
设计目标 分类任务(保持类别比例) 通用任务(回归/分类)
数据划分策略 每折中类别比例与原始数据一致 简单随机划分
输入要求 必须传入标签 y(用于计算类别比例) 只需特征 X
适用场景 不均衡分类数据集 均衡数据或回归任务
from sklearn.model_selection import StratifiedKFold, KFold
​
# 共同参数
strat_kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
kfold = KFold(n_splits=5, shuffle=True, random_state=42)
  • n_splits (int):

    • 折叠次数(默认5),即K值。

  • shuffle (bool):

    • True:划分前打乱数据顺序(避免原始数据分布影响)。

    • False:按原始顺序划分(适用于时间序列数据)。

  • random_state (int):

    • 随机种子,固定后保证每次划分结果一致(可复现性)。

何时用 shuffle=True

  • 当数据本身有顺序规律(如按类别排序)时,需打乱避免偏差。

为什么 StratifiedKFold 需要 y

  • 需计算每折的类别比例,确保与原始数据一致。

回归任务能用分层K折吗?

  • 不能!回归目标为连续值,无法分层。使用 KFoldTimeSeriesSplit(时序数据)。

2.超参数搜索

1. 核心概念

  • 超参数(Hyperparameter): 在模型训练前需要手动设定的参数(如KNN中的k、随机森林的n_estimators),无法通过训练数据自动学习

  • 网格搜索(Grid Search): 通过遍历所有可能的超参数组合,找到最优参数值的自动化方法。

2. 工作原理

  1. 定义参数网格:列出待调参数的候选值(如 k=[1, 3, 5])。

  2. 暴力搜索所有组合:对每一组参数训练模型并评估性能。

  3. 选择最优参数:根据评估指标(如准确率、F1-score)选择最佳组合。

3. 使用场景

  • 模型有多个超参数需要优化(如SVM的Cgamma)。

  • 计算资源充足(参数组合较多时计算成本高)。

示例:

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.neighbors import KNeighborsClassifier
​
# 加载数据
iris = load_iris()
X, y = iris.data, iris.target
​
# 分割数据(保持类别比例)
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y)
​
# 设置参数搜索范围
param_grid = {'n_neighbors': [1, 3, 5, 7, 9, 11]}
​
# 创建搜索器(内置5折交叉验证)
grid = GridSearchCV(KNeighborsClassifier(), param_grid, cv=5)
​
# 执行搜索
grid.fit(X_train, y_train)
​
# 查看结果
print(f"最佳K值: {grid.best_params_}")  # 比如输出:{'n_neighbors': 7}
print(f"验证集平均准确率: {grid.best_score_:.2f}")
​
# 用最佳模型测试
test_score = grid.score(X_test, y_test)
print(f"测试集准确率: {test_score:.2f}")
​
# 输出:
# 最佳K值: {'n_neighbors': 7}
# 验证集平均准确率: 0.98
# 测试集准确率: 0.95

3.sklearn API

class sklearn.model_selection.GridSearchCV(estimator, param_grid)
​
说明:
同时进行交叉验证(CV)、和网格搜索(GridSearch),GridSearchCV实际上也是一个估计器(estimator),同时它有几个重要属性:
      best_params_  最佳参数
      best_score_ 在训练集中的准确率
      best_estimator_ 最佳估计器
      cv_results_ 交叉验证过程描述
      best_index_最佳k在列表中的下标
参数:
    estimator: scikit-learn估计器实例
    param_grid:以参数名称(str)作为键,将参数设置列表尝试作为值的字典
        示例: {"n_neighbors": [1, 3, 5, 7, 9, 11]}
    cv: 确定交叉验证切分策略,值为:
        (1)None  默认5折
        (2)integer  设置多少折
        如果估计器是分类器,使用"分层k-折交叉验证(StratifiedKFold)"。在所有其他情况下,使用KFold。

四、朴素贝叶斯分类

1、贝叶斯分类理论

我们现在用p1(x,y)表示数据点(x,y)属于类别1的概率,用p2(x,y)表示数据点(x,y)属于类别2的概率,那么对于一个新数据点(x,y),可以用下面的规则来判断它的类别:

  • 如果p1(x,y)>p2(x,y),那么类别为1

  • 如果p1(x,y)<p2(x,y),那么类别为2

也就是说,我们会选择高概率对应的类别。这就是贝叶斯决策理论的核心思想,即选择具有最高概率的决策。已经了解了贝叶斯决策理论的核心思想,那么接下来,就是学习如何计算p1和p2概率。

我们把P(A)称为"先验概率"(Prior probability)**,即在B事件发生之前,我们对A事件概率的一个判断。

P(A|B)称为"后验概率"(Posterior probability),即在B事件发生之后,我们对A事件概率的重新评估。

P(B|A)/P(B)称为"可能性函数"(Likelyhood),这是一个调整因子,使得预估概率更接近真实概率。

所以,条件概率可以理解成下面的式子:

后验概率 = 先验概率x调整因子

这就是贝叶斯推断的含义。我们先预估一个"先验概率",然后加入实验结果,看这个实验到底是增强还是削弱了"先验概率",由此得到更接近事实的"后验概率"。

2、朴素贝叶斯推断

朴素贝叶斯是一种基于贝叶斯定理的分类方法,其核心假设是特征之间条件独立(即"朴素"的含义)。

  • 根据贝叶斯定理,后验概率 P(a|X) 可以表示为:

    P(a|X) = \frac{P(X|a)P(a)}{P(X)}

    其中:

    • P(X|a) 是给定类别 ( a ) 下观测到特征向量 X=(x_1, x_2, ..., x_n) 的概率;

    • P(a) 是类别 a 的先验概率;

    • P(X) 是观测到特征向量 X 的边缘概率,通常作为归一化常数处理。

from sklearn.naive_bayes import MultinomialNB
import numpy as np
​
# 特征:天气(晴=0, 阴=1, 雨=2), 温度(高=0, 中=1, 低=2), 湿度(高=0, 中=1), 风力(无=0, 有=1)
X = np.array([
    [0, 0, 0, 0],  # 晴,高,高,无 → 不打球
    [0, 0, 0, 1],  # 晴,高,高,有 → 不打球
    [1, 1, 0, 0],  # 阴,中,高,无 → 打球
    [2, 2, 1, 0]   # 雨,低,中,无 → 打球
])
y = np.array([0, 0, 1, 1])  # 0=不打球, 1=打球
​
# 训练模型
model = MultinomialNB(alpha=1)  # 拉普拉斯平滑
model.fit(X, y)
​
# 预测新样本:雨,低,中,无
new_sample = np.array([[2, 2, 1, 0]])
print("预测结果:", model.predict(new_sample)) 
​
# 输出:
# 预测结果: [1]

3、拉普拉斯平滑系数

拉普拉斯平滑通过给所有特征值的计数加一个小常数,避免零概率问题,使模型更具鲁棒性。

核心作用

解决朴素贝叶斯中零概率问题:当某个特征值在训练集中未出现时,直接计算会导致条件概率为0,进而使整个预测失效。

公式为:

一般α取值1,m的值为总特征数量

通过这种方法,即使某个特征在训练集中从未出现过,它的概率也不会被估计为零,而是会被赋予一个很小但非零的值,从而避免了模型在面对新数据时可能出现的过拟合或预测错误

示例:

#拉普拉斯平滑系数
from sklearn.naive_bayes import CategoricalNB
import numpy as np
​
# 特征编码:颜色(红=0, 黄=1, 绿=2),形状(圆=0, 长=1)
X = np.array([[0, 0], [1, 1], [2, 0]])
y = np.array([0, 1, 0])  # 0=苹果, 1=香蕉
​
# 使用拉普拉斯平滑(alpha=1)
model = CategoricalNB(alpha=1)
model.fit(X, y)
​
# 预测:黄(1), 圆(0)
print(model.predict([[1, 0]]))  
​
# 输出: [0](苹果)

4、API

sklearn.naive_bayes.MultinomialNB()

作用:创建一个多项式朴素贝叶斯分类器对象。 关键参数

  • alpha:拉普拉斯平滑系数(默认1.0)。

  • fit_prior:是否学习类别先验概率(默认True)。

  • class_prior:手动指定类别先验概率(如[0.6, 0.4])。

estimator.fit(x_train, y_train)
  • fit() 方法用于训练模型

  • x_train: 训练数据的特征矩阵(通常是数值型数据)

  • y_train: 训练数据对应的标签/类别

  • 这一步会计算每个类别的先验概率和条件概率

estimator.predict(x_test)

作用:对测试数据进行预测,返回预测类别。 内部过程

  1. 对每个测试样本,计算所有类别的联合概率

  2. 选择概率最大的类别作为预测结果。

  • predict() 方法用训练好的模型对新数据进行预测

  • x_test: 测试数据的特征矩阵(格式应与训练数据相同)

  • y_predict: 预测结果,包含测试集中每个样本的预测类别

我们把P(A)称为"先验概率"(Prior probability)**,即在B事件发生之前,我们对A事件概率的一个判断。

P(A|B)称为"后验概率"(Posterior probability),即在B事件发生之后,我们对A事件概率的重新评估。

P(B|A)/P(B)称为"可能性函数"(Likelyhood),这是一个调整因子,使得预估概率更接近真实概率。

所以,条件概率可以理解成下面的式子:

后验概率 = 先验概率x调整因子

这就是贝叶斯推断的含义。我们先预估一个"先验概率",然后加入实验结果,看这个实验到底是增强还是削弱了"先验概率",由此得到更接近事实的"后验概率"。

2、朴素贝叶斯推断

朴素贝叶斯是一种基于贝叶斯定理的分类方法,其核心假设是特征之间条件独立(即"朴素"的含义)。

  • 根据贝叶斯定理,后验概率 P(a|X) 可以表示为:

    P(a|X) = \frac{P(X|a)P(a)}{P(X)}

    其中:

    • P(X|a) 是给定类别 ( a ) 下观测到特征向量 X=(x_1, x_2, ..., x_n) 的概率;

    • P(a) 是类别 a 的先验概率;

    • P(X) 是观测到特征向量 X 的边缘概率,通常作为归一化常数处理。

from sklearn.naive_bayes import MultinomialNB
import numpy as np
​
# 特征:天气(晴=0, 阴=1, 雨=2), 温度(高=0, 中=1, 低=2), 湿度(高=0, 中=1), 风力(无=0, 有=1)
X = np.array([
    [0, 0, 0, 0],  # 晴,高,高,无 → 不打球
    [0, 0, 0, 1],  # 晴,高,高,有 → 不打球
    [1, 1, 0, 0],  # 阴,中,高,无 → 打球
    [2, 2, 1, 0]   # 雨,低,中,无 → 打球
])
y = np.array([0, 0, 1, 1])  # 0=不打球, 1=打球
​
# 训练模型
model = MultinomialNB(alpha=1)  # 拉普拉斯平滑
model.fit(X, y)
​
# 预测新样本:雨,低,中,无
new_sample = np.array([[2, 2, 1, 0]])
print("预测结果:", model.predict(new_sample)) 
​
# 输出:
# 预测结果: [1]

3、拉普拉斯平滑系数

拉普拉斯平滑通过给所有特征值的计数加一个小常数,避免零概率问题,使模型更具鲁棒性。

核心作用

解决朴素贝叶斯中零概率问题:当某个特征值在训练集中未出现时,直接计算会导致条件概率为0,进而使整个预测失效。

公式为:

一般α取值1,m的值为总特征数量

通过这种方法,即使某个特征在训练集中从未出现过,它的概率也不会被估计为零,而是会被赋予一个很小但非零的值,从而避免了模型在面对新数据时可能出现的过拟合或预测错误

示例:

#拉普拉斯平滑系数
from sklearn.naive_bayes import CategoricalNB
import numpy as np
​
# 特征编码:颜色(红=0, 黄=1, 绿=2),形状(圆=0, 长=1)
X = np.array([[0, 0], [1, 1], [2, 0]])
y = np.array([0, 1, 0])  # 0=苹果, 1=香蕉
​
# 使用拉普拉斯平滑(alpha=1)
model = CategoricalNB(alpha=1)
model.fit(X, y)
​
# 预测:黄(1), 圆(0)
print(model.predict([[1, 0]]))  
​
# 输出: [0](苹果)

4、API

sklearn.naive_bayes.MultinomialNB()

作用:创建一个多项式朴素贝叶斯分类器对象。 关键参数

  • alpha:拉普拉斯平滑系数(默认1.0)。

  • fit_prior:是否学习类别先验概率(默认True)。

  • class_prior:手动指定类别先验概率(如[0.6, 0.4])。

estimator.fit(x_train, y_train)
  • fit() 方法用于训练模型

  • x_train: 训练数据的特征矩阵(通常是数值型数据)

  • y_train: 训练数据对应的标签/类别

  • 这一步会计算每个类别的先验概率和条件概率

estimator.predict(x_test)

作用:对测试数据进行预测,返回预测类别。 内部过程

  1. 对每个测试样本,计算所有类别的联合概率

  2. 选择概率最大的类别作为预测结果。

  • predict() 方法用训练好的模型对新数据进行预测

  • x_test: 测试数据的特征矩阵(格式应与训练数据相同)

  • y_predict: 预测结果,包含测试集中每个样本的预测类别

Logo

更多推荐