茄子的个人空间

基于编辑距离的文本层次聚类

字数统计: 825阅读时长: 3 min
2025/03/06
loading

在自然语言处理(NLP)和数据清洗过程中,处理相似文本的聚类问题是一个常见的挑战。例如,在搜索日志、医学术语、客户查询等文本数据中,我们经常会遇到拼写相似或近似表达的词汇。为了更好地对这些数据进行分类和管理,我们可以使用 编辑距离(Levenshtein Distance) 结合 层次聚类(Hierarchical Clustering) 进行文本聚类。

本文介绍了一种基于 Python 的 编辑距离层次聚类 方法,并提供了一个完整的实现代码。该方法的核心思想是:

  • 计算编辑距离矩阵:通过 Levenshtein 距离衡量文本之间的相似性。

  • 层次聚类:使用层次聚类,将相似的文本归类到相同的簇中。

  • 排序和输出:按照聚类结果对数据进行排序,并将结果保存为 CSV 文件,便于后续分析。


下面是实现代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87

from scipy.cluster.hierarchy import linkage, fcluster
from scipy.spatial.distance import pdist, squareform
import Levenshtein # 用于计算编辑距离
import numpy as np
import pandas as pd


class EditDistanceClustering:
def __init__(self, input_csv: str, output_csv: str, column_name: str, threshold: int = 5):
"""
初始化类
:param input_csv: 输入CSV文件路径
:param output_csv: 输出CSV文件路径
:param column_name: 需要聚类的列名
:param threshold: 距离阈值,决定簇的划分
"""
self.input_csv: str = input_csv
self.output_csv: str = output_csv
self.column_name: str = column_name
self.threshold: int = threshold
self.df: pd.DataFrame | None = None # 初始化DataFrame变量

def read_csv(self) -> None:
"""读取CSV文件到DataFrame中"""
self.df = pd.read_csv(self.input_csv)

def lev_distance(self, s1: str, s2: str) -> int:
"""
计算两个字符串之间的Levenshtein编辑距离
:param s1: 第一个字符串
:param s2: 第二个字符串
:return: 编辑距离
"""
return Levenshtein.distance(s1, s2)

def compute_edit_distance_matrix(self) -> np.ndarray:
"""
计算字符串列表的编辑距离矩阵
:return: 计算得到的编辑距离矩阵(二维数组)
"""
# 获取指定列的所有字符串并转换为列表
strings: list[str] = self.df[self.column_name].astype(str).tolist()
# 将字符串列表转换为NumPy数组,并调整为二维格式
strings_array: np.ndarray = np.array(strings).reshape(-1, 1)
# 计算编辑距离矩阵
return squareform(pdist(strings_array, lambda u, v: self.lev_distance(u[0], v[0])))

def cluster_and_sort(self) -> None:
"""
执行层次聚类,并根据聚类结果排序
"""
# 计算编辑距离矩阵
distance_matrix: np.ndarray = self.compute_edit_distance_matrix()
# 使用层次聚类方法(Ward方法)进行聚类
linkage_matrix: np.ndarray = linkage(distance_matrix, method='ward')
# 根据设定的阈值进行聚类划分
clusters: np.ndarray = fcluster(linkage_matrix, self.threshold, criterion='distance')
# 将簇编号添加到DataFrame中
self.df['Cluster'] = clusters
# 按簇编号排序,并去掉Cluster列
self.df = self.df.sort_values(by=['Cluster']).drop(columns=['Cluster'])

def save_csv(self) -> None:
"""将处理后的DataFrame保存回CSV文件"""
self.df.to_csv(self.output_csv, index=False, encoding='utf-8-sig')

def run(self) -> None:
"""
运行完整的数据处理流程,包括读取CSV、聚类排序、保存CSV
"""
self.read_csv()
self.cluster_and_sort()
self.save_csv()


# 示例用法
if __name__ == "__main__":
# 指定输入和输出CSV文件路径以及需要聚类的列
clustering: EditDistanceClustering = EditDistanceClustering(
'data/second_fine_grained_tasks_new.csv',
'data/second_fine_grained_tasks_new_sorted1.csv',
'细粒度_任务相关查询'
)
# 运行聚类流程
clustering.run()


以上代码运行完之后,会将 data/second_fine_grained_tasks_new.csv 文件中的文本数据按照编辑距离进行层次聚类,并根据聚类结果进行排序,
最后将结果保存到 data/second_fine_grained_tasks_new_sorted1.csv

CATALOG