基于 sklearn 的均值偏移聚类算法的应用

news2025/2/26 7:30:49

基于 sklearn 的均值偏移聚类算法的应用

在机器学习和数据挖掘中,聚类算法是一类非常重要的无监督学习方法。它的目的是将数据集中的数据点划分为若干个类,使得同一类的样本点彼此相似,而不同类的样本点相互之间差异较大。均值偏移聚类(Mean Shift Clustering)是一种基于密度的聚类方法,可以很好地识别数据中的高密度区域。


1. 什么是均值偏移聚类

均值偏移(Mean Shift)是一种基于密度峰值的无监督聚类算法,最早由 Fukunaga 和 Hostetler 于1975年提出。

均值偏移聚类算法是通过计算数据点的局部均值来不断更新每个数据点的位置,直到所有的数据点都趋于聚集在密度较高的区域。其本质上是一种基于梯度上升的方式,通过对数据点的迭代移动找到最密集的区域,最后将数据点聚集成簇。

与传统的基于距离的聚类方法(如K-means)不同,均值偏移聚类不需要预先指定簇的数量,它自动寻找数据分布的密度极值点进行聚类,能够处理非规则形状的数据分布。

1.1 核心特点

  1. 无需预先指定聚类数量
  2. 自动发现任意形状的簇
  3. 对噪声数据具有健壮性
  4. 基于核密度估计的概率方法

2. 均值偏移的数学模型

2.1 质心候选位置的调整

这段描述了一个迭代过程,称为爬山算法(hill climbing),该过程用于找到估计概率密度的局部最大值。爬山算法是一种启发式搜索方法,通过不断地调整候选解的值,逐步逼近目标的最优解。

给定一个候选质心的位置 x t x^t xt,我们通过以下公式来更新候选质心的位置:
x t + 1 = x t + m ( x t ) x^{t+1} = x^t + m(x^t) xt+1=xt+m(xt)
其中, m ( x t ) m(x^t) m(xt) 是一个均值漂移向量(mean shift vector),它指向数据点密度增加的区域。

2.2 均值漂移向量的计算

均值漂移向量 m ( x t ) m(x^t) m(xt) 是通过计算每个质心所在邻域内的点的均值来更新质心的位置。为了计算这个向量,我们首先定义质心 x t x^t xt 的邻域 N ( x t ) N(x^t) N(xt),即在给定距离范围内的所有样本点。接着,均值漂移向量的计算公式如下:
m ( x ) = 1 ∣ N ( x ) ∣ ∑ x j ∈ N ( x ) x j − x m(x) = \frac{1}{|N(x)|} \sum_{x_j \in N(x)} x_j - x m(x)=N(x)1xjN(x)xjx
其中: N ( x ) N(x) N(x) 是质心 x x x 的邻域, x j x_j xj 是邻域内的样本点, ∣ N ( x ) ∣ |N(x)| N(x) 是邻域内样本点的数量, x x x 是当前的质心。

这个公式的意思是:计算邻域内所有点的均值,并通过减去当前质心的位置,得到一个向量。这个向量指示质心应该如何调整位置。

2.3 核函数的使用

通常,均值漂移向量的计算依赖于用于密度估计的核函数。上面给出的均值漂移向量公式是一个通用的公式
m ( x ) = ∑ x j ∈ N ( x ) K ( x j − x ) x j ∑ x j ∈ N ( x ) K ( x j − x ) − x m(x) = \frac{\sum_{x_j \in N(x)} K(x_j - x) x_j}{\sum_{x_j \in N(x)} K(x_j - x)} - x m(x)=xjN(x)K(xjx)xjN(x)K(xjx)xjx
其中, K ( x j − x ) K(x_j - x) K(xjx) 是一个核函数,衡量了每个邻域点 x j x_j xj 与当前质心 x x x 之间的相似度。通过这种方式,质心的更新不仅仅依赖于邻域点的位置,还考虑了每个点的重要性(通过核函数的加权)。

2.4 核函数的特性

