You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python新手求教:如何用nltk.cluster.kmeans.KMeansClusterer聚类句子及替换距离算法

使用NLTK的KMeansClusterer实现句子聚类并替换为莱文斯坦距离

嘿,作为Python新手,想用NLTK的KMeansClusterer做句子聚类还换距离度量?别担心,我一步步给你讲明白,保证你能上手!

一、先从基础入手:用欧氏距离实现句子聚类

KMeans本质是基于数值向量的聚类算法,所以第一步得把句子转换成机器能理解的数值形式,这里我们用TF-IDF向量来做示例:

1. 准备工作:安装依赖并导入库

import nltk
from nltk.cluster import KMeansClusterer
from sklearn.feature_extraction.text import TfidfVectorizer
import numpy as np

# 第一次运行需要下载NLTK的分词资源
nltk.download('punkt')

2. 准备测试句子

sentences = [
    "I love coding in Python",
    "Python is my favorite programming language",
    "Machine learning with Python is fun",
    "I enjoy reading books",
    "Books are a great source of knowledge",
    "Reading helps expand your mind"
]

3. 将句子转为TF-IDF向量

TF-IDF能把句子转换成反映词重要性的数值向量:

# 用NLTK的punkt分词器初始化TF-IDF向量器
vectorizer = TfidfVectorizer(tokenizer=nltk.word_tokenize)
tfidf_matrix = vectorizer.fit_transform(sentences).toarray()

4. 运行KMeans聚类(欧氏距离)

NLTK的KMeansClusterer默认支持欧氏距离,也可以显式指定:

num_clusters = 2  # 我们分成2个簇

# 初始化聚类器,repeats参数表示重复运行多次取最优结果(避免初始质心影响)
clusterer = KMeansClusterer(
    num_clusters,
    distance=nltk.cluster.util.euclidean_distance,
    repeats=10
)
# 执行聚类并获取每个句子的簇编号
clusters = clusterer.cluster(tfidf_matrix, assign_clusters=True)

# 输出结果
print("欧氏距离聚类结果:")
for idx, sentence in enumerate(sentences):
    print(f"句子: {sentence} -> 簇编号: {clusters[idx]}")

二、替换为莱文斯坦(编辑)距离

莱文斯坦距离是直接计算两个字符串之间的编辑操作次数(插入、删除、替换),适合从文本的字面相似度来聚类。但这里要注意:KMeans默认是处理数值向量的,所以我们需要自定义两个关键部分:距离计算函数和质心计算函数(因为原来的均值计算对字符串无效)。

1. 导入莱文斯坦距离工具

NLTK自带了编辑距离的实现:

from nltk.metrics import edit_distance

2. 自定义距离函数

其实直接用edit_distance就行,不过我们可以包装一下让逻辑更清晰:

def levenshtein_distance(s1, s2):
    # 计算两个句子的编辑距离
    return edit_distance(s1, s2)

3. 自定义质心计算函数

对于字符串簇,我们没法计算"均值",所以选簇内到其他所有句子编辑距离总和最小的句子作为质心:

def levenshtein_centroid(cluster_samples):
    min_total_dist = float('inf')
    best_centroid = None
    for sample in cluster_samples:
        # 计算当前样本到簇内所有其他样本的距离总和
        total_dist = sum(levenshtein_distance(sample, other) for other in cluster_samples)
        if total_dist < min_total_dist:
            min_total_dist = total_dist
            best_centroid = sample
    return best_centroid

4. 运行基于莱文斯坦距离的KMeans聚类

这次我们直接传入句子字符串,不用转成数值向量:

clusterer_lev = KMeansClusterer(
    num_clusters,
    distance=levenshtein_distance,
    centroid_func=levenshtein_centroid,
    repeats=10
)
# 直接用sentences作为输入
clusters_lev = clusterer_lev.cluster(sentences, assign_clusters=True)

# 输出结果
print("\n莱文斯坦距离聚类结果:")
for idx, sentence in enumerate(sentences):
    print(f"句子: {sentence} -> 簇编号: {clusters_lev[idx]}")

一些注意事项给新手

  • 莱文斯坦距离的计算复杂度是O(n*m)(n和m是两个句子的长度),如果你的数据集很大、句子很长,速度会比较慢,适合小样本场景。
  • KMeans对初始质心很敏感,所以repeats参数建议设置大一点(比如10),取多次运行后的最优结果。
  • 如果你的需求是基于语义相似度聚类,其实更适合用Word2Vec/BERT把句子转成语义向量,再用欧氏或余弦距离聚类,莱文斯坦更适合字面相似度的场景。

内容的提问来源于stack exchange,提问作者user3350047

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:21:04