中文自然语言处理--基于KMeans++的中文短文本聚类

文本聚类是将一个个文档由原有的自然语言文字信息转化成数学信息,以高维空间点的形式展现出来,通过计算哪些点距离比较近,从而将那些点聚成一个簇,簇的中心叫做簇心。一个好的聚类要保证簇内点的距离尽量的近,但簇与簇之间的点要尽量的远。
而KMeans++:
KMeans++是KMeans的改进。K-means算法是很典型的基于距离的聚类算法,采用距离 作为相似性的评价指标,即认为两个对象的距离越近,其相似度就越大。该算法认为簇是由距离靠近的对象组成的,因此把得到紧凑且独立的簇作为最终目标。k-means算法特点在于:同一聚类的簇内的对象相似度较高;而不同聚类的簇内的对象相似度较小。k-means++算法对选择初始seeds进行了改进,基本思想就是:初始的聚类中心之间的相互距离要尽可能的远。

代码:

import random
import jieba
import pandas as pd
import numpy as np
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer
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
from sklearn.manifold import TSNE

# 整个过程分为以下几个步骤:语料加载,分词,去停用词,抽取词向量特征,
# 实战 TF-IDF 的中文文本 K-means 聚类,实战 word2Vec 的中文文本 K-means 聚类

# 加载停用词
stopwords = pd.read_csv('./NB_SVM/stopwords.txt', index_col=False, quoting=3, sep="\t", names=['stopword'], encoding='utf-8')
stopwords = stopwords['stopword'].values
print("stopwords:\n", stopwords)

# 加载语料,语料是4个已经分好类的 csv 文件
laogong_df = pd.read_csv('./NB_SVM/beilaogongda.csv', encoding='utf-8', sep=',', index_col=[0])
laopo_df = pd.read_csv('./NB_SVM/beilaopoda.csv', encoding='utf-8', sep=',', index_col=[0])
erzi_df = pd.read_csv('./NB_SVM/beierzida.csv', encoding='utf-8', sep=',', index_col=[0])
nver_df = pd.read_csv('./NB_SVM/beinverda.csv', encoding='utf-8', sep=',', index_col=[0])
# 删除语料的nan行
laogong_df.dropna(inplace=True)
laopo_df.dropna(inplace=True)
erzi_df.dropna(inplace=True)
nver_df.dropna(inplace=True)
print("laogong_df:\n", laogong_df)
print("laopo_df:\n", laopo_df)
print("erzi_df:\n", erzi_df)
print("nver_df:\n", nver_df)
# 转换
laogong = laogong_df.segment.values.tolist()
laopo = laopo_df.segment.values.tolist()
erzi = erzi_df.segment.values.tolist()
nver = nver_df.segment.values.tolist()

# 分词和去停用词
# 定义分词函数preprocess_text
# 参数content_lines即为上面转换的list
# 参数sentences是定义的空list,用来储存分词后的数据
jieba.add_word("报警人")
jieba.add_word("防护装备")
jieba.add_word("防护设备")
jieba.suggest_freq(("人", "称"), tune=True)
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)
            continue

# 调用函数、生成训练数据
sentences = []
preprocess_text(laogong, sentences)
preprocess_text(laopo, sentences)
preprocess_text(erzi, sentences)
preprocess_text(nver, sentences)
# 将得到的数据集打散,生成更可靠的训练集分布,避免同类数据分布不均匀
random.shuffle(sentences)
# 控制台输出前10条数据
for sentence in sentences[:10]:
    print(sentence)

'''
    CountVectorizer 的作用是将文本文档转换为计数的稀疏矩阵;
    TfidfTransformer 使用计算 tf-idf;
    TfidfVectorizer 相当于 CountVectorizer + TfidfTransformer,如:
    vectorizer=CountVectorizer()
    transformer=TfidfTransformer()
    tfidf=transformer.fit_transform(vectorizer.fit_transform(corpus))
    等价于:
    transformer=TfidfVectorizer()
    tfidf=transformer.fit_transform(corpus)
'''
# 抽取特征,将文本中的词语转换为词频矩阵,统计每个词语的 tf-idf 权值,获得词在对应文本中的 tf-idf 权重
# 将文本中的词语转换为词频矩阵 矩阵元素a[i][j] 表示j词在i类文本下的词频
# CountVectorizer是属于常见的特征数值计算类,是一个文本特征提取方法。对于每一个训练文本,它只考虑每种词汇在该训练文本中出现的频率。
# CountVectorizer会将文本中的词语转换为词频矩阵,它通过fit_transform函数计算各个词语出现的次数。
# analyzer    一般使用默认,可设置为string类型,如’word’, ‘char’, ‘char_wb’,还可设置为callable类型,比如函数是一个callable类型
# max_features    默认为None,可设为int,对所有关键词的term frequency进行降序排序,只取前max_features个作为关键词集
vectorizer = CountVectorizer(analyzer='word',  # tokenise by character ngrams
                             ngram_range=(1, 2),  # use ngrams of size 1 and 2
                             max_features=20000  # keep the most common 1000 ngrams
                             )
#统计每个词语的tf-idf权值
transformer = TfidfTransformer()
# 第一个fit_transform是计算tf-idf 第二个fit_transform是将文本转为词频矩阵
tfidf = transformer.fit_transform(vectorizer.fit_transform(sentences))
# 获取词袋模型中的所有词语
word = vectorizer.get_feature_names()
print(word)
# 将tf-idf矩阵抽取出来,元素w[i][j]表示j词在i类文本中的tf-idf权重
weight = tfidf.toarray()
#查看特征大小
print('Features length: ' + str(len(word)))