在我们的实现中,核函数 K ( x j − x ) K(x_j - x) K(xjx) 的值会根据点 x j x_j xj 与质心 x x x 的距离决定:

  • x j x_j xj x x x 的距离较小(即 K ( x j − x ) K(x_j - x) K(xjx) 较大)时,核函数值为 1。
  • x j x_j xj x x x 的距离较大(即 K ( x j − x ) K(x_j - x) K(xjx) 较小)时,核函数值为 0。

核函数的作用是决定哪些点在质心的邻域内,以及这些点对质心更新的贡献大小。


3. 参数说明

from sklearn.cluster import MeanShift

MeanShift(
    *,
    bandwidth=None,		# 控制邻域大小的核心参数,影响聚类的精度和速度
    seeds=None,			# 控制初始化的方式,可以加速或精确化聚类过程。
    bin_seeding=False,	# 使用分箱方法来选择种子点
    min_bin_freq=1,		# 在分箱方法中每个区域内至少n个样本点才能被选择为种子点
    cluster_all=True,	# 是否将所有数据点都归类为簇,或者标记为噪声点
    n_jobs=None,		# 使得聚类过程能够并行化,从而加速计算
    max_iter=300,		# 设置算法的最大迭代次数,以避免过长的计算时间
)
  1. bandwidth (float)

    • 描述: 这个参数控制用于确定每个点邻域范围的带宽。带宽定义了“邻域”的大小,即每个点在计算均值漂移向量时考虑的邻域半径。如果未指定,则算法会根据数据自动估计合适的带宽。

    • 作用: 影响均值漂移的结果,带宽越大,每个质心的“邻域”越大,算法可能会合并更多的簇;带宽越小,簇会更细致,可能会产生更多的簇。

  2. seeds (array-like)

    • 描述: 用于初始化质心的种子点。如果为 None,默认将会使用数据中的点作为种子点。可以通过传入一个自定义的种子点集合来控制算法的初始化过程。

    • 作用: 影响聚类结果的初始位置,指定种子点后可以加速聚类过程。

  3. bin_seeding (bool)

    • 描述: 如果为 True,则使用分箱方法来选择种子点。分箱方法将数据分成多个小区域,在每个区域中选择一个点作为种子,从而减少计算量。如果为 False,则使用所有数据点作为种子。

    • 作用: 在大规模数据集上可以加速聚类过程,减少计算复杂度。

  4. min_bin_freq (int)

    • 描述: 如果启用了 bin_seeding,则该参数指定了在分箱方法中每个区域内至少需要有多少个样本点才能被选择为种子点。

    • 作用: 影响种子点选择的频率,较高的 min_bin_freq 值将减少种子点的数量。

  5. cluster_all (bool)

    • 描述: 如果为 True,则所有的点都会被归类到某个簇中。如果为 False,则没有找到密度极大值的点会被标记为 -1,表示这些点没有归属于任何簇(类似于离群点)。

    • 作用: 如果设置为 False,会将不符合某个簇条件的点视为噪声或离群点,常用于检测离群点。

  6. n_jobs (int)

    • 描述: 用于并行计算的工作线程数。n_jobs=-1 会使用所有可用的 CPU 核心。默认情况下,None 表示不使用并行计算(即单线程)。

    • 作用: 如果数据量较大,可以设置为 -1 来加速计算过程,利用多核并行处理。

  7. max_iter (int)

    • 描述: 算法的最大迭代次数。在均值漂移过程中,质心会不断地向密度极大值移动,max_iter 限制了算法最多执行多少次迭代。如果算法在达到最大迭代次数之前收敛,算法会提前停止。

    • 作用: 控制算法的计算复杂度和时间。如果数据分布较复杂,可能需要更多的迭代来达到收敛。


4. 均值偏移聚类样例

4.1 生成样例数据并聚类

# 导入必要的库
import numpy as np
from sklearn.cluster import MeanShift, estimate_bandwidth  # 导入均值偏移聚类和带宽估计函数
from sklearn.datasets import make_blobs  # 用于生成模拟数据集的函数

# 定义聚类的中心点
centers = [[1, 1], [-1, -1], [1, -1]]

# 生成模拟数据集,包含10000个样本,指定中心点和簇的标准差
X, _ = make_blobs(n_samples=10000, centers=centers, cluster_std=0.6)

# 使用估计带宽函数自动检测带宽,量化值设为0.2,选择500个样本计算带宽
bandwidth = estimate_bandwidth(X, quantile=0.2, n_samples=500)

# 创建均值偏移聚类对象,并设定带宽和开启二值化种子
ms = MeanShift(bandwidth=bandwidth, bin_seeding=True)

# 对数据进行聚类
ms.fit(X)

# 获取聚类标签和簇中心
labels = ms.labels_
cluster_centers = ms.cluster_centers_

# 获取聚类标签的唯一值,即不同的簇标签
labels_unique = np.unique(labels)

# 获取簇的数量
n_clusters_ = len(labels_unique)

# 输出聚类的估计数量
print("估计的簇数量: %d" % n_clusters_)
# 输出簇中心
print("簇中心为: \n", cluster_centers)

估计的簇数量: 3
簇中心为:
[[ 0.92930747 -0.92997006]
[-0.90712668 -0.97393151]
[ 1.02412056 0.94250739]]

4.2 可视化结果

# 导入绘图工具
import matplotlib.pyplot as plt
import seaborn as sns  # 导入seaborn库来美化图表

sns.set_theme(style="whitegrid", font="SimHei", rc={"axes.unicode_minus": False})  # 设置主题和字体

# 设定颜色和标记符号
colors = ["#dede00", "#377eb8", "#f781bf"]
markers = ["x", "o", "^"]

# 绘制每个簇的样本点,并标记簇的中心
for k, col in zip(range(n_clusters_), colors):
    my_members = labels == k  # 获取属于第k个簇的样本
    cluster_center = cluster_centers[k]  # 获取第k个簇的中心
    plt.plot(X[my_members, 0], X[my_members, 1], markers[k], color=col, label=f"集群 {k+1}", alpha=0.4)  # 绘制簇的样本点
    plt.plot(
        cluster_center[0],
        cluster_center[1],
        markers[k],
        markerfacecolor=col,
        markeredgecolor="k",
        markersize=14,
        # label=f"聚类中心点 {k+1}"  # 绘制簇的中心点
    )

# 设置图表标题
plt.title("均值偏移聚类样例结果")

# 显示图表
plt.legend()  # 显示图例
plt.show()

在这里插入图片描述


5. 均值偏移聚类算法的应用

均值偏移聚类算法在计算机视觉(图像分割、目标追踪、视频分析……)、用户行为分析(电商用户分群、社交网络社区发现、异常检测……)、生物信息学(基因表达数据分析、蛋白质结构分类……)和地理信息系统(卫星图像分析、人口密度研究……)等领域中被广泛应用。

5.1 图像分割

5.1.1 选择图像(flowers-6558487_640)

flowers-6558487_640

5.1.2 导入图片并进行分割
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import seaborn as sns
from sklearn.cluster import MeanShift, estimate_bandwidth
from sklearn.datasets import load_sample_image
from sklearn.preprocessing import StandardScaler

# 设置 Seaborn 样式
sns.set_theme(style="whitegrid", font="SimHei", rc={"axes.unicode_minus": False})  # 设置主题和字体

# 加载示例图像
img = mpimg.imread('flowers-6558487_640.jpg')

# 将图像转换为二维数组,准备聚类
image_data = img.reshape((-1, 3))  # 每个像素点是一个RGB值

# 进行标准化
scaler = StandardScaler()
image_data_scaled = scaler.fit_transform(image_data)

# 估算带宽(bandwidth)
bandwidth = estimate_bandwidth(image_data_scaled, quantile=0.1, n_samples=500)

# 使用均值偏移进行聚类
mean_shift = MeanShift(bandwidth=bandwidth, bin_seeding=True)
mean_shift.fit(image_data_scaled)

# 获取聚类结果
labels = mean_shift.labels_

# 将聚类标签重新映射为图像
segmented_image = labels.reshape(img.shape[:2])

# 显示原图和分割结果
fig, ax = plt.subplots(1, 2, figsize=(12, 10))

ax[0].imshow(img)
ax[0].set_title("原始图像")
ax[0].axis('off')

ax[1].imshow(segmented_image, cmap='jet')
ax[1].set_title("聚类分割结果(MeanShift)")
ax[1].axis('off')

