如何用Python执行K-means文本聚类?业务ID分类聚类方案咨询
嘿,我来帮你捋清楚这个商家聚类的问题~
一、你的思路可行性分析
首先得说,你的思路有一定合理性,但存在几个容易踩的坑:
- 手动构建类别字典分组太主观了:比如像"Wine & Pizza"和"Gastropubs & Wine"这种有重叠标签的,手动分组很容易忽略它们的关联,而且标签数量一多,手动分组效率极低还容易出错。
- 更顺的路径应该是:先把每个商家的标签集合转成机器能理解的数值向量,再直接用K-means聚类,让模型自动捕捉标签之间的关联,得到更客观的簇结构,不用提前手动给标签分组。
二、针对你的数据的Python最优实现
你的数据是每个商家对应多个标签,属于多标签短文本聚类场景,直接按下面的步骤来就行:
1. 先把数据整理成顺手的格式
把你的列表转成字典,后续处理更方便:
business_data = { "business_id_a": ["Food", "Restaurant", "Wine & Pizza"], "business_id_b": ["Mexican", "Burgers", "Gastropubs & Wine"], "business_id_k": ["Automotive", "Delivery", "Whatever"] # 把你的海量数据都塞进来就行 }
2. 把标签转成数值向量
这里用TF-IDF最适合,因为它能衡量每个标签在整个数据集中的重要性,避免那些太常见的标签干扰聚类结果:
from sklearn.feature_extraction.text import TfidfVectorizer # 把每个商家的标签列表转成空格分隔的字符串,方便向量器处理 texts = [" ".join(tags) for tags in business_data.values()] # 初始化TF-IDF向量器,这里用lambda直接按空格拆分标签就行 vectorizer = TfidfVectorizer(tokenizer=lambda x: x.split()) # 生成每个商家的向量矩阵 X = vectorizer.fit_transform(texts)
3. 用K-means聚类,重点选对K值
K值选不好聚类结果会很离谱,推荐用肘部法则来找最优K:
from sklearn.cluster import KMeans import matplotlib.pyplot as plt # 测试不同K值的聚类效果 inertias = [] k_candidates = range(2, 10) # 可以根据你的数据量调整范围 for k in k_candidates: kmeans = KMeans(n_clusters=k, random_state=42, n_init='auto') kmeans.fit(X) inertias.append(kmeans.inertia_) # 画肘部图,找拐点对应的K就是最优值 plt.plot(k_candidates, inertias) plt.xlabel("Number of Clusters (K)") plt.ylabel("Inertia (Cluster Compactness)") plt.title("Elbow Method to Find Optimal K") plt.show()
比如图里拐点在K=3,那就用K=3训练最终模型:
optimal_k = 3 # 替换成你找到的最优K kmeans = KMeans(n_clusters=optimal_k, random_state=42, n_init='auto') cluster_labels = kmeans.fit_predict(X) # 把商家ID和聚类结果对应起来,再按簇分组 from collections import defaultdict clustered_businesses = defaultdict(list) for business_id, cluster in zip(business_data.keys(), cluster_labels): clustered_businesses[cluster].append(business_id) # 看看结果,顺便打印每个簇的核心标签,更直观 for cluster_id, businesses in clustered_businesses.items(): print(f"Cluster {cluster_id}:") print(f"Businesses: {businesses}") # 找出该簇中心对应的Top3标签 top_tag_indices = kmeans.cluster_centers_[cluster_id].argsort()[-3:][::-1] top_tags = [vectorizer.get_feature_names_out()[i] for i in top_tag_indices] print(f"Core Tags: {top_tags}\n")
三、通用文本K-means聚类的实现步骤
如果是处理更长的文本(比如商家评论、描述),步骤类似,但预处理要更细致:
1. 先做文本清洗
比如去标点、去停用词、词形还原,让文本更干净:
import re from nltk.corpus import stopwords from nltk.stem import WordNetLemmatizer # 先下载nltk的停用词和词形还原数据(第一次运行需要) # import nltk # nltk.download('stopwords') # nltk.download('wordnet') stop_words = set(stopwords.words('english')) lemmatizer = WordNetLemmatizer() def clean_text(text): # 去掉特殊字符和数字 text = re.sub(r'[^a-zA-Z\s]', '', text) # 全部转小写 text = text.lower() # 分词后去除停用词+词形还原 words = [lemmatizer.lemmatize(word) for word in text.split() if word not in stop_words] return " ".join(words) # 示例:处理长文本 long_texts = [ "This cozy Italian restaurant serves amazing wood-fired pizza and imported wine.", "Our gastropub offers juicy Mexican burgers and craft beer on tap." ] cleaned_texts = [clean_text(text) for text in long_texts]
2. 文本向量化
还是用TF-IDF,要是文本量特别大,可以限制特征数量避免维度爆炸:
vectorizer = TfidfVectorizer(max_features=1000) # 保留Top1000重要特征 X = vectorizer.fit_transform(cleaned_texts)
3. K-means聚类
和之前的步骤一样,用肘部法则选K,训练模型,然后分析结果就行。
额外小Tips
- 如果你的标签有明显的层级关系(比如"Restaurant"是大类,"Mexican"是子类),可以先把每个标签转成Word2Vec向量,再对每个商家的所有标签向量取平均,用这个平均向量来聚类,这样能更好捕捉标签的语义关联。
- K-means对初始中心敏感,sklearn 1.2+版本可以设置
n_init='auto',让模型自动选最优初始中心,避免局部最优。
内容的提问来源于stack exchange,提问作者f_s




