一、规范行为
-
明确何为项目,改如何命名,又如何存储
-
文件路径不能存在中文以及特殊字符,防止发生意外
-
-
学习过程中可以随意命名变量、函数名等,但是项目中必须严格遵守命名规范
-
要明确每一个软件安装的作用和目的,并清楚安装位置在哪里【一切软件的安装路径都不要有中文和特殊字符】
-
重要:从现在开始为每个阶段项目都建立独立的虚拟环境,避不必要的麻烦
-
不要太过依赖ai
二、环境准备
-
打开cmd(win+R)
-
输入命令行
conda create -n sklearn_env python=3.8
注意:创建的python版本需要为要求的对应版本,不然也容易造成版本不兼容的问题
-
激活创建的虚拟环境【重点】
-
不激活虚拟环境下载库等于白下
-
conda activate sklearn_env
-
下载这里所需的库
-
numpy
-
pandas
-
scikit-learn
-
#numpy pip install numpy==1.21.6 -i https://pypi.mirrors.ustc.edu.cn/simple/ #pandas pip install pandas==1.1.5 -i https://pypi.mirrors.ustc.edu.cn/simple/ #scikit-learn pip install scikit-learn==1.0.2 -i https://pypi.mirrors.ustc.edu.cn/simple/
-
新建项目并为项目配置好虚拟环境
三、机器学习基础
1.训练数据集
-
自行准备用来训练模型的数据集,模型可根据训练集数据来学习规律,从而能模型来对未知的数据做预测
-
如果模型学习到的内容比较少且单一,那么使用模型的时候效果一定较差,训练模型一定要准备丰富的数据集
2、【重点】分类
-
监督学习:目前基本上所有的模型都是基于监督学习完成的
-
指在训练模型时,准备的数据集需要打标签
(自行理解打标签指:训练模型时,给模型的的数据是按标签分好类的)
-
-
半监督学习:
-
训练模型时,一部分数据集打标签,一部分不打标签
-
-
无监督学习:
-
训练模型的时候,数据集不打标签,让模型自己去学习其中的规律
-
-
强化学习:
-
让智能体在与环境的交互中,不断优化自身,得到有力的反馈。
-
-
打标签:
-
训练模型时需要告诉模型,学习的数据集里面某个内容是什么
-
3、上游任务和下游任务
-
上游任务:理解为做模型
-
下游任务:理解为用模型
4、计算机视觉的三大任务
-
图像分类任务:识别图像中的物体类别
-
目标检测任务:识别图像中的物体类别以及物体位置
-
图像分割任务
5、数据集的分类【重点】
-
训练数据集:训练模型。
-
epochs:训练模型的轮次,即让模型去学习多少次数据集里面的内容
-
数据集需要打标签
-
-
验证数据集:一般情况下,每训练完一轮(epoch),就会使用验证数据集验证训练出来的模型,基于验证结果去调整模型的超参数信息利于模型训练
-
验证数据集不参与模型训练
-
数据集需要打标签
-
-
测试数据集:模型训练好之后,在已知数据集中做测试
-
数据集需要打标签
-
一般是可选项,可以有可以没有
-
-
推理:模型训练好之后在未知数据上做测试(不打标签的数据)。
-
可理解为把训练好的模型拿来用
(注:测试和推理两个动作都是在模型训练好之后)
-
五、sklearn库
机器学习基本所有API都来自这个库
1、数据集
-
sklearn库中提供大量内置数据集,且可以通过sklearn库去下载网络数据集
-
自带数据集(内置):可以直接通过sklearn库对应的API去加载出来,包含下面两种数据集
-
分类数据集
-
线性回归数据集
-
1.1 内置数据
-
通过sklearn的datasets子模块导入、在线下载及本地生成数据集的常用三种方法:
-
本地加载数据:
sklearn.datasets.load_<name>_
-
远程加载数据:
-
sklearn.datasets.fetch_<name>_
-
构造数据集:
-
sklearn.datasets.make_<name>_
-
-
本地数据量小,只要安装sklearn就可以获取:
| 数据集 | 获得方法 | 适用模型 |
|---|---|---|
| 波士顿房价数据集 | load_boston | 回归模型 |
| 鸢尾花数据集 | load_iris | 分类模型 |
| 糖尿病数据集 | load_diabetes | 回归模型 |
| 手写数字识别数据集 | load_digits | 分类模型 |
| Linnerud 数据集 | load_linnerud | 多输出回归模型 |
| 红酒数据集 | load_wine | 分类模型 |
| 乳腺癌数据集 | load_breast_cancer | 分类模型 |
(注意:各个数据适应什么模型就在训练什么模型的时候使用,切忌用适用回归模型分类的数据集进行分类模型的训练,或者用适用分类模型的数据集进行回归模型的训练)
1.2 网络数据
-
网络数据集数量大,数据只能进行网络进行获取

1.3 加载数据集
1.3.1 内置数据集
-
加载鸢尾花数据集
-
# 导入函数 --- load_iris:加载鸢尾花数据集的函数 from sklearn.datasets import load_iris # 获取数据集 --- 执行 load_iris 函数 iris = load_iris()
-
加载糖尿病床数据
-
## 导入函数 from sklearn.datasets import load_diabetes # 获取数据集 diabetes = load_diabetes()
中文总结步骤
-
导入数据集对应的函数,函数在sklearn.datasets下
-
调用函数,得到数据集
-
后续代码处理
我将以鸢尾花数据集为例,详细解释其字典结构中的各个key及其含义,并通过代码直观展示数据内容。
首先,我们可以通过scikit-learn库加载鸢尾花数据集,然后逐一查看各个key的内容:
1.3.2 鸢尾花数据集各key详细解释【重点理解】
-
data:
-
内容为数据集
-
是一个二维数组(ndarray),形状为(150, 4)
-
包含150个样本(每行一个样本),每个样本有4个特征值
-
例如,第一个样本的特征数据为[5.1, 3.5, 1.4, 0.2]
-
-
target:
-
内容为类别标签
-
是一个一维数组(ndarray),形状为(150,)
-
每个元素是0、1或2,代表该样本的类别标签
-
与data中的样本一一对应
-
-
frame:
-
值为None,表示该数据集不是以pandas DataFrame格式存储的
-
-
target_names:
-
是类别标签的实际名称
-
对应关系:0 → setosa(山鸢尾)、1 → versicolor(变色鸢尾)、2 → virginica(维吉尼亚鸢尾)
-
-
DESCR:
-
是一个字符串,包含数据集的详细描述
-
包括数据集来源、特征说明、样本数量等信息
-
-
feature_names:
-
是4个特征的名称,依次为:
-
'sepal length (cm)':花萼长度
-
'sepal width (cm)':花萼宽度
-
'petal length (cm)':花瓣长度
-
'petal width (cm)':花瓣宽度
-
-
通过以上总结,我们可以更直观地看到每个样本的特征值、标签及其对应的鸢尾花品种,从而清晰地理解整个数据集的结构和内容。
1.3.3、加载网络数据集
-
现实世界数据,需要通过网络才能下载后,保存到本地目录,可以通过
datasets.get_data_home()获取到存储的目录 -
下载时,有可能回为网络问题而出题
-
如果硬盘中已经下载了这个数据集,直接加载,否则会下载到磁盘中,通过参数downl_if_missing=进行调整
-
示例:
-
import numpy as np #导入划分数据集函数 from sklearn.model_selection import train_test_split #数据已下载,直接加载新闻数据 from sklearn.datasets import fetch_20newsgroups news=fetch_20newsgroups(data_home="./", download_if_missing=False)
-
-
加载Newsgroups数据集
-
# 新闻数据集 from sklearn.datasets import fetch_20newsgroups """ fetch_20newsgroups 函数参数: 1、data_home:数据集下载之后存储的路径 2、subset:选择下载的数据集的类型,train:训练数据集、test:测试数据集、all:训练+测试 3、return_X_y:bool, default=False """ news = fetch_20newsgroups(data_home="./", subset="all", return_X_y=False) print(news)
-
-
加载加州福尼亚数据集
-
from sklearn.datasets import fetch_california_housing news=fetch_california_housing(data_home="./",return_X_y=False) print(news)
-
2、读取本地csv文件
-
加载本地csv文件数据集,使用pandas中的read_csv函数
-
加载本地excel文件数据集,使用pandas中的read_excel函数
3、数据集划分
-
数据集划分:把总数据集划分为训练数据和测试数据两个部分
3.1 可变参数
-
在 Python 中,可变参数(也称为不定长参数)是指函数可以接受任意数量的参数。Python 支持两种类型的不定长参数:
-
位置不定长参数:使用星号
*前缀来收集额外的位置参数,并将它们打包成一个元组(tuple) -
关键字不定长参数:使用双星号
**前缀来收集额外的关键字参数,并将它们打包成一个字典(dictionary)
-
3.2 train_test_split 函数
-
train_test_split是sklearn.model_selection库中的一个非常实用的函数,用于将数据集划分为训练集和测试集。这种划分是机器学习流程中的重要步骤之一,它有助于评估模型在未见过的数据上的性能,从而避免过拟合。 -
函数描述如下:
-
主要参数及其作用:
-
| 参数名 | 类型 | 默认值 | 可选值/说明 |
|---|---|---|---|
*arrays | list, numpy array, pandas DataFrame 等 | - | 传入一个或多个数组(如特征 X 和标签 y) |
test_size | float 或 int | 0.25 | 测试集大小:若为浮点数表示比例(如 0.2),若为整数表示样本数量 |
train_size | float 或 int | 自动计算 | 训练集大小,若未指定则根据 test_size 推导 |
random_state | int 或 RandomState 实例 或 None | None | 控制随机种子,确保每次划分一致(可复现) |
shuffle | bool | True | 是否在划分前打乱数据,默认开启;关闭后按顺序划分 |
stratify | array-like 或 None | None | 用于分类任务中保持类别分布一致性(常用于不平衡数据 |
-
返回值:
-
train_test_split函数返回一个元组,包含分割后的数据集。具体返回值的数量取决于传入的数组数量。如果传入两个数组(如X和y),则返回四个数组;如果传入三个数组,则返回六个数组,依此类推。返回值的数据类型和传入函数进行分割的数据类型一致 -
对于两个数组的情况,返回值如下:
返回值 类型 描述 X_trainarray-like 划分后的训练集特征数据 X_testarray-like 划分后的测试集特征数据 y_trainarray-like 划分后的训练集目标变量(标签) y_testarray-like 划分后的测试集目标变量(标签) -
3.2.1 随机数种子
-
如果您不设置
random_state或者将其设置为None,那么每次调用train_test_split时将会产生不同的数据分割,这是因为没有固定种子的情况下,函数内部会使用系统时间或者其它方法来初始化随机数生成器 -
当您设置
random_state为一个固定的整数值时,每次调用train_test_split都会产生相同的随机分割结果。这对于调试和验证模型非常有用,因为您可以确保每次运行都是基于完全相同的数据分割来进行的,便于后期调参。 -
在 sklearn 中是使用
RandomState类实现的随机数种子的生成,RandomState类是 NumPy 库中用于生成伪随机数的核心组件之一。它封装了 Mersenne Twister 算法(默认情况下)以及其他可能的伪随机数生成算法,提供了丰富的接口来生成不同分布下的随机数
3.2.2 数据类型一致
-
如果你输入的是 Pandas DataFrame 或 Series,那么
train_test_split返回的也将是 DataFrame 或 Series 类型的对象。如果你输入的是 Numpy 数组或者列表,那么返回的将是 Numpy 数组。即划分前后数据类型一致
3.2.3 二维数组数据集划分
-
只划分第一维度(行),第二维度(列)保持不变(这里看结果较直观)
-
案例代码:
import numpy as np
from sklearn.model_selection import train_test_split
data = np.arange(1, 16, 1)
print("原始数据:\n", data)
data.shape = (5, 3)
print("改变形状:\n", data)
print("现有形状:\n", data)
X_train, X_test = train_test_split(data, random_state=42)
print("X_train:\n", X_train)
print("X_test:\n", X_test)
-
运行结果
原始数据: [ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15] 改变形状: [[ 1 2 3] [ 4 5 6] [ 7 8 9] [10 11 12] [13 14 15]] 现有形状: [[ 1 2 3] [ 4 5 6] [ 7 8 9] [10 11 12] [13 14 15]] X_train: [[ 7 8 9] [ 1 2 3] [10 11 12]] X_test: [[ 4 5 6] [13 14 15]]
3.2.4 字典数据集划分
-
需要使用到API:DictVectorizer
-
参数:sparse
-
sparse=False参数指定输出为密集矩阵
-
存储所有元素,包括零值
-
-
sparse=True参数指定输出为稀疏矩阵(CSR 格式)
-
只存储非零元素的位置和值,节省内存空间
-
-
-
在n维中,如果进行特征提取之后,进行特征信息表达,选择的是 one-hot 编码【独热编码】
-
类似于这样存储[0 1 0 0 ... 0] 即只有一个位置上是1,其余都是0
-
# 定义一个数据集
data = [
{"name": "张三", "address": "成都", "age": "18"},
{"name": "lisi", "address": "重庆", "age": "20"},
{"name": "王五", "address": "贵州", "age": "30"},
]
# 导入字典特征的提取的类
from sklearn.feature_extraction import DictVectorizer
dict_vec = DictVectorizer(sparse=False)
#dict_vec = DictVectorizer(sparse=True)
# 执行特征提取操作
result = dict_vec.fit_transform(data)
print(result)
print(type(result))
# 获取每一列的名称
print(dict_vec.get_feature_names())
-
当sparse=False,数据存储为密集矩阵为:
[[1. 0. 0. 1. 0. 0. 0. 1. 0.] [0. 0. 1. 0. 1. 0. 1. 0. 0.] [0. 1. 0. 0. 0. 1. 0. 0. 1.]]
-
它的每一列名称为:
['address=成都', 'address=贵州', 'address=重庆', 'age=18', 'age=20', 'age=30', 'name=lisi', 'name=张三', 'name=王五']
-
当sparse=True,数据存储为密集矩阵为:
(0, 0) 1.0(0, 3) 1.0(0, 7) 1.0(1, 2) 1.0(1, 4) 1.0(1, 6) 1.0(2, 1) 1.0(2, 5) 1.0(2, 8) 1.0
-
只存储非零元素的位置和值,前面为非零元素的坐标(行,列),后面为值
4、特征工程
-
特征工程目的:为了在训练模型 之前处理数据,让数据变得更好,让训练出的模型效果更好(数)
-
处理数据方案:
-
特征提取:提取数据中的信息,进行数据信息的转化,如果有缺失值、异常值要进行处理
-
归一化处理:把数据集中数值压缩在一定范围,避免大值数据这种异常值的影响,可以消除单位因素产生的影响
-
标准化处理:把数据集编程均值为x,方差为y的分布,机器学习提供的API满足均值为0,标准差为1的情况【默认情况】
-
降维处理
-
-
步骤(不一定非得全部使用,要针对不同的数据进行相应的处理)
-
数据理解与预处理:首先需要理解数据集的特性,包括数据的分布、缺失值情况、异常值,去除重复记录、处理缺失值、纠正错误数据等
-
特征生成:根据业务理解或领域知识创造新的特征、将非数值特征转换为数值形式
-
特征选择:利用统计检验、相关性分析或其他特征选择技术来确定哪些特征对模型最为重要。这有助于减少维度,同时保持模型的有效性
-
特征变换:对原始特征进行转换,比如使用对数变换来处理偏斜的数据分布、使用多项式特征扩展来增加模型的非线性能力
-
特征编码:对于类别特征,需要进行编码处理,比如标签编码(label encoding)或独热编码(one-hot encoding)
-
标签编码是一种简单的编码方式,它将每个类别标签用唯一的整数表示。例如,如果有三个类别:'apple', 'banana', 'cherry',标签编码可能会将它们分别编码为 0, 1, 2。标签编码适用于有序分类变量(ordinal variables),即这些类别的顺序是有意义的,例如教育水平。然而,对于没有自然顺序的名义变量(nominal variables),直接使用标签编码可能会引入人为的顺序关系,这可能会影响模型的性能,因为模型可能会假定数值上较大的类别比数值上较小的类别更重要
-
独热编码是一种将名义变量转换为数值型数据的方式,它创建了一个新的二进制列(即只有 0 或 1 的列)用于每一个可能的类别值。例如,对于上述的类别'apple', 'banana', 'cherry',独热编码会创建三列,每列对应一个类别,每一行中只有一个类别被标记为 1,其余为 0。这种方式避免了引入任何顺序上的意义,因此适用于没有内在顺序关系的类别变量
-
-
特征缩放:确保所有特征都在相似的尺度上,即归一化、标准化
-
降维:当特征数量过多时,可以采用降维技术,如 PCA(主成分分析)来减少特征数量,同时尽可能保留原始数据的信息
-
4.1 API
4.1.1 DictVectorizer
-
DictVectorizer是sklearn.feature_extraction中用于特征提取和编码的重要工具之一,特别适用于处理字典格式的数据。它可以将字典列表转换为模型可直接使用的数值型特征矩阵,其中每一行代表一个样本,每一列表示一个特征 -
DictVectorizer实例化参数:参数 默认值 说明 dtypenumpy.float64输出数组的数据类型 separator"="当类别特征名称与值之间需要拼接时使用(默认不启用) sparseTrue如果为 True,输出是三元组的稀疏矩阵;如果为False,输出是 Numpy 数组sortTrue是否按字母顺序排序特征名
4.1.1.1 稀疏矩阵
-
在矩阵中,若数值为0的元素数目远多于非零元素的数目,且非0元素分布没规律时,则称该矩阵为稀疏矩阵,与之相反,非0元素数目占比大时,则称该矩阵为稠密矩阵
4.1.1.2 提取为稀疏矩阵
-
使用DictVectorizer提取出来的稀疏矩阵,通过三元组表进行输出,三元组表是一种用于表示系数矩阵的方法,特别适用于COO格式,它包含三部分
| 组成部分 | 名称 | 内容描述 |
|---|---|---|
| 第一部分 | 行索引(row indices) | 每个非零元素所在的行 |
| 第二部分 | 列索引(column indices) | 每个非零元素所在的列 |
| 第三部分 | 非零值(non-zero values) | 储非零元素的值 |
4.1.1.3 稀疏矩阵和稠密矩阵转换
-
稀疏矩阵调用以下函数可以转为稠密矩阵
-
API:result.toarray()#转numpy matrix
-
result.todense()#转numpy matrix
-
| 方法名 | 返回类型 | 描述说明 | 示例 |
|---|---|---|---|
todense() | numpy.matrix | 将稀疏矩阵转换为 NumPy 的 matrix 类型 | sparse_matrix.todense() |
toarray() | numpy.ndarray | 将稀疏矩阵转换为 NumPy 的 ndarray 类型 | sparse_matrix.toarray() |
字典提取的示例代码: fit_transform 方法重点解释
from sklearn.feature_extraction import DictVectorizer
"""
DictVectorizer 不会处理数字,数字是多少处理后就是多少
如果是字符串,就会处理,不同的字符串就会作为不同的特征
每一个特征就是一列数据,这一列数据满足一个位置上数值为1【通常】,其余位置为0【one-hot】
"""
# 定义一个数据集
data = [
{"name": "张三", "address": "成都", "age": 18},
{"name": "lisi", "address": "重庆", "age": 20},
{"name": "王五", "address": "贵州", "age": 30},
]
# 创建字典特征提取的对象
dv = DictVectorizer(sparse=True)
"""
fit_transform 方法等价于先执行 fit 方法、然后执行 transform 方法
fit 方法的作用:
在特征工程阶段:
比如 minMaxScaler(最小值最大值归一化),fit 方法就会从数据集中学习到数据集中的最大值、最小值
StandardScaler(标准化),fit 方法就会从数据集中学习数据集中的均值和标准差等信息
模型阶段:后期使用机器学习里面的模型---创建出来的对象叫做估计器
训练模型 --- 投喂
transform 方法的作用:【一定在 fit 方法之后执行】
使用 fit 方法的结果去处理数据
问题:我们训练模型的时候,是需要把所有数据集的信息都执行fit方法吗?分开执行fit方法?只需要部分数据集执行fit方法?
不是把所有数据集都去做 fit 处理
训练模型的时候,只能够提供训练集里面的信息给fit,去得到训练集的信息,来训练模型
而不可以把测试集的信息给到fit,否则会导致测试集中的数据集已经被处理了,模型后期做验证的时候就会存在误差
训练数据集 fit 方法之后,还需要对测试集进行 fit?不需要,测试集就直接使用训练集中的信息(最大值、最小值。。。)
"""
result = dv.fit_transform(data)
# dv.fit(data)
# result = dv.transform(data)
print(result)
# 查看特征名字 --- 有警告
# print(dv.get_feature_names())
print(dv.get_feature_names_out())
"""
稀疏矩阵转为numpy里面的数组、matrix
"""
print(type(result)) # <class 'scipy.sparse._csr.csr_matrix'>
result1 = result.toarray() # numpy ndarray
print(result1)
print(type(result1)) # <class 'numpy.ndarray'>
result2 = result.todense() # numpy matrix
print(result2)
print(type(result2)) # <class 'numpy.matrix'>
4.2 CountVectorizer
-
CountVectorizer是一个在自然语言处理(NLP)任务中常用的工具,用于将文本数据转换为向量形式。它属于sklearn.feature_extraction.text模块的一部分,是Scikit-learn库提供的功能之一。CountVectorizer主要通过以下方式工作:-
词汇表构建:首先根据训练集中的文档创建一个固定的词汇表(即所有唯一词的集合)。每个词在词汇表中都有一个对应的索引位置
-
词频统计:对于每个文档,
CountVectorizer会计算出词汇表中每个词出现的次数,并忽略那些未出现在文档中的词 -
输出格式:最终的输出是一个稀疏矩阵,每一行对应一个文档,每一列对应词汇表中的一个词。矩阵中的每个元素表示某个词在某个文档中出现的次数
-
-
CountVectorizer默认会忽略一些英文中的停用词(如“is”、“the”等),并且会对单词进行小写化处理。这些行为可以通过传递参数来调整,例如设置stop_words='english'可以显式地过滤英语停用词,而lowercase=False则可以禁用自动小写化处理 -
CountVectorizer实例化参数:
| 参数名 | 类型 | 默认值 | 描述说明 |
|---|---|---|---|
stop_words | string 或 list | None | 指定要忽略的停用词集合:<br> - 若设为 'english',则会使用内建的英语停用词列表(如 "is", "the" 等)<br> - 也可以传入一个自定义的停用词列表<br> - 单个字母(如 "i"、"a")通常会被自动忽略 |
lowercase | bool | True | 是否在分词前将文本统一转换为小写:<br> - 设为 True:自动转换为小写(推荐用于英文文本)<br> - 设为 False:保留原始大小写格式 |
4.2.1提取英文文本
-
提取英文文本不需要像中文文本一样需要进行分词
"""
统计词语在各自的文档中出现的次数
"""
# 导入类
from sklearn.feature_extraction.text import CountVectorizer
def english_cv():
# 准备数据
data = [
'This is the first document.',
'This document is the second document.',
'And this is the third one.',
'Is this the first document?',
'this is an apple.'
]
# 创建对象
"""
英文:
stop_words:哪些词被忽略掉,不参与最终的词表统计,列表
lowercase:默认情况下会把所有的词转为小写在分词
"""
cv = CountVectorizer(stop_words=["is"])
# fit_transform
result = cv.fit_transform(data)
print(result.toarray())
print(cv.get_feature_names_out())
if __name__ == '__main__':
english_cv()
4.2.2 提取中文文本
-
分词:Jieba 是一个广泛使用的中文分词库,支持三种分词模式:精确模式、全模式和搜索引擎模式。它还支持添加自定义词典、关键词提取、词性标注等功能。Jieba 的优点在于其高效性和易用性,适用于大多数中文文本处理场景
-
这里先掌握 Jieba 分词的基本上使用方式,在后面大模型课程中还会学习 Jieba 分词
-
-
主要功能
-
分词:将连续的中文文本切分成单独的词语
-
关键词提取:基于 TF-IDF 算法从文本中抽取关键词
-
词性标注:标记每个词的词性(如名词、动词等)
-
并行分词:利用多核处理器加速分词过程
-
自定义词典:允许用户根据需要添加或删除特定词汇
-
-
jieba分词的三种模式
-
精确默认:是默认的分词模式,会将句子精确切分,适合文本分析
-
全模式:扫描出所有可能的词,不能消除歧义,速度快但结果冗余
-
搜索引擎模式:适用于搜索引擎,在精确模式基础上,对长词再进行细粒度拆分
4.2.2.1 基础分词
-
案例代码:
import jieba
text = "南京市长江大桥"
# 精确模式,默认模式
result = jieba.lcut(text)
print("精确模式:", result)
# 全模式
result_full = jieba.lcut(text, cut_all=True)
print("全模式:", result_full)
# 搜索引擎模式
result_search = jieba.lcut_for_search(text)
print("搜索引擎模式:", result_search)
-
运行结果:
精确模式: ['南京市', '长江大桥'] 全模式: ['南京', '南京市', '京市', '市长', '长江', '长江大桥', '大桥'] 搜索引擎模式: ['南京', '京市', '南京市', '长江', '大桥', '长江大桥']
4.2.2.2 添加词典
-
添加一个词典并且添加词语(一个词占一行、每一行分三部分:词语、词频(可省略)、词性(可省略)、用空格隔开,顺序不可颠倒)
严寒 500 n 深冬 400 n 阴晦 300 a 冷风 200 n 呜呜 100 m 萧索 250 a 荒村 180 n 活气 160 n 悲凉 220 a 二十余年 350 num
-
案例代码:
import jieba.analyse
# 加载自定义词典
jieba.load_userdict("hometown.txt")
# 原始文本:鲁迅《故乡》节选
text = """我冒了严寒,回到相隔二千余里,别了二十余年的故乡去。
时候既然是深冬;渐近故乡时,天气又阴晦了,冷风吹进船舱中,呜呜的响,
从篷隙向外望,苍黄的天底下,远近横着几个萧索的荒村,没有一些活气。
我的心禁不住悲凉起来了。"""
# 1. 精确模式分词(默认模式)
seg_list = jieba.lcut(text)
print("【精确模式】")
print("/".join(seg_list))
# 2. 全模式(所有可能的词语组合)
seg_list_full = jieba.lcut(text, cut_all=True)
print("\n【全模式】")
print("/".join(seg_list_full))
# 3. 搜索引擎模式(适用于搜索引擎输入提示)
seg_list_search = jieba.lcut_for_search(text)
print("\n【搜索引擎模式】")
print("/".join(seg_list_search))
-
运行结果:
【精确模式】 我/冒/了/严寒/,/回到/相隔/二千余/里/,/别/了/二十余年/的/故乡/去/。/ /时候/既然/是/深冬/;/渐近/故乡/时/,/天气/又/阴晦/了/,/冷风吹/进/船舱/中/,/呜呜/的/响/,/ /从篷隙/向/外望/,/苍黄/的/天底下/,/远近/横着/几个/萧索/的/荒村/,/没有/一些/活气/。/ /我/的/心/禁不住/悲凉/起来/了/。 【全模式】 我/冒/了/严寒/,/回到/相隔/二千/二千余/千余/千余里/余里/,/别/了/二十/二十余/二十余年/十余/十余年/余年/的/故乡/去/。/ //时候/既然/是/深冬/;/渐近/故乡/时/,/天气/又/阴晦/了/,/冷风/冷风吹/风吹/吹进/船舱/中/,/呜呜/的/响/,/ //从/篷/隙/向/外/望/,/苍黄/的/天底/天底下/底下/,/远近/横/着/几个/萧索/的/荒村/,/没有/一些/活气/。/ //我/的/心/禁不住/不住/悲凉/起来/了/。 【搜索引擎模式】 我/冒/了/严寒/,/回到/相隔/二千/千余/二千余/里/,/别/了/二十/十余/余年/二十余/十余年/二十余年/的/故乡/去/。/ /时候/既然/是/深冬/;/渐近/故乡/时/,/天气/又/阴晦/了/,/冷风/风吹/冷风吹/进/船舱/中/,/呜呜/的/响/,/ /从篷隙/向/外望/,/苍黄/的/天底/底下/天底下/,/远近/横着/几个/萧索/的/荒村/,/没有/一些/活气/。/ /我/的/心/不住/禁不住/悲凉/起来/了/。
4.2.2.3 词性标注
-
Jieba 可以结合
posseg模块进行词性标注 -
常见的词性
| 标签 | 含义 | 标签 | 含义 | 标签 | 含义 | 标签 | 含义 |
|---|---|---|---|---|---|---|---|
| n | 普通名词 | f | 方位名词 | s | 处所名词 | t | 时间 |
| nr | 人名 | ns | 地名 | nt | 机构名 | nw | 作品名 |
| nz | 其他专名 | v | 普通动词 | vd | 动副词 | vn | 名动词 |
| a | 形容词 | ad | 副形词 | an | 名形词 | d | 副词 |
| m | 数量词 | q | 量词 | r | 代词 | p | 介词 |
| c | 连词 | u | 助词 | xc | 其他虚词 | w | 标点符号 |
| PER | 人名 | LOC | 地名 | ORG | 机构名 | TIME | 时间 |
-
案例代码:
import jieba.posseg as pseg
words = pseg.cut("我爱北京天安门")
for word, flag in words:
print(f'{word} {flag}')
-
运行结果:
我 r 爱 v 北京 ns 天安门 ns
4.2.2.3 停用词
-
如果你想去掉无意义的词(如的、是),可以使用停用词表
-
案例代码:
import jieba
text = "你和我是好朋友的吧"
stopwords = set(["的", "是", "和"])
words = jieba.lcut(text)
print("未使用停用词:", words)
words1 = [w for w in jieba.cut(text) if w not in stopwords]
print("使用停用词:", words1)
-
运行结果:
未使用停用词: ['你', '和', '我', '是', '好', '朋友', '的', '吧'] 使用停用词: ['你', '我', '好', '朋友', '吧']
4.2.2.4 综合案例
# 中文分词,使用 jieba 工具
"""
jieba 工具的使用:
1、安装 jieba 库
2、jieba 分词介绍:他是一个用来做中文分词的库,基于规则进行分词的,这个规则它自己设置了的,也可以引入自己的规则
这个规则的官方名字叫做词典
3、jieba 分词有三种分词方案:
1.默认模式【精确模式】:一般选择这种方式,按照词典对文本进行分词
2.全模式:更加细粒度的分词,分词的结果会更多一点
3.搜索引擎模型:就在精确模式的基础之上,把长一点词汇进一步分词
4、分词的 api:lcut、lcut_for_search
"""
# 导入jieba分词
"""
完成一个分词工具方法,能够把列表文本中的分词结果统计出来(词不可以重复),然后让countVectorizer统计次数
"""
import jieba
def chinese_cv():
# data = [
# '好好学习,天天向上,今天天气很不错哟,今天只有半天课',
# '好好学习,天天向上,今天天气很不错哟,今天只有半天课'
# ]
data = "在北京天安门看升国旗好开心呀"
# 默认模式
result1 = jieba.lcut(data)
print(result1)
# 统计次数
cv = CountVectorizer(stop_words=['呀'])
result = cv.fit_transform(result1)
print(result.toarray())
print(cv.get_feature_names_out())
# 全模式 cut_all 参数设置为 True
# result2 = jieba.lcut(data, cut_all=True)
# print(result2)
# 搜索引擎模式
# result3 = jieba.lcut_for_search(data)
# print(result3)
# 引入自己的词典---有的时候这个词典的内容可能不会再jieba分词中生效,为什么?
"""
设置的词语的词频可能没有默认词典中的词语的词频高,那么就把词频放大
"""
"""
如果说要引入自己的分词规则,就需要自己的定义词典,然后引入到项目中
定义词典的步骤:
1、创建一个txt文件
2、在文件中,每一行就是一个词,一共有三个数据词 词频[option] 词性[option]
3、加载自定义的词典,使用方法load_userdict实现,参数就是词典的访问路径
"""
def self_cv():
# 加载用户自定义的词典
jieba.load_userdict("./my_dict.txt")
data = """我冒了严寒,回到相隔二千余里,别了二十余年的故乡去。
时候既然是深冬;渐近故乡时,天气又阴晦了,冷风吹进船舱中,呜呜的响,
从篷隙向外望,苍黄的天底下,远近横着几个萧索的荒村,没有一些活气。
我的心禁不住悲凉起来了。"""
result = jieba.lcut(data)
print("/".join(result))
# 获取词典中分词过后的词语的内容和词性
"""
需要使用到jieba库中的词性方法
"""
import jieba.posseg as pos
def posseg_cv():
# 准备文本
data = "教育学会会长期间坚定支持民办教育事业!"
# 进行分词
result = pos.lcut(data)
"""
item:词
a:词性
"""
for item, a in result:
print(item, a)
if __name__ == '__main__':
chinese_cv()
#self_cv()
# posseg_cv()
4.3 TF-IDF
-
TF-IDF(Term Frequency-Inverse Document Frequency,词频-逆文档频率)是一种常用的文本特征表示方法,用于评估一个词对一个文档或语料库中的重要程度。如:
-
如果一个词或短语在一篇文章中出现的概率高,但在其他文章中出现的概率少,则任务此词或者短语有很好的类别区分能力,适合用来分类。
-
-
词频(Frequency):一个词在语料库中出现的次数,词频越高,说明该词在该文档中的相对重要性
-
词频概率:通常指的是归一化后的词频。
-
词在文档中出现的次数除以文档总词数,用来衡量这个词在整个文档中的相对重要性:
词在文档中出现的次数文档中词的总数
-
-
例如,如果词 cat 在一篇包含 100 个词的文章中出现了 5 次,那么它的词频概率为:
-
-
-
逆文档频率:词语在整个文档集合中的重要程度
-
TF-IDF稀有文本特征提取将CountVectorizer和TfidTransformer的所有功能组合在一个模型中
-
TfidTransformer将词频/字符频数矩阵转换为标准化的tf或tf-idf矩阵。
-
-
TF-IDF是两个指标的乘积:词频(TF)和逆文档频率(IDF),两个部分的计算公式如下:
-
逆文档频率(IDF):出现频率较低的词语会有较高的 IDF 值,从而提高其在文档中的权重,这里加 1 是为了防止除数为零的情况,并且确保 IDF 不会为负数
-
文档总数包含该词语的文件的数目数
-
TF-IDF:通过 TF-IDF 评分,重要的词语(即在该文档中频繁出现而在其他文档中不常见的词语)会得到较高的权重
-
TfidfVectorizer 是 scikit-learn 提供的一个工具,用于将文本数据转换为 TF-IDF 特征矩阵,函数介绍如下:
-
| 参数名 | 类型 | 默认值 | 描述说明 |
|---|---|---|---|
stop_words | string 或 list | None | 指定要忽略的停用词集合:<br> - 若设为 'english',则会使用内建的英语停用词(如 "is", "the" 等)<br> - 也可以传入一个自定义的停用词列表<br> - 单个字母(如 "i"、"a")通常会被自动忽略 |
use_idf | bool | True | 是否启用 IDF(逆文档频率)加权:<br> - 设为 True:使用 TF-IDF 权重计算<br> - 设为 False:仅使用 TF(词频)并归一化 |
smooth_idf | bool | True | 是否对 IDF 进行平滑处理:<br> - 加1平滑,防止除以0的情况,使计算更稳定 |
norm | string | 'l2' | 归一化方式:<br> - 'l1':L1 范数归一化(所有特征绝对值之和为1)<br> - 'l2':L2 范数归一化(默认,欧氏距离归一化) |
-
案例代码:
from sklearn.feature_extraction.text import TfidfVectorizer data = [ 'This is the first document', 'This is the second document', 'And the third one', 'Is this the first document', ] tfidf = TfidfVectorizer() X = tfidf.fit_transform(data) print(X.toarray()) print(tfidf.get_feature_names_out())
-
运行结果:
[[0. 0.43877674 0.54197657 0.43877674 0. 0. 0.35872874 0. 0.43877674] [0. 0.40412895 0. 0.40412895 0. 0.63314609 0.33040189 0. 0.40412895] [0.55280532 0. 0. 0. 0.55280532 0. 0.28847675 0.55280532 0. ] [0. 0.43877674 0.54197657 0.43877674 0. 0. 0.35872874 0. 0.43877674]] ['and' 'document' 'first' 'is' 'one' 'second' 'the' 'third' 'this']
-
运行结果计算过程解析:
-
第一步:得到所有唯一词语按字典序排列
['and' 'document' 'first' 'is' 'one' 'second' 'the' 'third' 'this']
-
第二步【这个步骤之后的每个步骤都以文档一为例】:计算词频 TF,得到向量表示形式:
[0, 1, 1, 1, 0, 0, 1, 0, 1]
词 出现次数 and 0 document 1 first 1 is 1 one 0 second 0 the 1 third 0 this 1 -
第三步:计算逆文档频率 IDF
词 出现在哪些文档 出现文档数 IDF 计算 IDF 值(保留4位小数) and d3 1 log(4+1/(1+1)) + 1 ≈ log(5/2) + 1 ln(2.5) + 1 ≈ 1.9163 document d1, d2, d4 3 log(4+1/(3+1)) + 1 = log(5/4) + 1 ln(1.25) + 1 ≈ 1.2231 first d1, d4 2 log(4+1/(2+1)) + 1 ≈ log(5/3) + 1 ln(1.6667) + 1 ≈ 1.5108 is d1, d2, d4 3 log(4+1/(3+1)) + 1 ≈ log(5/4) + 1 ln(1.25) + 1 ≈ 1.2231 one d3 1 log(4+1/(1+1)) + 1 ≈ log(5/2) + 1 ln(2.5) + 1 ≈ 1.9163 second d2 1 log(4+1/(1+1)) + 1 ≈ log(5/2) + 1 ln(2.5) + 1 ≈ 1.9163 the d1, d2, d3, d4 4 log(4+1/(4+1)) + 1 ≈ log(5/5) + 1 ln(1.0) + 1 = 1.0000 third d3 1 log(4+1/(1+1)) + 1 ≈ log(5/2) + 1 ln(2.5) + 1 ≈ 1.9163 this d1, d2, d4 3 log(4+1/(3+1)) + 1 ≈ log(5/4) + 1 ln(1.25) + 1 ≈ 1.2231 -
第四步:计算 TF-IDF
词 TF IDF TF-IDF(= TF × IDF) and 0 1.9163 0 document 1 1.2231 1.2231 first 1 1.5108 1.5108 is 1 1.2231 1.2231 one 0 1.9163 0 second 0 1.9163 0 the 1 1.0000 1.0000 third 0 1.9163 0 this 1 1.2231 1.2231 -
第五步:L2 归一化(默认 norm='l2')

-
分母
| 词 | TF-IDF | 归一化后值(保留4位小数) |
|---|---|---|
| and | 0.0000 | 0.0000 |
| document | 1.2231 | 0.4388 |
| first | 1.5108 | 0.5420 |
| is | 1.2231 | 0.4388 |
| one | 0.0000 | 0.0000 |
| second | 0.0000 | 0.0000 |
| the | 1.0000 | 0.3587 |
| third | 0.0000 | 0.0000 |
| this | 1.2231 | 0.4388 |
4.3.1 练习
-
手写代码实现 TF-IDF
-
参考代码:
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.preprocessing import normalize
data = [
'This is the first document',
'This is the second document',
'And the third one',
'Is this the first document',
]
vectorizer = CountVectorizer()
x = vectorizer.fit_transform(data)
tf = x.toarray()
print("词频矩阵:\n", tf)
fenzi = len(data) + 1
print("分子:\n", fenzi)
fenmu = np.sum(tf!=0, axis=0) + 1
print("分母:\n", fenmu)
idf = np.log(fenzi / fenmu) + 1
print("idf:\n", idf)
tf_idf = tf * idf
print("tfidf:\n", tf_idf)
tf_idf = normalize(tf_idf, norm="l2", axis=1)
print("归一化tf_idf:\n", tf_idf)
作业 2025.8.08
-
完成jieba分词任务,基于data = ["教育学会会长期间坚定支持民办教育事业!", "热忱关心、扶持民办学校发展", "事业做出重大贡献!"]完成下图输出
解答程序:
import jieba
import pandas as pd
from sklearn.feature_extraction.text import CountVectorizer
def chinese_cv():
#创建数据
data = ["教育学会会长期间坚定支持民办教育事业!",
"热忱关心、扶持民办学校发展",
"事业做出重大贡献!"]
#仅是显示划分结果
result1=[]
for s in data:
r=jieba.lcut(s)
result1.append(" ".join(r))
print(result1)
#自定义分词器
def chinese_tokenizer(text):
return jieba.lcut(text)
#创建对象
cv1 = CountVectorizer(tokenizer=chinese_tokenizer,stop_words={'!', '、'})#使用自定义分词器
result1_vector = cv1.fit_transform(data) # 直接使用原始data
print(result1_vector.toarray())
#查看特征名字
print(cv1.get_feature_names_out())
col=cv1.get_feature_names_out()
#将对应列名与矩阵内容对应起来,形成数据帧
df=pd.DataFrame(result1_vector.toarray(),columns=col)
print(df.to_string(index=False))#使用to_string方法不显示索引
if __name__ =="__main__":
chinese_cv()
运行结果:

-
手写代码实现TF-IDF
-
准备数据集
-
分词,英文不需要
-
使用countVectorizer统计词语的次数 --- 得到 TF
-
利用数学公式log(....)+1计算IDF,IDF使用l2正则化
-
TF*IDF
-
在调用api,查看自己是否计算正确
程序:
def two(): data2 = ['This is the first document.', 'This document is the second document.', 'And this is the third one.', 'Is this the first document?', 'this is an apple.'] cv2 = CountVectorizer(stop_words={'an', 'and', 'the'}) tf = cv2.fit_transform(data2) print("===================") print(tf.toarray()) tf_array = tf.toarray() tf_transposed = tf_array.T doc_frequency = [] # 计算包含该词的文档数量 for items in tf_transposed: non_zero_docs = sum(1 for item in items if item > 0) """ 注意non_zero_docs是要计算每个词出现的文档次数, 不是每个词出现的总次数 """ doc_frequency.append(non_zero_docs) print("文档频率:", doc_frequency) print("特征词:", cv2.get_feature_names_out()) # 使用与sklearn TfidfVectorizer相同的IDF公式 N = len(data2) # sklearn的默认IDF公式: log((N + 1) / (df + 1)) + 1 idf = [math.log((N + 1) / (df + 1)) + 1 for df in doc_frequency] print("IDF值:", idf) # 计算TF-IDF idf_array = np.array(idf) tf_idf = tf_array * idf_array # print("TF-IDF矩阵:") # print(tf_idf) #正则化,需要进行广播 tf_idf_normalizer=tf_idf/np.sqrt(np.sum(tf_idf**2,axis=1,keepdims=True)) print("正则化后的TF-IDF矩阵:",tf_idf_normalizer) -
# 如果要与TfidfVectorizer(norm=None)完全一致,还需要进行L2正则化 # 但既然要比较非正则化结果,就不需要这一步
def three():
def two():
data2 = ['This is the first document.',
'This document is the second document.',
'And this is the third one.',
'Is this the first document?',
'this is an apple.']
cv2 = CountVectorizer(stop_words={'an', 'and', 'the'})
tf = cv2.fit_transform(data2)
print("===================")
print(tf.toarray())
tf_array = tf.toarray()
tf_transposed = tf_array.T
doc_frequency = []
# 计算包含该词的文档数量
for items in tf_transposed:
non_zero_docs = sum(1 for item in items if item > 0)
"""
注意non_zero_docs是要计算每个词出现的文档次数,
不是每个词出现的总次数
"""
doc_frequency.append(non_zero_docs)
print("文档频率:", doc_frequency)
print("特征词:", cv2.get_feature_names_out())
# 使用与sklearn TfidfVectorizer相同的IDF公式
N = len(data2)
# sklearn的默认IDF公式: log((N + 1) / (df + 1)) + 1
idf = [math.log((N + 1) / (df + 1)) + 1 for df in doc_frequency]
print("IDF值:", idf)
# 计算TF-IDF
idf_array = np.array(idf)
tf_idf = tf_array * idf_array
# print("TF-IDF矩阵:")
# print(tf_idf)
#正则化
tf_idf_normalizer=tf_idf/np.sqrt(np.sum(tf_idf**2,axis=1,keepdims=True))
print("正则化后的TF-IDF矩阵:",tf_idf_normalizer)
结果对比:

TfidVectorizer:

结果对比没出错,在过程中容易把公式输入的小细节弄错。
&spm=1001.2101.3001.5002&articleId=150217465&d=1&t=3&u=3abccd958d574876aa5c0d98a8941241)
480

被折叠的 条评论
为什么被折叠?