plt.show()

在这里插入图片描述

5.1.3 显示分割结果
# 统计聚类数量
n = len(set(labels))

# 将标签重新变为图像的形状
segmented_image_list = []

# 创建每个簇的分割图像
for cluster in range(n):  # 假设我们有3个簇
    # 创建一个全为0的图像(与原图尺寸一致)
    segmented_image = np.zeros_like(img)
    
    # 将属于该簇的像素赋值为原图像素,其他像素设置为黑色
    # 获取属于该簇的像素的索引
    cluster_pixels = labels == cluster
    # 将符合条件的像素赋值
    segmented_image.reshape(-1, 3)[cluster_pixels] = img.reshape(-1, 3)[cluster_pixels]
    
    # 添加到分割图像列表中
    segmented_image_list.append(segmented_image)

# 创建子图布局
fig, axes = plt.subplots(1, n, figsize=(12, 10))

# 绘制每个聚类的分割图像
for i, ax in enumerate(axes.flat):
    ax.imshow(segmented_image_list[i])  # 显示分割后的图像
    ax.set_title(f'聚类 {i+1}', fontsize=14)  # 设置标题为聚类编号
    ax.axis('off')  # 禁用坐标轴

# 调整布局,防止重叠
plt.tight_layout()
plt.show()

在这里插入图片描述

5.1.4 调整参数

5.1.3 图像可知,黄色花朵被分割为了三个聚类(聚类2、聚类3、聚类4),说明效果不佳,因此调整参数 quantile=0.2

# 估算带宽(bandwidth)
bandwidth = estimate_bandwidth(image_data_scaled, quantile=0.2, n_samples=500)

在这里插入图片描述
在这里插入图片描述


5.2 异常检测

5.2.1 导入鸢尾花数据集并降维
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn import datasets
from sklearn.cluster import MeanShift
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler

# 设置 Seaborn 样式
sns.set_theme(style="whitegrid", font="SimHei", rc={"axes.unicode_minus": False})  # 设置主题和字体

# 加载鸢尾花数据集
iris = datasets.load_iris()
X = iris.data
y = iris.target

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

# PCA降维到2维
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)

# 绘制散点图
plt.figure(figsize=(8, 6))
sns.scatterplot(x=X_pca[:, 0], y=X_pca[:, 1], hue=None, s=100, edgecolor='k', alpha=0.8)
plt.title("鸢尾花数据集", fontsize=16)
plt.xlabel("主成分 1", fontsize=12)
plt.ylabel("主成分 2", fontsize=12)

# 设置网格线为虚线,并设置透明度
plt.grid(color='gray', linestyle='--', linewidth=0.7, alpha=0.5)

# 显示图例
plt.show()

在这里插入图片描述

5.2.2 添加异常数据并进行检测
# 在PCA降维后的数据中添加几个异常值
# 异常值:远离正常数据点
outliers = np.array([[4, 3], [-3, -3], [4, -4]])  # 假设我们人为添加3个异常点
X_pca_with_outliers = np.vstack([X_pca, outliers])

# 使用均值偏移聚类算法
mean_shift = MeanShift(bandwidth=1)
mean_shift.fit(X_pca_with_outliers)

# 获取聚类标签
labels = mean_shift.labels_

# 获取每个簇的大小
unique_labels, counts = np.unique(labels, return_counts=True)
print(f"聚类的簇数量: {len(unique_labels)}")

# 标记异常点
# 异常点的簇大小为1,表示每个簇只包含一个样本
outliers_labels = unique_labels[counts == 1]  # 找出簇大小为1的标签

# 可视化聚类结果
plt.figure(figsize=(8, 6))

# 使用sns.scatterplot进行美化
sns.scatterplot(x=X_pca_with_outliers[:, 0], y=X_pca_with_outliers[:, 1], hue=labels, palette="viridis", s=100, alpha=0.8, edgecolor='k', legend=None)

# 标记异常点
for label in outliers_labels:
    outlier_points = X_pca_with_outliers[labels == label]
    plt.scatter(outlier_points[:, 0], outlier_points[:, 1], color='red', s=100, marker='x', label='异常点')