# TF-IDF 的中文文本 K-means 聚类
numClass = 4  # 聚类分几簇
clf = KMeans(n_clusters=numClass, max_iter=10000, init="k-means++", tol=1e-6)  # 这里也可以选择随机初始化init="random"
pca = PCA(n_components=10)  # 降维
TnewData = pca.fit_transform(weight)  # 载入N维
s = clf.fit(TnewData)

# 聚类结果可视化函数 plot_cluster(result,newData,numClass),该函数包含3个参数,
# 其中 result 表示聚类拟合的结果集;
# newData 表示权重 weight 降维的结果,这里需要降维到2维,即平面可视化;
# numClass 表示聚类分为几簇
def plot_cluster(result, newData, numClass):
    # num: 图像编号或名称,字符串为名称
    plt.figure(2)
    Lab = [[] for i in range(numClass)]
    index = 0
    for labi in result:
        Lab[labi].append(index)
        index += 1
    color = ['oy', 'ob', 'og', 'cs', 'ms', 'bs', 'ks', 'ys', 'yv', 'mv', 'bv', 'kv', 'gv', 'y^', 'm^', 'b^', 'k^',
             'g^'] * 3
    for i in range(numClass):
        x1 = []
        y1 = []
        for ind1 in newData[Lab[i]]:
            # print ind1
            try:
                y1.append(ind1[1])
                x1.append(ind1[0])
            except:
                pass
        plt.plot(x1, y1, color[i])

    # 绘制初始中心点
    x1 = []
    y1 = []
    for ind1 in np.array(clf.cluster_centers_):
        try:
            y1.append(ind1[1])
            x1.append(ind1[0])
        except:
            pass
    plt.plot(x1, y1, "rv")  # 绘制中心
    plt.show()

pca = PCA(n_components=2)  # 输出两维
newData = pca.fit_transform(weight)  # 载入N维
result = list(clf.predict(TnewData))
print(clf.cluster_centers_)
print(result)
plot_cluster(result,newData,numClass)

# TSNE 保留下的属性信息,更具代表性,也即最能体现样本间的差异,但是 TSNE 运行极慢,PCA 则相对较快
ts = TSNE(2)
newData = ts.fit_transform(weight)
result = list(clf.predict(TnewData))
# 结果并不是很好
plot_cluster(result, newData, numClass)

# 更为一般的处理,常常先用 PCA 进行降维,再使用 TSNE
newData = PCA(n_components=4).fit_transform(weight)  # 载入N维
newData = TSNE(2).fit_transform(newData)
result = list(clf.predict(TnewData))
plot_cluster(result, newData, numClass)

# 从优化和提高模型准确率来说,主要有两方面可以尝试:
# 特征向量的构建,除了词袋模型、tf-idf模型,可以考虑使用 word2vec 和 doc2vec 等;
# 模型上可以采用基于密度的 DBSCAN、层次聚类等算法。

原文:
https://soyoger.blog.csdn.net/article/details/108729407

  • 3
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
K-means是常用的聚类算法之一,它的主要思想是将数据点分为K个簇,使得同一簇内的点相似度较高,不同簇之间的点相似度较低。在scikit-learn中,KMeans聚类算法已经实现,可以方便地进行聚类操作。 本文将介绍使用scikit-learn中的KMeans聚类算法进行聚类的步骤和实现方法,并介绍MiniBatchKMeans的使用。 ## 1. 数据准备 我们先生成一个随机数据集,用于演示KMeans聚类: ```python import numpy as np # 生成随机数据 np.random.seed(0) X = np.random.randn(1000, 2) # 生成1000个二维数据点 ``` ## 2. 模型训练 接下来,我们使用KMeans模型对数据进行聚类: ```python from sklearn.cluster import KMeans # 构建模型 kmeans = KMeans(n_clusters=3, random_state=0) # 训练模型 kmeans.fit(X) ``` 这里选择将数据分为3个簇,可以根据实际情况进行调整。训练完成后,我们可以查看簇中心点的位置: ```python print(kmeans.cluster_centers_) ``` 输出: ``` [[ 0.05161133 -0.96525049] [ 1.06359705 -0.02646225] [-0.9680658 0.04252211]] ``` ## 3. 预测和评估 训练完成后,我们可以使用训练好的模型对新数据进行预测: ```python # 预测新数据 y_pred = kmeans.predict(X) ``` 对于聚类算法,我们可以使用轮廓系数(Silhouette Coefficient)评估聚类效果。轮廓系数是一种衡量聚类质量的指标,取值范围在[-1, 1]之间,越接近1表示聚类效果越好。在scikit-learn中,可以使用metrics.silhouette_score来计算轮廓系数: ```python from sklearn import metrics # 计算轮廓系数 score = metrics.silhouette_score(X, y_pred) print(score) ``` 输出: ``` 0.6011942331016043 ``` ## 4. MiniBatchKMeans KMeans聚类算法的一个问题是它对于大规模数据的聚类会比较慢。因此,scikit-learn中还提供了MiniBatchKMeans算法,它可以加快聚类速度。 MiniBatchKMeans的使用方法与KMeans类似: ```python from sklearn.cluster import MiniBatchKMeans # 构建模型 mbkmeans = MiniBatchKMeans(n_clusters=3, random_state=0) # 训练模型 mbkmeans.fit(X) # 预测新数据 y_pred = mbkmeans.predict(X) # 计算轮廓系数 score = metrics.silhouette_score(X, y_pred) print(score) ``` 需要注意的是,MiniBatchKMeans算法在聚类效果上可能会稍微劣于KMeans算法,但是速度更加快捷。在处理大规模数据时,可以优先考虑使用MiniBatchKMeans算法。 本文介绍了使用scikit-learn中的KMeans聚类算法进行聚类的步骤和实现方法,并介绍了MiniBatchKMeans的使用。在实际应用中,可以根据实际情况选择不同的聚类算法和参数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值