简介
使用sklearn
基于TF_IDF算法,实现把文本变成向量。再使用sklearn的kmeans聚类算法进行文本聚类。
个人观点:这是比较古老的技术了,文本转向量的效果不如如今的 text2vec 文本转向量好。
而且sklearn 不支持GPU加速,处理大量数据速度极慢。
实现
项目完整可运行代码:https://github.com/JieShenAI/csdn/blob/main/machine_learning/TF-IDF%20sklearn聚类.ipynb
import re
import random
import jieba
import pandas as pd
import numpy as np
from sklearn.feature_extraction.text import TfidfTransformer, TfidfVectorizer
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.cluster import KMeans
import gensim
from gensim.models import Word2Vec
from sklearn.preprocessing import scale
import multiprocessing
语料库如下
corpus = ['花呗更改绑定银行卡','我什么时候开通了花呗','A man is eating food.','A man is eating a piece of bread.','The girl is carrying a baby.','A man is riding a horse.','A woman is playing violin.','Two men pushed carts through the woods.','A man is riding a white horse on an enclosed ground.'
]
jieba 分词
jieba.add_word("花呗")
,给jieba添加花呗
, 不然 jieba 会把花呗拆分成'花', '呗'
。
分词模型,用起来还是有点麻烦
jieba.add_word("花呗")def preprocess_text(content_lines, sentences):for line in content_lines:try:segs=jieba.lcut(line)segs = [v for v in segs if not str(v).isdigit()]#去数字segs = list(filter(lambda x:x.strip(), segs)) #去左右空格segs = list(filter(lambda x:len(x)>1, segs)) #长度为1的字符# segs = list(filter(lambda x:x not in stopwords, segs)) #去掉停用词sentences.append(" ".join(segs))except Exception:print(line)continuesentences = []
# 处理语料,语料的处理结果存放在sentences
preprocess_text(corpus, sentences)
jieba 分词结果如下:
利用 TF_IDF 算法把分词结果转成向量
vectorizer = TfidfVectorizer(sublinear_tf=True, max_df=0.5)
#统计每个词语的tf-idf权值
transformer = TfidfTransformer()
# 第一个fit_transform是计算tf-idf 第二个fit_transform是将文本转为词频矩阵
tfidf = transformer.fit_transform(vectorizer.fit_transform(sentences))
# 获取词袋模型中的所有词语
word = vectorizer.get_feature_names_out()
# 将tf-idf矩阵抽取出来,元素w[i][j]表示j词在i类文本中的tf-idf权重
weight = tfidf.toarray()
#查看特征大小
print ('Features length: ' + str(len(word)))
如下图所示,向量矩阵过于稀疏了,没有worc2vec
编码的向量稠密。
编码的向量是33纬;
模型
为了方便使用,在JieKmeans
类中封装了,kmeans聚类训练、预测和绘图功能。
from sklearn.decomposition import PCAclass JieKmeans:def __init__(self, numClass=4, n_components=10, func_type='PCA'):#这里也可以选择随机初始化init="random"self.PCA = PCA(n_components=n_components)if func_type == 'PCA':self.func_plot = PCA(n_components=2)elif func_type == 'TSNE':from sklearn.manifold import TSNEself.func_plot = TSNE(2)self.numClass = numClassdef plot_cluster(self, result, newData):plt.figure(2)Lab = [[] for i in range(self.numClass)]index = 0for labi in result:Lab[labi].append(index)index += 1color = ['oy', 'ob', 'og', 'cs', 'ms', 'bs', 'ks', 'ys', 'yv', 'mv', 'bv', 'kv', 'gv', 'y^', 'm^', 'b^', 'k^','g^'] * 3for i in range(self.numClass):x1 = []y1 = []for ind1 in newData[Lab[i]]:# print ind1try:y1.append(ind1[1])x1.append(ind1[0])except:passplt.plot(x1, y1, color[i])#绘制初始中心点x1 = []y1 = []for ind1 in self.model.cluster_centers_:try:y1.append(ind1[1])x1.append(ind1[0])except:passplt.plot(x1, y1, "rv") #绘制中心plt.show()def train(self, data):tmp = self.PCA.fit_transform(data)self.model = KMeans(n_clusters=self.numClass,max_iter=10000, init="k-means++", tol=1e-6)s = self.model.fit(tmp)print("聚类算法训练完成\n", s)def predict(self, data):t_data = self.PCA.fit_transform(data)result = list(self.model.predict(t_data))return resultdef plot(self, weight):t_data = self.PCA.fit_transform(weight)result = list(self.model.predict(t_data))plot_pos = self.func_plot.fit_transform(weight)self.plot_cluster(result, plot_pos)
net = JieKmeans(numClass=3, # 聚类类别n_components=5,func_type='PCA' # 绘图降纬方法)net.train(weight)
# net.plot(weight)
聚类可视化
net.plot(weight)
如上图所示,上图的可视化显示聚类效果很好,但是由于TF-IDF文本转向量的效果不是很好,所以上述聚类出来的结果可能并不是我们想要的。
预测结果:
p = net.predict(weight)class_data = {i:[]for i in range(3)
}for text,cls in zip(corpus, p):class_data[cls.item()].append(text)class_data
聚类结果如下:
进一步阅读
点击即可阅读,基于word2vec 和 kmeans_pytorch 的文件聚类实现,利用GPU加速提高聚类速度
该文使用text2vec通过cuda加速,加快文本转向量的速度。使用kmeans_pytorch包,基于pytorch在GPU上计算,提高聚类速度。
如下是其基于word2vec的聚类结果: