当前位置: 首页 > article >正文

自然语言处理:文本聚类

介绍

大家好,博主又来和大家分享自然语言处理领域的知识了。今天给大家分享的内容是自然语言处理中文本聚类

文本聚类在自然语言处理领域占据着重要地位,它能将大量无序的文本按照内容的相似性自动划分成不同的类别,极大地提高了文本处理和信息提取的效率。就好比在一个大型图书馆中,文本聚类能够像智能管理员一样,把各种书籍按照主题分类摆放,方便读者快速找到所需资料。

而实现文本聚类的方法有很多,其中k均值聚类算法基于高斯混合模型的最大期望值算法,以及无监督朴素贝叶斯模型是比较常用的。好了,话不多说,我们直接进入正题。

文本聚类

k均值聚类算法

k均值聚类算法是一种简单且经典的聚类算法。它的核心思想就像是在一群人中寻找几个代表,让其他人都围绕着这些代表“站队”

具体来说,我们首先要确定聚类的数量k,这个k就像是我们设定的几个“代表小组”的数量。然后随机选择k个文本作为初始的聚类中心,就好像是先选了几个有代表性的人。接下来,计算每个文本与这k个聚类中心的距离,把文本分配到距离最近的聚类中心所代表的类别中。之后,不断地重新计算每个类别中所有文本的中心位置,也就是更新聚类中心,就像代表们根据自己所在小组的人员情况调整位置一样。重复这个过程,直到聚类中心不再变化或者变化很小,此时就完成了文本聚类。

这种算法的优点是简单易懂、计算效率高,对于大规模文本数据的处理有较好的可扩展性。但它也有一些缺点,比如需要预先指定聚类的数量k,这个k值如果选择不当,可能会导致聚类结果不理想;而且它对初始聚类中心的选择比较敏感,不同的初始中心可能会得到不同的聚类结果。

接下来,我们将着手实现k均值算法,以此来开展文本聚类的工作。此次所运用的数据集涵盖了大约1万本图书的相关信息,并且这些图书被划分为3种不同的主题类别。在这个数据集中,我们所关注的文本内容并非图书的标题,而是图书的摘要部分。我们用代码来演示:

预处理完整代码

nlp_book_data_collection.py

# 导入用于处理JSON数据的库
import json
# 导入defaultdict类,用于创建具有默认值的字典
from collections import defaultdict
# 导入spaCy库,用于自然语言处理
import spacy
# 从spaCy的中文停用词模块中导入停用词集合
from spacy.lang.zh.stop_words import STOP_WORDS
# 导入tqdm库,用于显示进度条
from tqdm import tqdm# 加载中文语言模型
nlp_model = spacy.load('zh_core_web_sm')# 定义一个类,用于收集和处理书籍数据
class BookDataCollection:# 类的初始化方法def __init__(self):# 训练集和测试集的文件名self.training_file, self.testing_file = 'train_original.jsonl', 'test_original.jsonl'self.init_data()# 定义一个内部函数,用于读取JSONL文件def read_json_file(self, file_path):# 以只读模式打开文件,并指定编码为UTF-8with open(file_path, 'r', encoding='utf-8') as file:# 将文件的每一行读取为一个列表json_lines = list(file)# 初始化一个空列表,用于存储解析后的JSON数据data_list = []# 遍历每一行JSON数据for json_str in json_lines:# 将JSON字符串解析为Python对象,并添加到数据列表中data_list.append(json.loads(json_str))# 返回解析后的数据列表return data_listdef init_data(self):# 调用read_json_file函数读取训练集和测试集数据self.training_data, self.testing_data = self.read_json_file(self.training_file), self.read_json_file(self.testing_file)# 打印训练集和测试集的大小print('训练集大小 =', len(self.training_data), ', 测试集大小 =', len(self.testing_data))# 初始化两个空字典,用于存储标签到ID和ID到标签的映射self.label_to_id, self.id_to_label = {}, {}# 遍历训练集和测试集数据for data_group in [self.training_data, self.testing_data]:# 遍历每个数据项for data_item in data_group:# 获取数据项的类别标签category = data_item['class']# 如果类别标签不在标签到ID的映射中if category not in self.label_to_id:# 生成一个新的IDindex = len(self.label_to_id)# 将类别标签和对应的ID添加到标签到ID的映射中self.label_to_id[category] = index# 将ID和对应的类别标签添加到ID到标签的映射中self.id_to_label[index] = category# 获取类别标签对应的IDlabel_index = self.label_to_id[category]# 在数据项中添加标签ID字段data_item['label'] = label_index# 定义一个方法,用于对文本进行分词处理def tokenize_text(self, attribute='book'):# 遍历训练集和测试集数据for data_group in [self.training_data, self.testing_data]:# 使用tqdm显示进度条,遍历每个数据项for data_item in tqdm(data_group):# 获取数据项指定属性的文本内容,并转换为小写text_content = data_item[attribute].lower()# 使用spaCy模型对文本进行处理,过滤掉停用词,并提取词元tokens = [token.text for token in nlp_model(text_content) if token.text not in STOP_WORDS]# 在数据项中添加分词结果字段data_item['tokens'] = tokens# 定义一个方法,用于创建词汇表def create_vocabulary(self, min_frequency=3, min_length=2, max_vocab_size=None):# 初始化一个defaultdict,用于统计词元的频率word_frequency = defaultdict(int)# 遍历训练集数据for data_item in self.training_data:# 获取数据项的分词结果tokens = data_item['tokens']# 遍历每个词元for token in tokens:# 统计词元的频率word_frequency[token] += 1# 打印唯一词元数量、总词元数量、最大词频和最小词频print(f'唯一词元数量 = {len(word_frequency)}, 总词元数量 = {sum(word_frequency.values())}, 'f'最大词频 = {max(word_frequency.values())}, 最小词频 = {min(word_frequency.values())}')# 初始化两个空字典,用于存储词元到ID和ID到词元的映射self.token_to_id = {}self.id_to_token = {}# 初始化总词频为0total_frequency = 0# 按词频从高到低对词元进行排序,并遍历for token, freq in sorted(word_frequency.items(), key=lambda x: -x[1]):# 如果指定了最大词汇表大小,且当前词汇表大小已达到最大值if max_vocab_size and len(self.token_to_id) >= max_vocab_size:# 跳出循环break# 如果词元的频率大于最小频率if freq > min_frequency:# 如果未指定最小词长,或者词元长度大于等于最小词长if (min_length is None) or (min_length and len(token) >= min_length):# 将词元添加到词元到ID的映射中,并分配一个新的IDself.token_to_id[token] = len(self.token_to_id)# 将ID添加到ID到词元的映射中,并关联对应的词元self.id_to_token[len(self.id_to_token)] = token# 累加词元的频率到总词频中total_frequency += freqelse:# 跳出循环break# 打印最小词频、最小词长、最大词汇表大小、剩余词元数量和词表内词元占比print(f'最小词频 = {min_frequency}, 最小词长 = {min_length}, 最大词表大小 = {max_vocab_size}, 'f'剩余词元数量 = {len(self.token_to_id)}, 'f'词表内词元占比 = {total_frequency / sum(word_frequency.values())}')# 定义一个方法,用于将词元转换为对应的IDdef convert_tokens_to_indices(self):# 遍历训练集和测试集数据for data_group in [self.training_data, self.testing_data]:# 遍历每个数据项for data_item in data_group:# 初始化一个空列表,用于存储词元对应的IDdata_item['token_indices'] = []# 遍历数据项的分词结果for token in data_item['tokens']:# 如果词元在词元到ID的映射中if token in self.token_to_id:# 将词元对应的ID添加到列表中data_item['token_indices'].append(self.token_to_id[token])

nlp_text_clustering.py

# 从book_data_container模块导入BookDataContainer类
from nlp_book_data_collection import BookDataCollection# 定义一个用于自然语言处理文本聚类的类
class NLPTextClustering:def __init__(self):passdef text_clustering(self):# 创建书籍数据集对象book_dataset = BookDataCollection()# 打印标签到ID的映射print(book_dataset.id_to_label)# 对文本进行分词处理book_dataset.tokenize_text(attribute='abstract')# 创建词汇表book_dataset.create_vocabulary(min_frequency=3)# 将词元转换为索引book_dataset.convert_tokens_to_indices()# 程序入口,当作为脚本直接运行时执行以下代码
if __name__ == "__main__":# 创建NLPTextClustering类的一个实例nlp_text_clustering = NLPTextClustering()# 调用实例的text_clustering方法进行文本聚类操作nlp_text_clustering.text_clustering()

预处理运行结果

训练集大小 = 8626 , 测试集大小 = 2156
{0: '计算机类', 1: '艺术传媒类', 2: '经管类'}
100%|██████████| 8626/8626 [02:29<00:00, 57.74it/s]
100%|██████████| 2156/2156 [00:37<00:00, 56.76it/s]
唯一词元数量 = 34251, 总词元数量 = 806791, 最大词频 = 19194, 最小词频 = 1
最小词频 = 3, 最小词长 = 2, 最大词表大小 = None, 剩余词元数量 = 9504, 词表内词元占比 = 0.8910448926673699进程已结束,退出代码为 0

然后,我们引入实现TF-IDF算法的相关函数,并把经过处理的数据集输入至该函数内,从而获取文档的特征信息。我们用代码来演示:

特征信息完整代码

nlp_tfidf_transformer.py

# 导入numpy库,用于进行数值计算
import numpy as np# 定义一个类,用于进行TF-IDF转换
class TFIDFTransformer:# 类的初始化方法def __init__(self, vocabulary_size, normalization='l2', smooth_idf_flag=True, sublinear_tf_flag=True):# 存储词汇表大小self.vocabulary_size = vocabulary_size# 存储归一化方法self.normalization = normalization# 存储是否进行平滑IDF计算的标志self.smooth_idf_flag = smooth_idf_flag# 存储是否进行子线性TF计算的标志self.sublinear_tf_flag = sublinear_tf_flag# 定义一个方法,用于拟合数据,计算IDF值def fit_data(self, input_data):# 初始化一个全零数组,用于存储每个词元的文档频率document_frequency = np.zeros(self.vocabulary_size, dtype=np.float64)# 遍历输入数据for data_item in input_data:# 遍历数据项中唯一的词元IDfor token_index in set(data_item):# 统计词元的文档频率document_frequency[token_index] += 1# 根据平滑IDF标志,对文档频率进行平滑处理document_frequency += int(self.smooth_idf_flag)# 计算样本数量,并根据平滑IDF标志进行调整num_samples = len(input_data) + int(self.smooth_idf_flag)# 计算每个词元的IDF值self.idf = np.log(num_samples / document_frequency) + 1# 定义一个方法,用于对输入数据进行转换def transform_data(self, input_data):# 确保已经计算了IDF值assert hasattr(self, 'idf')# 初始化一个全零矩阵,用于存储词频矩阵term_frequency = np.zeros((len(input_data), self.vocabulary_size), dtype=np.float64)# 遍历输入数据for i, data_item in enumerate(input_data):# 遍历数据项中的词元IDfor token in data_item:# 统计词元的词频term_frequency[i, token] += 1# 如果启用了子线性TF计算if self.sublinear_tf_flag:# 对词频矩阵进行子线性变换term_frequency = np.log(term_frequency + 1)# 计算TF-IDF矩阵transformed_data = term_frequency * self.idf# 如果启用了归一化if self.normalization:# 计算每行的L2范数row_norm = (transformed_data ** 2).sum(axis=1)# 将范数为0的行的范数设为1,避免除零错误row_norm[row_norm == 0] = 1# 对TF-IDF矩阵进行归一化处理transformed_data /= np.sqrt(row_norm)[:, None]# 返回转换后的矩阵return transformed_data# 定义一个方法,用于拟合数据并进行转换def fit_and_transform(self, input_data):# 调用fit_data方法拟合数据self.fit_data(input_data)# 调用transform_data方法进行转换return self.transform_data(input_data)

nlp_text_clustering.py

# 从nlp_book_data_collection模块导入BookDataCollection类
from nlp_book_data_collection import BookDataCollection
# 从nlp_tfidf_transformer模块导入TFIDFTransformer类
from nlp_tfidf_transformer import TFIDFTransformer# 定义一个用于自然语言处理文本聚类的类
class NLPTextClustering:def __init__(self):passdef text_clustering(self):# 创建书籍数据集对象book_dataset = BookDataCollection()# 打印标签到ID的映射print(book_dataset.id_to_label)# 对文本进行分词处理book_dataset.tokenize_text(attribute='abstract')# 创建词汇表book_dataset.create_vocabulary(min_frequency=3)# 将词元转换为索引book_dataset.convert_tokens_to_indices()# 获取训练集和测试集数据training_data, testing_data = book_dataset.training_data, book_dataset.testing_data# 获取词汇表大小vocabulary_size = len(book_dataset.token_to_id)# 初始化训练输入列表training_input = []# 遍历训练数据for data_item in training_data:# 将词元索引添加到训练输入列表training_input.append(data_item['token_indices'])# 创建TF-IDF转换器对象tfidf_transformer = TFIDFTransformer(vocabulary_size, normalization='l2', smooth_idf_flag=True,sublinear_tf_flag=True)# 拟合训练数据tfidf_transformer.fit_data(training_input)# 转换训练数据training_features = tfidf_transformer.transform_data(training_input)# 打印训练特征的形状print(training_features.shape)# 程序入口,当作为脚本直接运行时执行以下代码
if __name__ == "__main__":# 创建NLPTextClustering类的一个实例nlp_text_clustering = NLPTextClustering()# 调用实例的text_clustering方法进行文本聚类操作nlp_text_clustering.text_clustering()

特征信息运行结果

训练集大小 = 8626 , 测试集大小 = 2156
{0: '计算机类', 1: '艺术传媒类', 2: '经管类'}
100%|██████████| 8626/8626 [02:29<00:00, 57.74it/s]
100%|██████████| 2156/2156 [00:37<00:00, 56.76it/s]
唯一词元数量 = 34251, 总词元数量 = 806791, 最大词频 = 19194, 最小词频 = 1
最小词频 = 3, 最小词长 = 2, 最大词表大小 = None, 剩余词元数量 = 9504, 词表内词元占比 = 0.8910448926673699
(8626, 9504)进程已结束,退出代码为 0

当获取到数据后,便可运用k均值聚类算法对文本展开聚类操作。在此过程中,一个关键的前提是要预先设定簇数K。为了便于与实际的标签数据进行对照分析,此次设定K值为 3。下面,我们用代码来演示:

聚类操作完整代码

nlp_kmeans_clusterer.py

# 导入NumPy库,用于数值计算
import numpy as np# 定义一个类,用于实现K-Means聚类算法
class KMeansClusterer:# 类的初始化方法def __init__(self, num_clusters, data_dimension, stop_threshold=1e-4, max_steps=100):# 存储聚类的数量self.num_clusters = num_clusters# 存储数据的维度self.data_dimension = data_dimension# 存储停止迭代的阈值self.stop_threshold = stop_threshold# 存储最大迭代步数self.max_steps = max_steps# 定义一个方法,用于更新聚类中心def update_cluster_centers(self, input_data):# 初始化一个全零矩阵,用于存储聚类中心cluster_centers = np.zeros([self.num_clusters, self.data_dimension])# 遍历每个聚类for k in range(self.num_clusters):# 获取属于当前聚类的数据点cluster_data = input_data[self.cluster_assignments == k]# 如果当前聚类中有数据点if len(cluster_data) > 0:# 计算当前聚类的中心cluster_centers[k] = cluster_data.mean(axis=0)# 返回更新后的聚类中心return cluster_centers# 定义一个方法,用于拟合模型def fit_model(self, input_data):# 打印初始化信息print('-----------初始化-----------')# 获取输入数据的样本数量num_samples = len(input_data)# 获取输入数据的维度data_dim = len(input_data[0])# 随机初始化每个数据点的聚类分配self.cluster_assignments = np.random.randint(0, self.num_clusters, num_samples)# 调用update_cluster_centers方法更新聚类中心self.cluster_centers = self.update_cluster_centers(input_data)# 打印初始化完成信息print('-----------初始化完成-----------')# 初始化当前迭代步数为0current_step = 0# 当当前迭代步数小于最大迭代步数时,继续迭代while current_step < self.max_steps:# 迭代步数加1current_step += 1# 初始化每个数据点的聚类分配为0self.cluster_assignments = np.zeros(num_samples, int)# 遍历每个数据点for i, data_point in enumerate(input_data):# 计算每个数据点和每个簇中心的L2距离distances = np.linalg.norm(data_point[None, :] - self.cluster_centers, ord=2, axis=-1)# 找到每个数据点所属新的聚类self.cluster_assignments[i] = distances.argmin(-1)# 调用update_cluster_centers方法更新聚类中心new_cluster_centers = self.update_cluster_centers(input_data)# 计算聚类中心的平均移动距离center_movement = np.linalg.norm(new_cluster_centers - self.cluster_centers, ord=2, axis=-1).mean()# 打印当前迭代步数和聚类中心的平均移动距离print(f"第{current_step}步,中心点平均移动距离:{center_movement}")# 如果聚类中心的平均移动距离小于停止迭代的阈值if center_movement < self.stop_threshold:# 打印停止迭代信息print("中心点不再移动,退出程序")# 跳出循环break# 更新聚类中心self.cluster_centers = new_cluster_centers

nlp_text_clustering.py

