传统向量空间模型的缺陷
向量空间模型简单的基于单词的出现与否以及TF-IDF等信息来进行检索,但是“说了或者写了哪些单词”和“真正想表达的意思”之间有很大的区别,其中两 个重要的阻碍是单词的多义性(polysems)和同义性(synonymys)。多义性指的是一个单词可能有多个意思,比如Apple,既可以指水果苹果,也可以指苹果公司;而同义性指的是多个不同的词可能表示同样的意思,比如search和find。
Latent Semantic Analysis (Latent Semantic Indexing)
我们希望找到一种模型,能够捕获到单词之间的相关性。如果两个单词之间有很强的相关性,那么当一个单词出现时,往往意味着另一个单词也应该出现(同义词);反之,如果查询语句或者文档中的某个单词和其他单词的相关性都不大,那么这个词很可能表示的是另外一个意思(比如在讨论互联网的文章中,Apple 更可能指的是Apple公司,而不是水果) 。
LSA(LSI)使用SVD来对单词-文档矩阵进行分解。SVD可以看作是从单词-文档矩阵中发现不相关的索引变量(因子),将原来的数据映射到语义空间内。在单词-文档矩阵中不相似的两个文档,可能在语义空间内比较相似。我们是一个使用sklearn中的TruncatedSVD进行文本主题分析。通过主题分析,我们可以得到一个语料中的关键主题,即各个词语在主题中的重要程度,各个文章在各个主题上的倾向程度。并且可以根据它们,得到主题对应的关键词以及代表性文本。
实现步骤
(1)将数据填充空白值处理后抽样50条差评(或差评)。
(2)分词、停用词处理得到如图1的结果。
(3)将(2)的结果作为输入,调用TfidfVectorizer.fit_transform方法得到词向量矩阵
(4)设定主题数、能代表主题的文档数、主题的关键词数,调用TruncatedSVD方法处理
(5)打印结果。
图1 分词结果
实现代码:
import numpy as np import pandas as pd from sklearn.decomposition import TruncatedSVD import jieba import re #from sklearn.feature_extraction.text import CountVectorizer from sklearn.feature_extraction.text import TfidfVectorizer #df = pd.DataFrame(pd.read_excel("D:\\用户目录\\我的文档\\182学期\\大数据管理技术\\评论\\558款.xls",encoding='gbk') data = pd.read_excel("C://Users//ASUS//Desktop//词频文件及tfidf值文件//1258款.xlsx",encoding='gbk') data['字数']=data['字数'].fillna('0') data[(data.字数=='0')].index.tolist data=data.drop([62, 75, 76, 108, 150, 159, 160, 191, 227, 240, 248, 284, 286]) df=pd.DataFrame(data) df1=df.loc[df['评论类型'].isin(['好评'])] df_outer=df1.sample(n=50, replace=False, random_state=None, axis=0) #df2=df.loc[df['评论类型'].isin(['好评'])] #df2=df2.sample(n=50, replace=False, random_state=None, axis=0) #df_outer=pd.merge(df1,df2,how='outer') #取表中的第1列的所有值 print(u"获取总评内容") df_outer.drop('字数',axis=1,inplace=False) df_outer['总评'] = df_outer['评论'] col=df_outer['总评'] stopwords = [line.strip() for line in open("C://Users//ASUS//Desktop//词频文件及tfidf值文件//stop.txt", 'r', encoding='gbk').readlines()] #print(stopwords) import jieba arrs = col.values corpus=[] for a in arrs: a = re.sub("[^\u4e00-\u9fa5]", "",a)#正则表达式 #print(a) seglist = jieba.cut(a,cut_all=False) #精确模式 #print(seglist) final = '' for seg in seglist: #seg = seg.encode('utf-8') #seg=str(seg) if seg.strip() not in stopwords: #不是停用词的保留 final += seg seg_list = jieba.cut(final, cut_all=False) #output = ''.join(str(list(seg_list))) #空格拼接 #list2 = [str(i) for i in output] #list3 = ' '.join(list2) output=list(seg_list) list3 = ' '.join(output) #print(list3) # list=' '.join(output) #print(list) #print(output) corpus.append(list3) # print(list3) vectorizer = TfidfVectorizer() X = vectorizer.fit_transform(corpus) word = vectorizer.get_feature_names() #print(word) #print(X.toarray()) n_pick_topics = 3 # 设定主题数为3 lsa = TruncatedSVD(n_pick_topics) X2 = lsa.fit_transform(X) n_pick_docs= 3 topic_docs_id = [X2[:,t].argsort()[:-(n_pick_docs+1):-1] for t in range(n_pick_topics)] #print(topic_docs_id) n_pick_keywords = 4 topic_keywords_id = [lsa.components_[t].argsort()[:-(n_pick_keywords+1):-1] for t in range(n_pick_topics)] print(topic_keywords_id) for t in range(n_pick_topics): print("topic %d:" % t) print(" keywords: %s" % ", ".join(word[topic_keywords_id[t][j]] for j in range(n_pick_keywords))) for i in range(n_pick_docs): print(" doc %d" % i) print("\t"+corpus[topic_docs_id[t][i]])
其中结果和源数据如表1,表2:
表1 好评(实例)
| topic 0 | topic 1 | topic 2 |
Keyword 0 | 看书 | 喜欢 | 终于 |
Keyword 1 | 不错 | 眼睛 | 手机 |
Keyword 2 | 舒服 | 客服 | 看书 |
Keyword 3 | 喜欢 | 反应 | 女神 |
doc 0 | 体验 真的 好 书籍 资源 丰富 书城 确实 好 看书 方便 眼睛 舒服 喜欢 看书 人 如获至宝 手机 吸引力 | 感觉 很棒 值 眼睛 累 客服 态度 好 问题解答 认真 反应 肯定 慢 看书 足矣 真的 喜欢 壳 | 想 买 终于 女神 节 下手 手 看书 手机 看书 反光 太 严重 |
doc 1 | 视频 完美 看书 专心 电子 水墨 屏 看着 真的 舒服 内置 阅读 灯 阳光 看书 眼睛 舒服 | 喜欢 再也 几斤 重 到处跑 精致 轻薄 水墨 屏 舒服 触摸 反应 不错 携带方便 伤 眼睛 看书 高效 挺好用 | 终于 买 心仪已久 电子书 满意 很护 眼看 不 累 利用 碎片 时间 看书 终于 放下 手机 好好学习 沉淀 |
doc 2 | 感觉 很棒 值 眼睛 累 客服 态度 好 问题解答 认真 反应 肯定 慢 看书 足矣 真的 喜欢 壳 | 单反 穷 三代 富 一身 一起 入手 两部 喜欢 喜欢 读书 赶紧 入手 轻薄 分辨率 高比 第一代 背光 更好 | 手机 看书 多年 学 近视 玩 多年 手机 事情 毕业 看书 感觉 眼镜 有点 模糊 尤其 完 手机 再 看电视 情况 明显 拯救 视力 说 包装 简陋 完全 库房 锅 库房 好 纸箱 |
表2 源数据(部分)
参考链接:https://blog.csdn.net/blmoistawinde/article/details/83446529 利用TruncatedSVD做文本主题分析