当前位置:   article > 正文

基于Word2vec文本聚类_词向量模型word2vec 与 聚类

词向量模型word2vec 与 聚类

基于Word2vec文本聚类

一、Word2vec

Word2vec词向量模型为Google于2013年提出,可以看为无监督神经网络模型,包括输入层-隐藏层-输出层,实现表征语义信息的词向量,根据输入层与输出层的不同,分为两个模型Skip-gram(跳字模型,输入中心词预测周边词)和CBOW(连续词袋模型,输入周边词预测中心词)。

1.Word2vec与one-hot编码关系

对比one-hot编码,明显能降低表征词向量的维度,避免one-hot维度灾难,同时降低的矩阵的稀疏性,Word2vec维度低且稠密;Word2vec可以实现词与词之间联系,而one-hot编码更像是信息孤岛,割裂了词与词之间的联系

2.Word2vec训练过程

用Skip-gram模型图解来说,即中心词预测周边词。
第一步:输入层为one-hot编码,维度为V,指定词embedding后的向量为维度为N,(输入层与隐藏层之间)之间W(VN)嵌入矩阵,最后留下该矩阵,赋予每个词向量。
第二步:隐藏层与输出层之间权重矩阵W(N
V)还原成V维度向量,透过softmax函数多分类实现,还原周边词为V的向量。
第三步,softmx函数与真实one-hot编码周边词向量存在差距,这样就可以构造损失函数,model采用的是交叉熵的损失函数,判断真实模型分布与训练模型分布差距,反向更新前面权重矩阵W。
第四步:这里的softmax多分类,可以想象一个根节点,下面全是一层的叶子节点,更新所有叶子节点,消耗资源过大,最后更新的softmax结果绝大多数与softmax前的矩阵对比变动会非常小,会让人直觉上这里会有一定优化空间, 文章作者给出负采样(Negative Sample)方案,选取一小部分权重来解决softmax复杂度问题,给定这个词正例和随机抽样选取负例,实际抽样会保证高频词大概率被抽到的概率同时,会提升抽到低频词的概率!
负采样选词
Skip-gram图示

3.Word2Vec过时??

确实过时了(仅专业人士而言),现在主流都是Bert,各类开源预训练模型很多了。Word2Vec比较经典,为NLP入门模型,入门必学,理解它可以进一步了解前人Embedding思想
网上有太多Word2Vec讲述,自行检索

之前训练过220M的维基百科的文章,给出计算机、苹果两个字段,可以看出别人叙述计算机时通常会提到编程、eniac等,是符合正常逻辑的,如果做文本聚类、知识图谱等方面应该有不错的效果,wiki文章地址: link

在这里插入图片描述

代码演示

数据为网络某平台公开的2021年某月份关于笔记本的评论数据集,使用场景,面对较多的文本数据,某些工作者需要快速整理出话题,可以尝试使用该类方法
import os
import random
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'SimHei'
from matplotlib.ticker import MaxNLocator
from warnings import filterwarnings
filterwarnings('ignore')
import re
import numpy as np
import pandas as pd
import jieba
from gensim.models import Word2Vec
from sklearn.cluster import MiniBatchKMeans
from sklearn.metrics import silhouette_samples, silhouette_score
from sklearn.feature_extraction.text import TfidfVectorizer
SEED = 42
random.seed(SEED)
os.environ["PYTHONHASHSEED"] = str(SEED)
np.random.seed(SEED)在这里插入代码片
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
#分词代码
def jieba_cut(mytext):
    jieba.load_userdict('custwords.txt')
    jieba.initialize()
    with open('stopwords.txt',encoding ='utf-8') as f:
        file_stop = f.readlines()
        stop_list = []
        for line in file_stop:
            line = re.sub('\n|\\r', '', line)
            stop_list.append(line)
        word_list = []
        #jieba分词
    seg_list = jieba.lcut(mytext)
    for seg_word in seg_list:
        if seg_word not in stop_list:
            word_list.append(seg_word)      
    return (" ").join(word_list)在这里插入代码片
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
数据已经清洗,去除敏感信息、符号等等,
df_data = pd.read_excel('commentkk.xlsx')
df_data['content_clean'] = df_data.content_clean.apply(jieba_cut)
cut_word_list = np.array([cont.split() for cont in df_data.content_clean.tolist()])
  • 1
  • 2
  • 3