# 从nlp_book_data_collection模块导入BookDataCollection类
from nlp_book_data_collection import BookDataCollection
# 从nlp_tfidf_transformer模块导入TFIDFTransformer类
from nlp_tfidf_transformer import TFIDFTransformer
# 从nlp_kmeans_clusterer模块导入KMeansClusterer类
from nlp_kmeans_clusterer import KMeansClusterer# 聚类的数量
num_clusters = 3# 定义一个用于自然语言处理文本聚类的类
class NLPTextClustering:def __init__(self):passdef text_clustering(self):# 创建书籍数据集对象book_dataset = BookDataCollection()# 打印标签到ID的映射print(book_dataset.id_to_label)# 对文本进行分词处理book_dataset.tokenize_text(attribute='abstract')# 创建词汇表book_dataset.create_vocabulary(min_frequency=3)# 将词元转换为索引book_dataset.convert_tokens_to_indices()# 获取训练集和测试集数据training_data, testing_data = book_dataset.training_data, book_dataset.testing_data# 获取词汇表大小vocabulary_size = len(book_dataset.token_to_id)# 初始化训练输入列表training_input = []# 遍历训练数据for data_item in training_data:# 将词元索引添加到训练输入列表training_input.append(data_item['token_indices'])# 创建TF-IDF转换器对象tfidf_transformer = TFIDFTransformer(vocabulary_size, normalization='l2', smooth_idf_flag=True,sublinear_tf_flag=True)# 拟合训练数据tfidf_transformer.fit_data(training_input)# 转换训练数据training_features = tfidf_transformer.transform_data(training_input)# 打印训练特征的形状print(training_features.shape)# 创建K-Means聚类器对象kmeans_clusterer = KMeansClusterer(num_clusters, training_features.shape[1])# 拟合训练特征kmeans_clusterer.fit_model(training_features)# 程序入口,当作为脚本直接运行时执行以下代码
if __name__ == "__main__":# 创建NLPTextClustering类的一个实例nlp_text_clustering = NLPTextClustering()# 调用实例的text_clustering方法进行文本聚类操作nlp_text_clustering.text_clustering()
训练集大小 = 8626 , 测试集大小 = 2156
{0: '计算机类', 1: '艺术传媒类', 2: '经管类'}
100%|██████████| 8626/8626 [03:05<00:00, 46.54it/s]
100%|██████████| 2156/2156 [00:36<00:00, 58.80it/s]
唯一词元数量 = 34251, 总词元数量 = 806791, 最大词频 = 19194, 最小词频 = 1
最小词频 = 3, 最小词长 = 2, 最大词表大小 = None, 剩余词元数量 = 9504, 词表内词元占比 = 0.8910448926673699
(8626, 9504)
-----------初始化-----------
-----------初始化完成-----------
第1步,中心点平均移动距离:0.06890890571733081
第2步,中心点平均移动距离:0.05478241286369078
第3步,中心点平均移动距离:0.018892396863314006
第4步,中心点平均移动距离:0.013429342825043227
第5步,中心点平均移动距离:0.013566480916429499
第6步,中心点平均移动距离:0.013989222795632706
第7步,中心点平均移动距离:0.011440477943083664
第8步,中心点平均移动距离:0.007103963059848575
第9步,中心点平均移动距离:0.006074946365616077
第10步,中心点平均移动距离:0.00477369638045405
第11步,中心点平均移动距离:0.0037873833801874888
第12步,中心点平均移动距离:0.003169778238863545
第13步,中心点平均移动距离:0.0026544650799152428
第14步,中心点平均移动距离:0.0029003953549483793
第15步,中心点平均移动距离:0.002845907460494008
第16步,中心点平均移动距离:0.0029565530700650586
第17步,中心点平均移动距离:0.0046409302413431995
第18步,中心点平均移动距离:0.007601779316323283
第19步,中心点平均移动距离:0.008556943854755123
第20步,中心点平均移动距离:0.007326270837156583
第21步,中心点平均移动距离:0.004774654456463306
第22步,中心点平均移动距离:0.004131223162570739
第23步,中心点平均移动距离:0.0034665383237183632
第24步,中心点平均移动距离:0.0028326750163131242
第25步,中心点平均移动距离:0.0024085910806691804
第26步,中心点平均移动距离:0.0025467882048793647
第27步,中心点平均移动距离:0.0024867293424594233
第28步,中心点平均移动距离:0.00232851482144344
第29步,中心点平均移动距离:0.002858996918517763
第30步,中心点平均移动距离:0.0027176858630063097
第31步,中心点平均移动距离:0.0024908107307621374
第32步,中心点平均移动距离:0.002725824149863784
第33步,中心点平均移动距离:0.0029918663142641765
第34步,中心点平均移动距离:0.0021179114918197877
第35步,中心点平均移动距离:0.0019590759238497786
第36步,中心点平均移动距离:0.0021350571707413643
第37步,中心点平均移动距离:0.0029617190015900938
第38步,中心点平均移动距离:0.0033936270370122233
第39步,中心点平均移动距离:0.0029231439612436316
第40步,中心点平均移动距离:0.0032854686271343914
第41步,中心点平均移动距离:0.0031848632066834794
第42步,中心点平均移动距离:0.003748152169792271
第43步,中心点平均移动距离:0.0034990023467288468
第44步,中心点平均移动距离:0.003588666039850141
第45步,中心点平均移动距离:0.003444720739168902
第46步,中心点平均移动距离:0.004132389860665119
第47步,中心点平均移动距离:0.0042080010326193
第48步,中心点平均移动距离:0.004440204058509182
第49步,中心点平均移动距离:0.002555459672126323
第50步,中心点平均移动距离:0.0025740606612964256
第51步,中心点平均移动距离:0.0017377711466915063
第52步,中心点平均移动距离:0.001173105458515561
第53步,中心点平均移动距离:0.0014038477302960907
第54步,中心点平均移动距离:0.002010183332161079
第55步,中心点平均移动距离:0.0025465099651279664
第56步,中心点平均移动距离:0.003412787991913555
第57步,中心点平均移动距离:0.00491581405490893
第58步,中心点平均移动距离:0.006009725805675484
第59步,中心点平均移动距离:0.0030275349972018945
第60步,中心点平均移动距离:0.0023261247949924505
第61步,中心点平均移动距离:0.0019728143627690867
第62步,中心点平均移动距离:0.0021625513846364737
第63步,中心点平均移动距离:0.001665616845718412
第64步,中心点平均移动距离:0.000931590997003939
第65步,中心点平均移动距离:0.001013041855168734
第66步,中心点平均移动距离:0.0008405371362220621
第67步,中心点平均移动距离:0.001367543177768866
第68步,中心点平均移动距离:0.0014425643303775304
第69步,中心点平均移动距离:0.001116963591121085
第70步,中心点平均移动距离:0.001491048450742236
第71步,中心点平均移动距离:0.002040608920857972
第72步,中心点平均移动距离:0.0036833183433489704
第73步,中心点平均移动距离:0.010667221023078093
第74步,中心点平均移动距离:0.022518116498817724
第75步,中心点平均移动距离:0.019497945687248934
第76步,中心点平均移动距离:0.012781228163674337
第77步,中心点平均移动距离:0.006360174137399897
第78步,中心点平均移动距离:0.004201484107008095
第79步,中心点平均移动距离:0.0035826113950724998
第80步,中心点平均移动距离:0.0037105073591507513
第81步,中心点平均移动距离:0.00219649791629415
第82步,中心点平均移动距离:0.0015802391154533663
第83步,中心点平均移动距离:0.001539134331937778
第84步,中心点平均移动距离:0.0
中心点不再移动,退出程序进程已结束,退出代码为 0

为了能更直观地呈现聚类效果,我们定义了display_clusters()函数,它的作用是展示每个真实分类下各个簇的占比情况。接下来,我们会利用这个函数展示k均值算法的聚类结果,借此观察3个标签中不同簇的占比情况。 我们用代码来演示:

聚类结果完整代码

nlp_text_clustering.py

# 从nlp_book_data_collection模块导入BookDataCollection类
from nlp_book_data_collection import BookDataCollection
# 从nlp_tfidf_transformer模块导入TFIDFTransformer类
from nlp_tfidf_transformer import TFIDFTransformer
# 从nlp_kmeans_clusterer模块导入KMeansClusterer类
from nlp_kmeans_clusterer import KMeansClusterer# 聚类的数量
num_clusters = 3# 定义一个用于自然语言处理文本聚类的类
class NLPTextClustering:def __init__(self):passdef display_clusters(self, cluster_assignments, num_clusters, book_dataset, labels_list):# 初始化标签聚类字典label_clusters = {label_id: {} for label_id in book_dataset.id_to_label}# 初始化每个标签下每个聚类的计数为0for k, v in label_clusters.items():label_clusters[k] = {i: 0 for i in range(num_clusters)}# 遍历标签和聚类分配for label_id, cluster_id in zip(labels_list, cluster_assignments):# 增加对应标签和聚类的计数label_clusters[label_id][cluster_id] += 1# 按标签ID排序遍历for label_id in sorted(book_dataset.id_to_label.keys()):# 初始化聚类信息字符串cluster_str = book_dataset.id_to_label[label_id] + ':\t{ '# 遍历每个聚类for cluster_id in range(num_clusters):# 获取当前聚类的计数count = label_clusters[label_id][cluster_id]# 计算总数total = sum(label_clusters[label_id].values())# 拼接聚类信息cluster_str += f'{str(cluster_id)}: {count}({count / total:.2f}), '# 结束聚类信息字符串cluster_str += '}'# 打印聚类信息print(cluster_str)def text_clustering(self):# 创建书籍数据集对象book_dataset = BookDataCollection()# 打印标签到ID的映射print(book_dataset.id_to_label)# 对文本进行分词处理book_dataset.tokenize_text(attribute='abstract')# 创建词汇表book_dataset.create_vocabulary(min_frequency=3)# 将词元转换为索引book_dataset.convert_tokens_to_indices()# 获取训练集和测试集数据training_data, testing_data = book_dataset.training_data, book_dataset.testing_data# 获取词汇表大小vocabulary_size = len(book_dataset.token_to_id)# 初始化训练输入列表training_input = []# 遍历训练数据for data_item in training_data:# 将词元索引添加到训练输入列表training_input.append(data_item['token_indices'])# 创建TF-IDF转换器对象tfidf_transformer = TFIDFTransformer(vocabulary_size, normalization='l2', smooth_idf_flag=True,sublinear_tf_flag=True)# 拟合训练数据tfidf_transformer.fit_data(training_input)# 转换训练数据training_features = tfidf_transformer.transform_data(training_input)# 打印训练特征的形状print(training_features.shape)# 创建K-Means聚类器对象kmeans_clusterer = KMeansClusterer(num_clusters, training_features.shape[1])# 拟合训练特征kmeans_clusterer.fit_model(training_features)# 初始化标签列表labels_list = []# 遍历训练数据for data_item in training_data:# 将标签添加到标签列表labels_list.append(data_item['label'])# 打印标签列表的长度print(len(labels_list))# 获取K-Means聚类结果cluster_assignments = kmeans_clusterer.cluster_assignments# 显示K-Means聚类结果self.display_clusters(cluster_assignments, num_clusters, book_dataset, labels_list)# 程序入口,当作为脚本直接运行时执行以下代码
if __name__ == "__main__":# 创建NLPTextClustering类的一个实例nlp_text_clustering = NLPTextClustering()# 调用实例的text_clustering方法进行文本聚类操作nlp_text_clustering.text_clustering()

聚类结果运行结果

训练集大小 = 8626 , 测试集大小 = 2156
{0: '计算机类', 1: '艺术传媒类', 2: '经管类'}
100%|██████████| 8626/8626 [03:00<00:00, 47.89it/s]
100%|██████████| 2156/2156 [00:36<00:00, 58.84it/s]
唯一词元数量 = 34251, 总词元数量 = 806791, 最大词频 = 19194, 最小词频 = 1
最小词频 = 3, 最小词长 = 2, 最大词表大小 = None, 剩余词元数量 = 9504, 词表内词元占比 = 0.8910448926673699
(8626, 9504)
-----------初始化-----------
-----------初始化完成-----------
第1步,中心点平均移动距离:0.07187923654672244
第2步,中心点平均移动距离:0.044157507688436216
第3步,中心点平均移动距离:0.022896531888343605
第4步,中心点平均移动距离:0.0159488039593934
第5步,中心点平均移动距离:0.012182250613021412
第6步,中心点平均移动距离:0.012091131336056611
第7步,中心点平均移动距离:0.011953069179042916
第8步,中心点平均移动距离:0.007551366337940332
第9步,中心点平均移动距离:0.00607274740895354
第10步,中心点平均移动距离:0.0051005041228621905
第11步,中心点平均移动距离:0.0037475278494419353
第12步,中心点平均移动距离:0.002873947676155657
第13步,中心点平均移动距离:0.0032856197227294393
第14步,中心点平均移动距离:0.0037597515304094073
第15步,中心点平均移动距离:0.005154214384698833
第16步,中心点平均移动距离:0.01429702264635499
第17步,中心点平均移动距离:0.011662801294254196
第18步,中心点平均移动距离:0.01061592695683227
第19步,中心点平均移动距离:0.01964312337838108
第20步,中心点平均移动距离:0.012665767903761787
第21步,中心点平均移动距离:0.005392861470868378
第22步,中心点平均移动距离:0.002772730322582759
第23步,中心点平均移动距离:0.0018288923370850228
第24步,中心点平均移动距离:0.0014922387193858154
第25步,中心点平均移动距离:0.0010964808376660166
第26步,中心点平均移动距离:0.0011809417903345324
第27步,中心点平均移动距离:0.0008189027391701968
第28步,中心点平均移动距离:0.0008794506802535549
第29步,中心点平均移动距离:0.0003873751480754425
第30步,中心点平均移动距离:0.00023008235702405927
第31步,中心点平均移动距离:0.0
中心点不再移动,退出程序
8626
计算机类:	{ 0: 397(0.10), 1: 845(0.22), 2: 2600(0.68), }
艺术传媒类:	{ 0: 177(0.08), 1: 2115(0.92), 2: 7(0.00), }
经管类:	{ 0: 2408(0.97), 1: 36(0.01), 2: 41(0.02), }进程已结束,退出代码为 0

基于高斯混合模型的最大期望值算法

基于高斯混合模型的最大期望值算法则是另一种强大的文本聚类方法。高斯混合模型认为文本数据是由多个高斯分布混合而成的,就好像是把不同颜色的颜料混合在一起。

最大期望值算法通过不断地迭代,分为期望步骤和最大化步骤。在期望步骤中,根据当前的模型参数,计算每个文本属于不同高斯分布的概率,就像是猜测每个文本更可能属于哪一种“颜料”;在最大化步骤中,利用期望步骤得到的概率,重新计算模型的参数,比如高斯分布的均值、方差和权重,就像调整颜料的混合比例。通过这样反复迭代,让模型更好地拟合文本数据,从而实现文本聚类。

这种算法的优势在于能够灵活地拟合复杂的数据分布,对于多模态的数据聚类效果很好,而且它有完善的理论基础。不过,它也存在一些问题,比如计算复杂度比较高,对超参数的选择很敏感,像高斯分布的数量、协方差类型等,而且容易陷入局部最优解,就像在一个复杂的迷宫中,容易被困在某个局部区域,找不到全局最优的聚类结果。

下面,我们来演示怎样运用高斯混合模型进行聚类操作。需要注意的是,高斯混合模型会计算每个数据点属于各个簇的概率分布,在实际应用中,我们通常把概率最高的簇作为最终的聚类输出结果。通过这种方式,我们就能依据数据点的概率分布情况,将它们划分到最合适的簇中,实现文本数据的有效聚类。我们用代码来演示:

高斯混合聚类完整代码

nlp_gaussian_mixture_model.py

# 导入NumPy库,用于数值计算
import numpy as np
# 从scipy库中导入多元正态分布函数
from scipy.stats import multivariate_normal as gaussian# 定义高斯混合模型类
class GaussianMixtureModel:# 初始化方法,设置聚类数量、数据维度和最大迭代次数def __init__(self, num_clusters, data_dimension, max_iterations=100):# 存储聚类数量self.num_clusters = num_clusters# 存储数据维度self.data_dimension = data_dimension# 存储最大迭代次数self.max_iterations = max_iterations# 初始化混合系数,每个聚类初始权重相同self.mixing_coefficients = np.ones(num_clusters) / num_clusters# 随机初始化每个聚类的均值self.means = np.random.rand(num_clusters, data_dimension) * 2 - 1# 初始化协方差矩阵为全零矩阵self.covariances = np.zeros((num_clusters, data_dimension, data_dimension))# 遍历每个聚类for i in range(num_clusters):# 将每个聚类的协方差矩阵设为单位矩阵self.covariances[i] = np.eye(data_dimension)# 期望步骤,计算每个数据点属于每个聚类的概率def expectation_step(self, input_data):# 遍历每个聚类for i in range(self.num_clusters):# 计算每个数据点属于当前聚类的概率self.responsibilities[:, i] = self.mixing_coefficients[i] * gaussian.pdf(input_data, mean=self.means[i],cov=self.covariances[i])# 对概率进行归一化处理self.responsibilities /= self.responsibilities.sum(axis=1, keepdims=True)# 最大化步骤,更新模型参数def maximization_step(self, input_data):# 计算每个聚类的责任权重总和responsibility_sum = self.responsibilities.sum(axis=0)# 更新混合系数self.mixing_coefficients = responsibility_sum / self.num_samples# 更新每个聚类的均值self.means = np.matmul(self.responsibilities.T, input_data) / responsibility_sum[:, None]# 遍历每个聚类for i in range(self.num_clusters):# 计算数据点与当前聚类均值的差值delta = np.expand_dims(input_data, axis=1) - self.means[i]# 计算协方差矩阵covariance = np.matmul(delta.transpose(0, 2, 1), delta)# 更新当前聚类的协方差矩阵self.covariances[i] = np.matmul(covariance.transpose(1, 2, 0), self.responsibilities[:, i]) / \responsibility_sum[i]# 计算对数似然值def log_likelihood_value(self, input_data):# 初始化对数似然值为0log_likelihood = 0# 遍历每个数据点for data_point in input_data:# 初始化概率为0probability = 0# 遍历每个聚类for i in range(self.num_clusters):# 累加数据点属于当前聚类的概率probability += self.mixing_coefficients[i] * gaussian.pdf(data_point, mean=self.means[i],cov=self.covariances[i])# 累加对数概率log_likelihood += np.log(probability)# 返回平均对数似然值return log_likelihood / self.num_samples# 拟合模型def fit_model(self, input_data):# 存储输入数据的样本数量self.num_samples = len(input_data)# 初始化责任矩阵为全零矩阵self.responsibilities = np.zeros((self.num_samples, self.num_clusters))# 计算初始对数似然值log_likelihood = self.log_likelihood_value(input_data)# 打印开始迭代信息print('开始迭代')# 开始迭代for i in range(self.max_iterations):# 执行期望步骤self.expectation_step(input_data)# 执行最大化步骤self.maximization_step(input_data)# 计算新的对数似然值new_log_likelihood = self.log_likelihood_value(input_data)# 打印当前迭代步数和对数似然值print(f'第{i}步, log-likelihood = {new_log_likelihood:.4f}')# 如果对数似然值变化小于阈值,停止迭代if new_log_likelihood - log_likelihood < 1e-4:print('log-likelihood不再变化,退出程序')breakelse:# 更新对数似然值log_likelihood = new_log_likelihood# 转换数据,返回每个数据点所属的聚类def transform_data(self, input_data):# 确保责任矩阵已计算且长度与输入数据一致assert hasattr(self, 'responsibilities') and len(self.responsibilities) == len(input_data)# 返回每个数据点所属的聚类索引return np.argmax(self.responsibilities, axis=1)# 拟合并转换数据def fit_and_transform(self, input_data):# 拟合模型self.fit_model(input_data)# 转换数据return self.transform_data(input_data)

和k均值聚类方法相似,在运用基于最大期望值法的高斯混合模型时,我们来观察一下在Books数据集中,3个真实类别里不同簇各自所占的比例情况:

nlp_text_clustering.py