# 设置图表标题、轴标签
plt.title("均值偏移聚类与异常检测", fontsize=16)
plt.xlabel("主成分 1", fontsize=12)
plt.ylabel("主成分 2", fontsize=12)

# 显示图例
# plt.legend(loc='upper right')
plt.show()

聚类的簇数量: 7

在这里插入图片描述


6. 算法优缺点

优势

  • 自动确定聚类数量
  • 对噪声不敏感
  • 适应任意形状的簇

局限

  • 时间复杂度较高(约O(n²))
  • 带宽选择对结果影响大
  • 不适用于高维数据

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2306232.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

国产OS上完整编译Qt5.15、搭建基本开发环境需要的库

近期有师弟问我国产OS安装Qt5.15编译老是不完整,不是没声音,就是没视频,或者没有xcb。通过QEMU模拟Arm64,闲来20几天摸索,完整编译了Qt5.15,并编译成功了我的SDR玩具taskBus。 1.主要结论: 该O…

MyBatis简明教程

MyBatis 是一个用于简化数据库操作的持久层框架,它的核心思想是 将 SQL 与 Java 代码解耦,让开发者专注于 SQL 的编写,同时自动处理重复的数据库操作步骤。 一、核心思想:SQL 与 Java 解耦 传统 JDBC 需要开发者手动管理数据库连…

有什么区别?Elastic 和 Splunk 数据层

作者:来自 Elastic Ugo Sangiorgi, Matt Wehle 了解 Elastic 和 Splunk 数据管理方法之间的主要区别,以便做出明智的决策,实现高效的数据处理 在数据管理领域,在讨论如何根据不同的性能要求提供和/或保留数据时,经常会…

BGP状态和机制

BGP邻居优化 为了增加稳定性,通常建议实验回环口来建立邻居。更新源:建立邻居和邻居所学习到的路由的下一跳。多跳:EBGP邻居建立默认选哟直连,因为TTL=1,如果非直连,必须修改TTL。命令备注peer 2.2.2.2 connect-interface lo1配置更新源peer 2.2.2.2 ebgp-max-hop 2配置T…

【电机控制器】PY32F00BF15U6TR-从KEIL5中计算资源消耗资源

【电机控制器】PY32F00BF15U6TR-从KEIL5中计算资源消耗资源 文章目录 [TOC](文章目录) 前言一、MCU芯片手册二、实验三、实验结论四、参考资料总结 前言 使用工具: 1.KEIL5编译器 提示:以下是本篇文章正文内容,下面案例可供参考 一、MCU芯片…

python实战项目58:采集蜻蜓FM热门音频top排行榜

python实战项目58:采集蜻蜓FM热门音频top排行榜 一、采集流程介绍二、数据接口采集三、使用xpath提取页面数据1、抓包,找到数据接口2、发送请求,获取数据3、提取数据4、保存数据一、采集流程介绍 蜻蜓FM热门音频top排行榜的链接为: https://m.qingting.fm/rank/,首页如下图…

STM32【3】芯片的底层组成概论

关于单片机的组成 单片机的意思是,小小计算电脑,麻雀虽小,五脏俱全,里面包含了CPU,ROM,RAM,各种外设。 CPU地位最高,可以访问ROM和RAM,Flash,GPIO等外设&…

基于django图书信息管理系统的搭建(增删改查)

✍django项目搭建教程 ☞ ----------------- 教程 本文主要讲解django如何连接数据库MySQL并且可视化展示,实现增删改查功能 目录 一. 创建django应用 二. 数据库配置 三. 查看数据库 四. 编写代码 4.1视图函数 4.2 配置URL 4.3创建模板文件 4.…

Kotlin 知识点二 延迟初始化和密封类

对变量延迟初始化 Kotlin 语言的许多特性,包括变量不可变,变量不可为空,等等。这些特性 都是为了尽可能地保证程序安全而设计的,但是有些时候这些特性也会在编码时给我们带来不 少的麻烦。 比如,如果你的类中存在很多…