#训练词向量模型,构建avg word2vec词向量,用于聚类
model = Word2Vec(sentences=cut_word_list, vector_size=200, workers=1, seed=SEED)
def vectorize(cut_word_list, model):
    features = []
    for tokens in cut_word_list:
        zero_vector = np.zeros(model.vector_size)
        vectors = []
        for token in tokens:
            if token in model.wv:
                try:
                    vectors.append(model.wv[token])
                except KeyError:
                    continue
        if vectors:
            vectors = np.asarray(vectors)
            avg_vec = vectors.mean(axis=0)
            features.append(avg_vec)
        else:
            features.append(zero_vector)
    return features
vector_sentence = vectorize(cut_word_list, model=model)
len(vector_sentence),df_data.shape[0],vector_sentence[1].shape
(5813, 5813, (200,))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
这边聚类采用的MiniBatchKMeans算法,该算法本身多应用于较大数据的量,其实这里不适合用这个算法,建议用KMeans等其他的聚类model可能会更好,聚类方法的语法基本一样;
选取聚类最佳簇数一般用轮廓系数,表示的意思簇内距离越小越好,簇间距离越大越好,在[-1,1]之间,越接近的1的簇类个数聚类效果越好
X=vector_sentence
mb = 500
km_cloest_distance = [MiniBatchKMeans(n_clusters=k,batch_size=mb).fit(X) for k in range(1,30)]
#**有坑见官方文档解释Note that Silhouette Coefficient is only defined if number of labels is 2 <= n_labels <= n_samples - 1
silhouette_scores = [silhouette_score(X,model.labels_) for model in km_cloest_distance[1:]]
print(min(silhouette_scores))
plt.gca().xaxis.set_major_locator(MaxNLocator(integer=True))
plt.plot(range(2,30),silhouette_scores,'bo-')
plt.show()
0.17193452767226713
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在这里插入图片描述

这里我们发现一个奇怪的现象,刚才说明使用轮廓系数越近1的簇作为最佳簇类个数,明显当簇的数量等于2,效果最好,那么按照理解取2是最好的吗?其实并非如此,1.聚类算法采用轮廓系数来指定最佳簇数本身就值得争议,2.数据本身为产品评论数据,文本差异较小,我们选取“清晰”字段文本,看相似程度几个词及相似度,可以猜侧每条记录之间平均词向量差异较小
model.wv.most_similar("清晰")
[('屏幕', 0.9968936443328857),
 ('效果', 0.9953073859214783),
 ('色彩', 0.9946492314338684),
 ('护眼', 0.9914485216140747),
 ('然', 0.9887149333953857),
 ('散热', 0.9876371622085571),
 ('流畅', 0.9875931739807129),
 ('速度快', 0.9864599704742432),
 ('高清', 0.9842337965965271),
 ('舒服', 0.9837706685066223)]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
这边选择的依据Wie,轮廓系数在趋于稳定,尽量不要偏0,虽然在数据层面有重叠,但是对于挑选的主题影响不是很大,这边选取簇的数量等于18
n=18
km = MiniBatchKMeans(n_clusters=n, batch_size=mb).fit(X)
label_result = km.labels_
df_data['clustering'] = pd.DataFrame(label_result)
df_data.to_excel("filecluster.xlsx")
  • 1
  • 2
  • 3
  • 4
  • 5
我们这里明显可以看出第一个聚类topic讲的是一个物流速度快、笔记本很满意一个话题,已经能够满足需求了在这里插入图片描述
当然也有很多用TF-IDF算法来做文本聚类,已经该做过该聚类,不贴代码了,说下感受,TF-IDF有效果,但不如Word2vec有效,其实从TF-IDF原理上应该不如Word2vec,它没有考虑到词之间的关系,更多是表现词在预料的权重度(转载注明出处)
本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号