# 从nlp_book_data_collection模块导入BookDataCollection类
from nlp_book_data_collection import BookDataCollection
from nlp_gaussian_mixture_model import GaussianMixtureModel
# 从nlp_tfidf_transformer模块导入TFIDFTransformer类
from nlp_tfidf_transformer import TFIDFTransformer
# 从nlp_kmeans_clusterer模块导入KMeansClusterer类
from nlp_kmeans_clusterer import KMeansClusterer
# 从sklearn库中导入主成分分析(PCA)类
from sklearn.decomposition import PCA# 聚类的数量
num_clusters = 3# 定义一个用于自然语言处理文本聚类的类
class NLPTextClustering:def __init__(self):passdef display_clusters(self, cluster_assignments, num_clusters, book_dataset, labels_list):# 初始化标签聚类字典label_clusters = {label_id: {} for label_id in book_dataset.id_to_label}# 初始化每个标签下每个聚类的计数为0for k, v in label_clusters.items():label_clusters[k] = {i: 0 for i in range(num_clusters)}# 遍历标签和聚类分配for label_id, cluster_id in zip(labels_list, cluster_assignments):# 增加对应标签和聚类的计数label_clusters[label_id][cluster_id] += 1# 按标签ID排序遍历for label_id in sorted(book_dataset.id_to_label.keys()):# 初始化聚类信息字符串cluster_str = book_dataset.id_to_label[label_id] + ':\t{ '# 遍历每个聚类for cluster_id in range(num_clusters):# 获取当前聚类的计数count = label_clusters[label_id][cluster_id]# 计算总数total = sum(label_clusters[label_id].values())# 拼接聚类信息cluster_str += f'{str(cluster_id)}: {count}({count / total:.2f}), '# 结束聚类信息字符串cluster_str += '}'# 打印聚类信息print(cluster_str)def text_clustering(self):# 创建书籍数据集对象book_dataset = BookDataCollection()# 打印标签到ID的映射print(book_dataset.id_to_label)# 对文本进行分词处理book_dataset.tokenize_text(attribute='abstract')# 创建词汇表book_dataset.create_vocabulary(min_frequency=3)# 将词元转换为索引book_dataset.convert_tokens_to_indices()# 获取训练集和测试集数据training_data, testing_data = book_dataset.training_data, book_dataset.testing_data# 获取词汇表大小vocabulary_size = len(book_dataset.token_to_id)# 初始化训练输入列表training_input = []# 遍历训练数据for data_item in training_data:# 将词元索引添加到训练输入列表training_input.append(data_item['token_indices'])# 创建TF-IDF转换器对象tfidf_transformer = TFIDFTransformer(vocabulary_size, normalization='l2', smooth_idf_flag=True,sublinear_tf_flag=True)# 拟合训练数据tfidf_transformer.fit_data(training_input)# 转换训练数据training_features = tfidf_transformer.transform_data(training_input)# 打印训练特征的形状print(training_features.shape)# 创建K-Means聚类器对象kmeans_clusterer = KMeansClusterer(num_clusters, training_features.shape[1])# 拟合训练特征kmeans_clusterer.fit_model(training_features)# 初始化标签列表labels_list = []# 遍历训练数据for data_item in training_data:# 将标签添加到标签列表labels_list.append(data_item['label'])# 打印标签列表的长度print(len(labels_list))# 获取K-Means聚类结果cluster_assignments = kmeans_clusterer.cluster_assignments# 显示K-Means聚类结果self.display_clusters(cluster_assignments, num_clusters, book_dataset, labels_list)# 创建PCA降维器对象pca_reducer = PCA(n_components=50)# 对训练特征进行降维training_pca = pca_reducer.fit_transform(training_features)# 创建高斯混合模型对象gmm_model = GaussianMixtureModel(num_clusters, data_dimension=training_pca.shape[1])# 拟合并转换训练数据cluster_assignments = gmm_model.fit_and_transform(training_pca)# 打印高斯混合模型聚类结果print(cluster_assignments)# 显示高斯混合模型聚类结果self.display_clusters(cluster_assignments, num_clusters, book_dataset, labels_list)# 程序入口,当作为脚本直接运行时执行以下代码
if __name__ == "__main__":# 创建NLPTextClustering类的一个实例nlp_text_clustering = NLPTextClustering()# 调用实例的text_clustering方法进行文本聚类操作nlp_text_clustering.text_clustering()

高斯混合聚类运行结果

训练集大小 = 8626 , 测试集大小 = 2156
{0: '计算机类', 1: '艺术传媒类', 2: '经管类'}
100%|██████████| 8626/8626 [02:36<00:00, 54.95it/s]
100%|██████████| 2156/2156 [00:36<00:00, 59.32it/s]
唯一词元数量 = 34251, 总词元数量 = 806791, 最大词频 = 19194, 最小词频 = 1
最小词频 = 3, 最小词长 = 2, 最大词表大小 = None, 剩余词元数量 = 9504, 词表内词元占比 = 0.8910448926673699
(8626, 9504)
-----------初始化-----------
-----------初始化完成-----------
第1步,中心点平均移动距离:0.07821463876668384
第2步,中心点平均移动距离:0.05703827383757104
第3步,中心点平均移动距离:0.0227878128221168
第4步,中心点平均移动距离:0.012985270767233279
第5步,中心点平均移动距离:0.010560323354748833
第6步,中心点平均移动距离:0.011526155533891311
第7步,中心点平均移动距离:0.014447526451567915
第8步,中心点平均移动距离:0.01480361614434264
第9步,中心点平均移动距离:0.007805741764265261
第10步,中心点平均移动距离:0.004696899248898042
第11步,中心点平均移动距离:0.003858954772666219
第12步,中心点平均移动距离:0.0037634051652670757
第13步,中心点平均移动距离:0.0036342433215190346
第14步,中心点平均移动距离:0.004037746948698562
第15步,中心点平均移动距离:0.0037074902463420808
第16步,中心点平均移动距离:0.0025126860295755764
第17步,中心点平均移动距离:0.0017742952721109479
第18步,中心点平均移动距离:0.001311558516669006
第19步,中心点平均移动距离:0.0008183675564787064
第20步,中心点平均移动距离:0.0011545852276947674
第21步,中心点平均移动距离:0.0006864544106957334
第22步,中心点平均移动距离:0.0009260959472041178
第23步,中心点平均移动距离:0.0004974572613901904
第24步,中心点平均移动距离:0.00047763554726450624
第25步,中心点平均移动距离:0.000561811847711657
第26步,中心点平均移动距离:0.00030713124482862106
第27步,中心点平均移动距离:0.0
中心点不再移动,退出程序
8626
计算机类:	{ 0: 1233(0.32), 1: 2572(0.67), 2: 37(0.01), }
艺术传媒类:	{ 0: 74(0.03), 1: 282(0.12), 2: 1943(0.85), }
经管类:	{ 0: 26(0.01), 1: 2452(0.99), 2: 7(0.00), }
开始迭代
第0步, log-likelihood = 77.2117
第1步, log-likelihood = 87.3795
第2步, log-likelihood = 90.4587
第3步, log-likelihood = 91.7301
第4步, log-likelihood = 92.7042
第5步, log-likelihood = 93.5868
第6步, log-likelihood = 94.6852
第7步, log-likelihood = 95.8890
第8步, log-likelihood = 96.4726
第9步, log-likelihood = 96.8001
第10步, log-likelihood = 96.9560
第11步, log-likelihood = 97.0857
第12步, log-likelihood = 97.5848
第13步, log-likelihood = 97.5959
第14步, log-likelihood = 97.6033
第15步, log-likelihood = 97.6140
第16步, log-likelihood = 97.6341
第17步, log-likelihood = 97.6695
第18步, log-likelihood = 97.6801
第19步, log-likelihood = 97.6888
第20步, log-likelihood = 97.7062
第21步, log-likelihood = 97.7420
第22步, log-likelihood = 97.7711
第23步, log-likelihood = 97.8122
第24步, log-likelihood = 97.8207
第25步, log-likelihood = 97.8232
第26步, log-likelihood = 97.8244
第27步, log-likelihood = 97.8255
第28步, log-likelihood = 97.8284
第29步, log-likelihood = 97.8330
第30步, log-likelihood = 97.8486
第31步, log-likelihood = 97.9543
第32步, log-likelihood = 98.0578
第33步, log-likelihood = 98.0620
第34步, log-likelihood = 98.0625
第35步, log-likelihood = 98.0626
第36步, log-likelihood = 98.0628
第37步, log-likelihood = 98.0628
log-likelihood不再变化,退出程序
[0 2 0 ... 2 0 2]
计算机类:	{ 0: 2742(0.71), 1: 299(0.08), 2: 801(0.21), }
艺术传媒类:	{ 0: 9(0.00), 1: 421(0.18), 2: 1869(0.81), }
经管类:	{ 0: 829(0.33), 1: 1625(0.65), 2: 31(0.01), }进程已结束,退出代码为 0

无监督朴素贝叶斯模型

无监督朴素贝叶斯模型也是文本聚类的有力工具。它基于贝叶斯定理和特征条件独立假设,认为文本中的各个词之间是相互独立的,就好像每个人都是独立行动的个体。在文本聚类时,它通过统计文本中词的出现频率,结合贝叶斯定理,计算文本属于不同主题(类别)的概率,然后把概率相近的文本归为一类。

这种算法的优点是简单高效,对数据量的要求相对较低,可扩展性也不错。然而,它的特征条件独立假设在实际情况中往往不太符合,因为文本中的词之间其实是有语义关联的;而且它对多义词的处理能力有限,可能会把不同含义的同一个词都当作相同的来处理,影响聚类的准确性;此外,模型的性能很大程度上依赖于文本的表示方式,如果文本表示不准确,聚类效果也会受到影响。

接下来,为大家展示基于朴素贝叶斯模型的聚类算法具体是如何实现的:

朴素贝叶斯模型聚类完整代码

nlp_unsupervised_naive_bayes_classifier.py