基于SpringBoot的“古城景区管理系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“古城景区管理系统”的设计与实现(源码数据库文档PPT) 开发语言:Java 数据库:MySQL 技术:SpringBoot 工具:IDEA/Ecilpse、Navicat、Maven 系统展示 系统整体功能图 系统首页界面 系统注册界面 景…

力扣hot100 —— 电话号码字母组合; 子集 (非回溯做法)简单易懂

由于博主对回溯也不是很熟悉,这里提出一种简单易懂的解法(有点暴力) 解题思路: 每个数字对应有自己的字母串; 首先遍历将每个字母存入也就是 res{{a},{b},{c}} 然后遍历后续数子对应的字母,让每个字母与…

【Redis】在Java中以及Spring环境下操作Redis

Java环境下&#xff1a; 1.创建maven 项目 2.导入依赖 <!-- redis --><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>4.3.2</version></dependency> 此处使用的是Jedis&…

Directx上传堆和默认堆注意事项

前景 之前我用directx写上传堆上传给默认堆Index&#xff0c;但是我发现数据无法被GPU读取 void HelloTriangle::createDefaultBuffer(const void* data, const UINT byteSize, ComPtr<ID3D12Resource>& defaultBuffer) {ThrowIfFiled(m_Device->CreateCommitte…

Java封装弱密码校验工具类

弱密码校验工具类 通过检查密码是否符合某些安全策略来判断其强度 ● 密码长度 ● 字符类型 ● 常见密码组合 import java.util.Arrays; import java.util.HashSet; import java.util.Set;public class WeakPasswordCheckUtil {// 常见弱密码列表&#xff08;可根据需求扩展&…

Figure自研模型Helix发布,人形机器人迈向新纪元?

Figure 公司自 2022 年成立以来&#xff0c;便在人形机器人领域崭露头角&#xff0c;成为行业内备受瞩目的新星。公司由连续创业者 Brett Adcock 创立&#xff0c;总部位于美国加利福尼亚州桑尼维尔&#xff0c;汇聚了来自波士顿动力公司、特斯拉、谷歌 DeepMind 等知名企业的顶…

vue3.0将后端返回的word文件流转换为pdf并导出+html2pdf.js将页面导出为pdf

实现思路 1.将Word文档转换为HTML&#xff1a;mammoth.js&#xff0c;它可以将.docx文件转换为HTML 2.将HTML转换为PDF&#xff1a;使用html2pdf.js将HTML转换为PDF 如果想要相同的效果&#xff0c;也可以把前端页面直接导出转换为pdf: 运用的插件&#xff1a;html2pdf.js 后端…

(Arrow)试时间处理变得更简单

前言 Arrow库并不是简单的二次开发,而是在datetime的基础上进行了扩展和增强。它通过提供更简洁的API、强大的时区支持、丰富的格式化和解析功能以及人性化的显示,填补了datetime在某些功能上的空白。如果你需要更高效、更人性化的日期时间处理方式,Arrow库是一个不错的选择…

锂电池使用和存储电压

表格补充说明&#xff1a; 每列数据中&#xff0c;2S和3S电池的数值都是单电芯数值的2倍和3倍&#xff1b;对于其他电压的电池&#xff0c;将单电芯数值乘以相应S数即可&#xff1b;理论上单个电芯过放电压为3.0V&#xff0c;实际中为了保险&#xff0c;电压降到3.6V即需充电。…

欧拉回路与哈密尔顿回路: Fleury算法与Hierholzer 算法(C++)

图论中的回路是指一个路径, 它从某个顶点开始, 经过所有边恰好一次, 并回到起始顶点. 定义 欧拉回路: 从一个顶点出发, 经过每条边恰好一次, 并且最终回到起始顶点. 哈密尔顿回路: 从一个顶点出发, 经过每个顶点恰好一次, 并且最终回到起始顶点. 欧拉路径: 从一个顶点出发, …

20250221 NLP

1.向量和嵌入 https://zhuanlan.zhihu.com/p/634237861 encoder的输入就是向量&#xff0c;提前嵌入为向量 二.多模态文本嵌入向量过程 1.文本预处理 文本tokenizer之前需要预处理吗&#xff1f; 是的&#xff0c;文本tokenizer之前通常需要对文本进行预处理。预处理步骤可…