# 导入NumPy库,用于数值计算
import numpy as np
# 从scipy库中导入对数求和指数函数
from scipy.special import logsumexp# 定义无监督朴素贝叶斯分类器类
class UnsupervisedNaiveBayesClassifier:# 初始化方法,设置聚类数量、数据维度和最大迭代次数def __init__(self, num_clusters, data_dimension, max_iterations=100):# 存储聚类数量self.num_clusters = num_clusters# 存储数据维度self.data_dimension = data_dimension# 存储最大迭代次数self.max_iterations = max_iterations# 初始化先验概率,每个聚类初始概率相同self.prior_probabilities = np.ones(num_clusters) / num_clusters# 随机初始化条件概率self.conditional_probabilities = np.random.random((num_clusters, data_dimension))# 对条件概率进行归一化处理self.conditional_probabilities /= self.conditional_probabilities.sum(axis=1, keepdims=True)# 期望步骤,计算每个数据点属于每个聚类的概率def expectation_step(self, input_data):# 遍历每个数据点for i, data_point in enumerate(input_data):# 计算对数概率self.responsibilities[i, :] = np.log(self.prior_probabilities) + (np.log(self.conditional_probabilities) * data_point).sum(axis=1)# 减去对数求和指数,避免数值溢出self.responsibilities[i, :] -= logsumexp(self.responsibilities[i, :])# 计算概率self.responsibilities[i, :] = np.exp(self.responsibilities[i, :])# 最大化步骤,更新模型参数def maximization_step(self, input_data):# 计算每个聚类的责任权重总和self.prior_probabilities = self.responsibilities.sum(axis=0) / self.num_samples# 对先验概率进行归一化处理self.prior_probabilities /= self.prior_probabilities.sum()# 遍历每个聚类for i in range(self.num_clusters):# 更新条件概率self.conditional_probabilities[i] = (self.responsibilities[:, i:i + 1] * input_data).sum(axis=0) / \(self.responsibilities[:, i] * input_data.sum(axis=1)).sum()# 避免条件概率为0self.conditional_probabilities += 1e-10# 对条件概率进行归一化处理self.conditional_probabilities /= self.conditional_probabilities.sum(axis=1, keepdims=True)# 计算对数似然值def log_likelihood_value(self, input_data):# 初始化对数似然值为0log_likelihood = 0# 遍历每个数据点for data_point in input_data:# 存储每个聚类的对数概率log_probabilities = []# 遍历每个聚类for i in range(self.num_clusters):# 计算对数概率log_probabilities.append(np.log(self.prior_probabilities[i]) + (np.log(self.conditional_probabilities[i]) * data_point).sum())# 累加对数求和指数log_likelihood += logsumexp(log_probabilities)# 返回平均对数似然值return log_likelihood / len(input_data)# 拟合模型def fit_model(self, input_data):# 存储输入数据的样本数量self.num_samples = len(input_data)# 初始化责任矩阵为全零矩阵self.responsibilities = np.zeros((self.num_samples, self.num_clusters))# 计算初始对数似然值log_likelihood = self.log_likelihood_value(input_data)# 打印初始对数似然值print(f'初始化log-likelihood = {log_likelihood:.4f}')# 打印开始迭代信息print('开始迭代')# 开始迭代for i in range(self.max_iterations):# 执行期望步骤self.expectation_step(input_data)# 执行最大化步骤self.maximization_step(input_data)# 计算新的对数似然值new_log_likelihood = self.log_likelihood_value(input_data)# 打印当前迭代步数和对数似然值print(f'第{i}步, log-likelihood = {new_log_likelihood:.4f}')# 如果对数似然值变化小于阈值,停止迭代if new_log_likelihood - log_likelihood < 1e-4:print('log-likelihood不再变化,退出程序')breakelse:# 更新对数似然值log_likelihood = new_log_likelihood# 转换数据,返回每个数据点所属的聚类def transform_data(self, input_data):# 确保责任矩阵已计算且长度与输入数据一致assert hasattr(self, 'responsibilities') and len(self.responsibilities) == len(input_data)# 返回每个数据点所属的聚类索引return np.argmax(self.responsibilities, axis=1)# 拟合并转换数据def fit_and_transform(self, input_data):# 拟合模型self.fit_model(input_data)# 转换数据return self.transform_data(input_data)

nlp_text_clustering.py

# 从nlp_book_data_collection模块导入BookDataCollection类
from nlp_book_data_collection import BookDataCollection
from nlp_gaussian_mixture_model import GaussianMixtureModel
# 从nlp_tfidf_transformer模块导入TFIDFTransformer类
from nlp_tfidf_transformer import TFIDFTransformer
# 从nlp_kmeans_clusterer模块导入KMeansClusterer类
from nlp_kmeans_clusterer import KMeansClusterer
# 从sklearn库中导入主成分分析(PCA)类
from sklearn.decomposition import PCA
# 从nlp_unsupervised_naive_bayes_classifier模块导入UnsupervisedNaiveBayesClassifier类
from nlp_unsupervised_naive_bayes_classifier import UnsupervisedNaiveBayesClassifier
# 导入NumPy库,用于数值计算
import numpy as np# 聚类的数量
num_clusters = 3# 定义一个用于自然语言处理文本聚类的类
class NLPTextClustering:def __init__(self):passdef display_clusters(self, cluster_assignments, num_clusters, book_dataset, labels_list):# 初始化标签聚类字典label_clusters = {label_id: {} for label_id in book_dataset.id_to_label}# 初始化每个标签下每个聚类的计数为0for k, v in label_clusters.items():label_clusters[k] = {i: 0 for i in range(num_clusters)}# 遍历标签和聚类分配for label_id, cluster_id in zip(labels_list, cluster_assignments):# 增加对应标签和聚类的计数label_clusters[label_id][cluster_id] += 1# 按标签ID排序遍历for label_id in sorted(book_dataset.id_to_label.keys()):# 初始化聚类信息字符串cluster_str = book_dataset.id_to_label[label_id] + ':\t{ '# 遍历每个聚类for cluster_id in range(num_clusters):# 获取当前聚类的计数count = label_clusters[label_id][cluster_id]# 计算总数total = sum(label_clusters[label_id].values())# 拼接聚类信息cluster_str += f'{str(cluster_id)}: {count}({count / total:.2f}), '# 结束聚类信息字符串cluster_str += '}'# 打印聚类信息print(cluster_str)def text_clustering(self):# 创建书籍数据集对象book_dataset = BookDataCollection()# 打印标签到ID的映射print(book_dataset.id_to_label)# 对文本进行分词处理book_dataset.tokenize_text(attribute='abstract')# 创建词汇表book_dataset.create_vocabulary(min_frequency=3)# 将词元转换为索引book_dataset.convert_tokens_to_indices()# 获取训练集和测试集数据training_data, testing_data = book_dataset.training_data, book_dataset.testing_data# 获取词汇表大小vocabulary_size = len(book_dataset.token_to_id)# 初始化训练输入列表training_input = []# 遍历训练数据for data_item in training_data:# 将词元索引添加到训练输入列表training_input.append(data_item['token_indices'])# 创建TF-IDF转换器对象tfidf_transformer = TFIDFTransformer(vocabulary_size, normalization='l2', smooth_idf_flag=True,sublinear_tf_flag=True)# 拟合训练数据tfidf_transformer.fit_data(training_input)# 转换训练数据training_features = tfidf_transformer.transform_data(training_input)# 打印训练特征的形状print(training_features.shape)# 创建K-Means聚类器对象kmeans_clusterer = KMeansClusterer(num_clusters, training_features.shape[1])# 拟合训练特征kmeans_clusterer.fit_model(training_features)# 初始化标签列表labels_list = []# 遍历训练数据for data_item in training_data:# 将标签添加到标签列表labels_list.append(data_item['label'])# 打印标签列表的长度print(len(labels_list))# 获取K-Means聚类结果cluster_assignments = kmeans_clusterer.cluster_assignments# 显示K-Means聚类结果self.display_clusters(cluster_assignments, num_clusters, book_dataset, labels_list)# 创建PCA降维器对象pca_reducer = PCA(n_components=50)# 对训练特征进行降维training_pca = pca_reducer.fit_transform(training_features)# 创建高斯混合模型对象gmm_model = GaussianMixtureModel(num_clusters, data_dimension=training_pca.shape[1])# 拟合并转换训练数据cluster_assignments = gmm_model.fit_and_transform(training_pca)# 打印高斯混合模型聚类结果print(cluster_assignments)# 显示高斯混合模型聚类结果self.display_clusters(cluster_assignments, num_clusters, book_dataset, labels_list)# 初始化训练计数矩阵training_count_matrix = np.zeros((len(training_input), vocabulary_size))# 遍历训练输入for i, data_item in enumerate(training_input):# 遍历词元索引for token_index in data_item:# 增加对应位置的计数training_count_matrix[i, token_index] += 1# 创建无监督朴素贝叶斯分类器对象naive_bayes_classifier = UnsupervisedNaiveBayesClassifier(num_clusters, data_dimension=vocabulary_size,max_iterations=100)# 拟合并转换训练数据cluster_assignments = naive_bayes_classifier.fit_and_transform(training_count_matrix)# 打印无监督朴素贝叶斯分类器聚类结果print(cluster_assignments)# 显示无监督朴素贝叶斯分类器聚类结果self.display_clusters(cluster_assignments, num_clusters, book_dataset, labels_list)# 程序入口,当作为脚本直接运行时执行以下代码
if __name__ == "__main__":# 创建NLPTextClustering类的一个实例nlp_text_clustering = NLPTextClustering()# 调用实例的text_clustering方法进行文本聚类操作nlp_text_clustering.text_clustering()

朴素贝叶斯模型聚类运行结果

训练集大小 = 8626 , 测试集大小 = 2156
{0: '计算机类', 1: '艺术传媒类', 2: '经管类'}
100%|██████████| 8626/8626 [02:36<00:00, 54.95it/s]
100%|██████████| 2156/2156 [00:36<00:00, 59.32it/s]
唯一词元数量 = 34251, 总词元数量 = 806791, 最大词频 = 19194, 最小词频 = 1
最小词频 = 3, 最小词长 = 2, 最大词表大小 = None, 剩余词元数量 = 9504, 词表内词元占比 = 0.8910448926673699
(8626, 9504)
-----------初始化-----------
-----------初始化完成-----------
第1步,中心点平均移动距离:0.07821463876668384
第2步,中心点平均移动距离:0.05703827383757104
第3步,中心点平均移动距离:0.0227878128221168
第4步,中心点平均移动距离:0.012985270767233279
第5步,中心点平均移动距离:0.010560323354748833
第6步,中心点平均移动距离:0.011526155533891311
第7步,中心点平均移动距离:0.014447526451567915
第8步,中心点平均移动距离:0.01480361614434264
第9步,中心点平均移动距离:0.007805741764265261
第10步,中心点平均移动距离:0.004696899248898042
第11步,中心点平均移动距离:0.003858954772666219
第12步,中心点平均移动距离:0.0037634051652670757
第13步,中心点平均移动距离:0.0036342433215190346
第14步,中心点平均移动距离:0.004037746948698562
第15步,中心点平均移动距离:0.0037074902463420808
第16步,中心点平均移动距离:0.0025126860295755764
第17步,中心点平均移动距离:0.0017742952721109479
第18步,中心点平均移动距离:0.001311558516669006
第19步,中心点平均移动距离:0.0008183675564787064
第20步,中心点平均移动距离:0.0011545852276947674
第21步,中心点平均移动距离:0.0006864544106957334
第22步,中心点平均移动距离:0.0009260959472041178
第23步,中心点平均移动距离:0.0004974572613901904
第24步,中心点平均移动距离:0.00047763554726450624
第25步,中心点平均移动距离:0.000561811847711657
第26步,中心点平均移动距离:0.00030713124482862106
第27步,中心点平均移动距离:0.0
中心点不再移动,退出程序
8626
计算机类:	{ 0: 1233(0.32), 1: 2572(0.67), 2: 37(0.01), }
艺术传媒类:	{ 0: 74(0.03), 1: 282(0.12), 2: 1943(0.85), }
经管类:	{ 0: 26(0.01), 1: 2452(0.99), 2: 7(0.00), }
开始迭代
第0步, log-likelihood = 77.2117
第1步, log-likelihood = 87.3795
第2步, log-likelihood = 90.4587
第3步, log-likelihood = 91.7301
第4步, log-likelihood = 92.7042
第5步, log-likelihood = 93.5868
第6步, log-likelihood = 94.6852
第7步, log-likelihood = 95.8890
第8步, log-likelihood = 96.4726
第9步, log-likelihood = 96.8001
第10步, log-likelihood = 96.9560
第11步, log-likelihood = 97.0857
第12步, log-likelihood = 97.5848
第13步, log-likelihood = 97.5959
第14步, log-likelihood = 97.6033
第15步, log-likelihood = 97.6140
第16步, log-likelihood = 97.6341
第17步, log-likelihood = 97.6695
第18步, log-likelihood = 97.6801
第19步, log-likelihood = 97.6888
第20步, log-likelihood = 97.7062
第21步, log-likelihood = 97.7420
第22步, log-likelihood = 97.7711
第23步, log-likelihood = 97.8122
第24步, log-likelihood = 97.8207
第25步, log-likelihood = 97.8232
第26步, log-likelihood = 97.8244
第27步, log-likelihood = 97.8255
第28步, log-likelihood = 97.8284
第29步, log-likelihood = 97.8330
第30步, log-likelihood = 97.8486
第31步, log-likelihood = 97.9543
第32步, log-likelihood = 98.0578
第33步, log-likelihood = 98.0620
第34步, log-likelihood = 98.0625
第35步, log-likelihood = 98.0626
第36步, log-likelihood = 98.0628
第37步, log-likelihood = 98.0628
log-likelihood不再变化,退出程序
[0 2 0 ... 2 0 2]
计算机类:	{ 0: 2742(0.71), 1: 299(0.08), 2: 801(0.21), }
艺术传媒类:	{ 0: 9(0.00), 1: 421(0.18), 2: 1869(0.81), }
经管类:	{ 0: 829(0.33), 1: 1625(0.65), 2: 31(0.01), }
初始化log-likelihood = -779.6002
开始迭代
第0步, log-likelihood = -589.5137
第1步, log-likelihood = -583.1897
第2步, log-likelihood = -579.2382
第3步, log-likelihood = -577.0352
第4步, log-likelihood = -575.8822
第5步, log-likelihood = -575.3356
第6步, log-likelihood = -574.8611
第7步, log-likelihood = -574.5028
第8步, log-likelihood = -574.2625
第9步, log-likelihood = -574.1030
第10步, log-likelihood = -573.9690
第11步, log-likelihood = -573.7704
第12步, log-likelihood = -573.6187
第13步, log-likelihood = -573.4686
第14步, log-likelihood = -573.3280
第15步, log-likelihood = -573.2186
第16步, log-likelihood = -573.1160
第17步, log-likelihood = -572.9857
第18步, log-likelihood = -572.8356
第19步, log-likelihood = -572.7076
第20步, log-likelihood = -572.4683
第21步, log-likelihood = -572.3301
第22步, log-likelihood = -572.2375
第23步, log-likelihood = -572.0611
第24步, log-likelihood = -571.8587
第25步, log-likelihood = -571.7117
第26步, log-likelihood = -571.6412
第27步, log-likelihood = -571.6158
第28步, log-likelihood = -571.5863
第29步, log-likelihood = -571.5397
第30步, log-likelihood = -571.5281
第31步, log-likelihood = -571.5163
第32步, log-likelihood = -571.4902
第33步, log-likelihood = -571.4693
第34步, log-likelihood = -571.4604
第35步, log-likelihood = -571.4457
第36步, log-likelihood = -571.4339
第37步, log-likelihood = -571.4301
第38步, log-likelihood = -571.4288
第39步, log-likelihood = -571.4272
第40步, log-likelihood = -571.4257
第41步, log-likelihood = -571.4254
第42步, log-likelihood = -571.4176
第43步, log-likelihood = -571.4060
第44步, log-likelihood = -571.4028
第45步, log-likelihood = -571.4027
log-likelihood不再变化,退出程序
[0 1 0 ... 1 0 1]
计算机类:	{ 0: 2266(0.59), 1: 1479(0.38), 2: 97(0.03), }
艺术传媒类:	{ 0: 64(0.03), 1: 703(0.31), 2: 1532(0.67), }
经管类:	{ 0: 2237(0.90), 1: 117(0.05), 2: 131(0.05), }进程已结束,退出代码为 0

结束

好了,以上就是本次分享的全部内容了。不知道大家是否对自然语言处理中的文本聚类有了更深入的了解呢?

本次分享主要围绕文本聚类展开,介绍了几种常见的文本聚类方法,包括 k 均值聚类算法、基于高斯混合模型的最大期望值算法和无监督朴素贝叶斯模型。

  • k均值聚类算法:简单且经典,计算效率高,但需要预先指定聚类数量 k,对初始聚类中心的选择比较敏感。
  • 基于高斯混合模型的最大期望值算法:能够灵活地拟合复杂的数据分布,对于多模态的数据聚类效果较好,但计算复杂度高,对超参数的选择敏感,容易陷入局部最优解。
  • 无监督朴素贝叶斯模型:简单高效,对数据量的要求相对较低,可扩展性不错,但特征条件独立假设在实际情况中往往不太符合,对多义词的处理能力有限,模型性能依赖于文本的表示方式。

文本聚类在自然语言处理领域有着广泛的应用前景,如信息检索、文本分类、情感分析等。随着技术的不断发展,未来可能会出现更高效、更准确的文本聚类算法。同时,结合深度学习等技术,也有望进一步提升文本聚类的效果。

那么本次分享就到这里了。最后,博主还是那句话:请大家多去大胆的尝试和使用,成功总是在不断的失败中试验出来的,敢于尝试就已经成功了一半。如果大家对博主分享的内容感兴趣或有帮助,请点赞和关注。大家的点赞和关注是博主持续分享的动力🤭,博主也希望让更多的人学习到新的知识。 

相关文章:

自然语言处理:文本聚类

介绍 大家好&#xff0c;博主又来和大家分享自然语言处理领域的知识了。今天给大家分享的内容是自然语言处理中的文本聚类。 文本聚类在自然语言处理领域占据着重要地位&#xff0c;它能将大量无序的文本按照内容的相似性自动划分成不同的类别&#xff0c;极大地提高了文本处…...

RabbitMQ 集群降配

这里写自定义目录标题 摘要检查状态1. 检查 RabbitMQ 服务状态2. 检查 RabbitMQ 端口监听3. 检查 RabbitMQ 管理插件是否启用4. 检查开机自启状态5. 确认集群高可用性6. 检查使用该集群的服务是否做了断开重连 实操1. 负载均衡配置2. 逐个节点降配&#xff08;滚动操作&#xf…...

uniapp工程中解析markdown文件

在uniapp中如何导入markdown文件&#xff0c;同时在页面中解析成html&#xff0c;请参考以下配置&#xff1a; 1. 安装以下3个依赖包 npm install marked highlight.js vite-plugin-markdown 2. 创建vite.config.js配置文件 // vite.config.js import { defineConfig } fro…...

数据结构:二叉树(一)·(重点)

前言 什么树&#xff1f;what&#xff1f; 树的概念与结构 概念&#xff1a; 树是⼀种⾮线性的数据结构&#xff0c;它是由 n &#xff08; n>0 &#xff09; 个有限结点组成⼀个具有层次关系的集合。 结构&#xff1a; 有⼀个特殊的结点&#xff0c;称为根结点&#…...

DevEco Studio的使用

目录 1.创建ArkTS工程 2.ArkTS工程目录结构&#xff08;Stage模型&#xff09; 构建第一个页面 构建第二个页面 实现页面间的跳转 1.创建ArkTS工程 若首次打开DevEco Studio&#xff0c;请点击Create Project创建工程。如果已经打开了一个工程&#xff0c;请在菜单栏选择…...

十七、实战开发 uni-app x 项目(仿京东)- 后端指南

前面我们已经用uniappx进行了前端实战学习 一、实战 开发uni-app x项目(仿京东)-规划-CSDN博客 二、实战 开发uni-app x项目(仿京东)-项目搭建-CSDN博客 三、实战开发 uni-app x 项目(仿京东)- 技术选型-CSDN博客 四、实战开发 uni-app x 项目(仿京东)- 页面设计-C…...

数据开发岗笔试题>>sql(hive) ,excel [2025]

sql SELECT user_id, AVG(loan_amount) AS avg_loan_amount FROM loan GROUP BY user_id HAVING AVG(loan_amount) > 20000; 授信表&#xff1a;credit 字段包含user_id(用户id)&#xff0c;credit_id(授信id)&#xff0c;credit_time(授信时间yyyy-MM-dd HH:mm:ss)&#x…...

内存模型以及分区,需要详细到每个区放什么。

1. 内存模型以及分区&#xff0c;需要详细到每个区放什么。 JVM 分为堆区和栈区&#xff0c;还有方法区&#xff0c;初始化的对象放在堆里面&#xff0c;引用放在栈里面&#xff0c; class 类信息常量池&#xff08;static 常量和 static 变量&#xff09;等放在方法区new: …...

python strip/rstrip/lstrip详细讲解(涵盖许多例子、作用以及复杂行为处理)

python strip/rstrip/lstrip详细讲解: 在Python中,strip、lstrip、rstrip 是用于字符串处理的常用方法,主要功能是去除字符串首尾的指定字符。它们的区别如下: 1. strip([chars]) 作用 :删除字符串开头和结尾 处所有属于 chars 的字符,直到遇到不属于 chars 的字符为止…...

Spring Boot集成PageHelper:轻松实现数据库分页功能

Spring Boot集成PageHelper&#xff1a;轻松实现数据库分页功能 1. 为什么需要分页&#xff1f; 分页是处理大数据量查询的核心技术&#xff0c;其重要性体现在&#xff1a; 性能优化&#xff1a;避免单次查询返回过多数据导致内存溢出或响应延迟。用户体验&#xff1a;前端展…...

OpenGL ES 入门指南:从基础到实战

引言&#xff1a;为什么需要 OpenGL ES&#xff1f; 在当今的嵌入式设备&#xff08;如智能手机、汽车仪表盘、智能家居中控屏&#xff09;中&#xff0c;流畅的图形渲染能力是用户体验的核心。OpenGL ES&#xff08;OpenGL for Embedded Systems&#xff09; 作为行业标准&am…...

docker安装milvus向量数据库Attu可视化界面

Docker 部署 Milvus 及 Attu 可视化工具完整指南 一、环境准备 安装 Docker 及 Docker Compose Docker 版本需 ≥20.10.12Docker Compose 版本需 ≥2.20.0&#xff08;推荐 V2&#xff09; 验证 Docker 环境 docker --version && docker-compose --version若出现&…...

Elasticsearch 索引

一、简介 在 Elasticsearch 中&#xff0c;索引&#xff08;Index&#xff09;是存储相关文档的地方&#xff0c;类似于关系数据库中的数据库。索引是 Elasticsearch 中最重要的概念之一&#xff0c;用于组织和存储数据。 二、索引的基本概念 索引&#xff08;Index&#xf…...

ArcGIS10. 8简介与安装,附下载地址

目录 ArcGIS10.8 1. 概述 2. 组成与功能 3. 10.8 特性 下载链接 安装步骤 1. 安装准备 2. 具体步骤 3.补丁 其他版本安装 ArcGIS10.8 1. 概述 ArcGIS 10.8 是由美国 Esri 公司精心研发的一款功能强大的地理信息系统&#xff08;GIS&#xff09;平台。其核心功能在于…...

Idea中使用Git插件_合并当前分支到master分支_冲突解决_很简单---Git工作笔记005

由于之前用svn习惯了,用的git少,其实在idea中使用git,解决冲突,合并分支,非常的简单,一起来看一下吧. 一定要注意操作之前,一定要确保自己的分支代码,都已经commit提交了,并且push到远程了. 不要丢东西. 可以看到首先,在idea的左下角有个 git,点开以后 可以看到有显示的分支…...

Docker简易使用说明

Docker使用说明 文章目录 Docker使用说明一. 安装二. 测试三. 镜像加速 一. 安装 安装其实没什么可说的&#xff0c;但凡有显示界面的OS&#xff0c;如windows/Mac&#xff0c;直接上官方网站下载安装即可 二. 测试 若安装好docker后&#xff0c;应当先检测docker的网络通信…...

【Linux】应用层自定义协议 + 序列化和反序列化

应用层自定义协议 序列化和反序列化 一.应用层1.再谈 "协议"2.序列化 和 反序列化 二. Jsoncpp1.序列化2.反序列化 三. Tcp全双工 面向字节流四.自定义协议 保证报文的完整性1.Makefile2.Mutex.hpp3.Cond.hpp4.Log.hpp5.Thread.hpp6.ThreadPool.hpp7.Common.hpp8.…...

Matlab 雷达导引头伺服系统的建模与仿真研究

1、内容简介 Matlab 177-雷达导引头伺服系统的建模与仿真研究 可以交流、咨询、答疑 2、内容说明 略[摘 要]基于 Malah/Simuink 雷达导引|头同服系统的建模与仿真&#xff0c;首先对雷达导引头同服系统按照预定回路和跟踪回路的步骤分别进行建模以及相关控制参数计算,接着构建…...

华为ipd流程华为流程体系管理华为数字化转型流程数字化管理解决方案介绍81页精品PPT

华为流程体系最佳实践主要包括构建完善的流程框架&#xff0c;明确各层级流程要素与职责&#xff0c;梳理涵盖研发、采购、营销、服务、资产管理等多领域的流程&#xff0c;通过梳理业务场景和核心能力搭建差异化流程框架&#xff0c;采用自上而下与自下而上相结合的建模方法&a…...

深入理解 HTML 中的统一资源定位器(URL)

一、引言 在互联网的世界中&#xff0c;我们每天都在与各种网页打交道。而网页能够被准确地访问和获取&#xff0c;离不开一个关键的元素 —— 统一资源定位器&#xff08;Uniform Resource Locators&#xff0c;简称 URL&#xff09;。它就像是网络世界中的地址&#xff0c;指…...

网络流基本概念及实现算法

基本概念 流网络 对于一个有向图, 抽象成水管里的水的模型, 每根管子有容量限制, 计为 G ( V , E ) G (V, E) G(V,E), 首先不考虑反向边 对于任意无向图, 都可以将反向边转化为上述形式 如果一条边不存在, 定义为容量为 0 0 0, 形式上来说就是 c ( u , v ) 0 c(u, v) 0 c(…...

Qt程序增加Dump文件保存

qt程序出现程序闪退&#xff0c;对这些未能捕获的异常&#xff0c;存储未Dump文件方便我们定位哪块代码出的问题。利用Window API 的相关接口&#xff0c;具体如下 #include <QCoreApplication> #include <windows.h> #include <DbgHelp.h> #include <QD…...

【Go每日一练】猜数字游戏

&#x1f47b;创作者&#xff1a;丶重明 &#x1f47b;创作时间&#xff1a;2025年3月16日 &#x1f47b;擅长领域&#xff1a;运维 目录 1.&#x1f636;‍&#x1f32b;️题目&#xff1a;猜数字游戏2.&#x1f636;‍&#x1f32b;️代码开发3.&#x1f636;‍&#x1f32b;…...

SpringBoot对接DeepSeek

文章目录 Spring Boot 集成 DeepSeek API 详细步骤1. 创建API Key1.访问 [DeepSeek控制台](https://platform.deepseek.com/usage) 并登录。2.点击 Create API Key 生成新密钥。3.复制并保存密钥&#xff08;需在Spring Boot配置文件中使用&#xff09;。 2. 创建Spring Boot工…...

doris:审计日志

Doris 提供了对于数据库操作的审计能力&#xff0c;可以记录用户对数据库的登陆、查询、修改操作。在 Doris 中&#xff0c;可以直接通过内置系统表查询审计日志&#xff0c;也可以直接查看 Doris 的审计日志文件。 开启审计日志​ 通过全局变量 enable_audit_plugin 可以随时…...

`fetch` 和 `axios`的前端使用区别

&#x1f389;&#x1f389;&#x1f389;&#x1f389;&#x1f389;&#x1f389;&#x1f389;&#x1f389;&#x1f389;&#x1f389;&#x1f389;&#x1f389;&#x1f389;&#x1f389;&#x1f389;&#x1f389;&#x1f389;&#x1f389; 欢迎访问的个人博客&am…...

大语言模型的多垂类快速评估与 A/B 测试

简介 行业领先的模型构建企业携手澳鹏&#xff08;Appen&#xff09;开展了一项极具挑战性的项目。针对 3 至 6 个大型语言模型&#xff08;LLM&#xff09;&#xff0c;在广泛的通用领域及复杂专业领域&#xff08;如医疗保健、法律、金融、编程、数学和汽车行业等&#xff0…...

【RabbitMQ】RabbitMQ如何保证消息不丢失?

为了保证消息不丢失&#xff0c;需要在生产者、RabbitMQ本身和消费者三个环节采取相应措施。 1.生产者端&#xff1a;确保消息发送成功 1.1开启消息确认机制(Publisher Confirms) 原理&#xff1a; 生产者发送消息后&#xff0c;RabbitMQ会返回一个确认(ACK),表示消息已成功…...

RAGFlow + LlamaIndex 本地知识库RAG增强架构与实现直播智能复盘

一、需求分析与架构设计 基于 RAGFlow LlamaIndex 本地知识库RAG 扩展直播话术合规与复盘系统&#xff0c;需构建 实时流处理、多模态合规引擎、智能复盘分析 三层能力。以下是完整架构图与技术方案&#xff1a; 二、核心模块技术方案 1. 直播流实时处理&#xff08;输入层→…...

《UNIX网络编程卷1:套接字联网API》第2章 传输层:TCP、UDP和SCTP

《UNIX网络编程卷1&#xff1a;套接字联网API》第2章 传输层&#xff1a;TCP、UDP和SCTP 2.1 传输层的核心作用与协议选型 传输层是网络协议栈中承上启下的核心层&#xff0c;直接决定应用的通信质量。其主要职责包括&#xff1a; 端到端通信&#xff1a;屏蔽底层网络细节&am…...