全文基于《射雕英雄传》语料库,下面是读入数据的一个基于Pandas的通用操作框架。
import pandas as pd
raw = pd.read_table("金庸-射雕英雄传txt精校版.txt",
names = ['txt'], encoding ="GBK")
def m_head(tmpstr):
return tmpstr[:1]
def m_mid(tmpstr):
return tmpstr.find("回 ")
raw['head'] = raw.txt.apply(m_head)
raw['mid'] = raw.txt.apply(m_mid)
raw['len'] = raw.txt.apply(len)
chapnum = 0
for i in range(len(raw)):
if raw['head'][i] == "第" and raw['mid'][i] > 0 and raw['len'][i] < 30 :
chapnum += 1
if chapnum >= 40 and raw['txt'][i] == "附录一:成吉思汗家族" :
chapnum = 0
raw.loc[i, 'chap'] = chapnum
del raw['head']
del raw['mid']
del raw['len']
rawgrp = raw.groupby('chap')
chapter = rawgrp.agg(sum)
chapter = chapter[chapter.index != 0]
计算两个词相似度的原理:简单的说,就是将每个词的向量在空间上进行余弦运算,当cos越接近0时候,两者越相似。
1.1词条相似度:word2vec
词袋模型不考虑词条之间的相关性,因此无法用于计算词条相似度。
分布式表达会考虑词条的上下文关联,因此能够提取出词条上下文中的相关性信息,而词条之间的相似度就可以直接利用此类信息加以计算。
目前主要使用gensim实现相应的算法。
gensim 通用格式list of list格式
gensim也提供了sklearn的API接口:sklearn_api.w2vmodel,可以在sklearn中直接使用。
class gensim.models.word2vec.Word2Vec(
sentences = None : 类似list of list的格式,对于特别大的文本,尽量考虑流式处理
size = 100 : 词条向量的维度,数据量充足时,300/500的效果会更好
window = 5 : 上下文窗口大小
workers = 3 : 同时运行的线程数,多核系统可明显加速计算
其余细节参数设定:
min_count = 5 : 低频词过滤阈值,低于该词频的不纳入模型
max_vocab_size = None : 每1千万词条需要1G内存,必要时设定该参数以节约内存
sample=0.001 : 负例采样的比例设定
negative=5 : 一般为5-20,设为0时不进行负例采样
iter = 5 : 模型在语料库上的迭代次数,该参数将被取消
与神经网络模型有关的参数设定:
seed=1, alpha=0.025, min_alpha=0.0001, sg=0, hs=0
chapter.head()
txtchap1.0第一回 风雪惊变 那说话人五十来岁年纪,一件青布长袍早洗得褪成了蓝灰带白。只听他两…2.0第二回 江南七怪 颜烈跨出房门,过道中一个中年士人拖着鞋皮,踢跶踢跶的直响,一路打着哈…3.0第三回 黄沙莽莽 寺里僧众见焦木圆寂,尽皆悲哭。有的便为伤者包扎伤处,抬入客舍。 忽…4.0第四回 黑风双煞 完颜洪熙笑道:”好,再打他个痛快。”蒙古兵前哨报来:”王罕亲自前来迎…5.0第五回 弯弓射雕 一行人下得山来,走不多时,忽听前面猛兽大吼声一阵阵传来。韩宝驹一提缰…
生成list of list格式,注意方法,后面要用到
import jieba
chapter['cut'] = chapter.txt.apply(jieba.lcut)
chapter.head()
txtcutchap1.0第一回 风雪惊变 那说话人五十来岁年纪,一件青布长袍早洗得褪成了蓝灰带白。只听他两…[第一回, , 风雪, 惊变, , , , , , , 那, 说话, 人, 五…2.0第二回 江南七怪 颜烈跨出房门,过道中一个中年士人拖着鞋皮,踢跶踢跶的直响,一路打着哈…[第二回, , 江南七怪, , , , , 颜烈, 跨出, 房门, ,, 过道, …3.0第三回 黄沙莽莽 寺里僧众见焦木圆寂,尽皆悲哭。有的便为伤者包扎伤处,抬入客舍。 忽…[第三回, , 黄沙, 莽莽, , , , , 寺里, 僧众, 见, 焦木, 圆寂…4.0第四回 黑风双煞 完颜洪熙笑道:”好,再打他个痛快。”蒙古兵前哨报来:”王罕亲自前来迎…[第四回, , 黑风双, 煞, , , , , 完颜洪熙, 笑, 道, :, “,…5.0第五回 弯弓射雕 一行人下得山来,走不多时,忽听前面猛兽大吼声一阵阵传来。韩宝驹一提缰…[第五回, , 弯弓, 射雕, , , , , 一行, 人下, 得, 山来, ,,…
from gensim.models.word2vec import Word2Vec
n_dim = 300
w2vmodel = Word2Vec(size = n_dim, min_count = 10)
w2vmodel.build_vocab(chapter.cut)
w2vmodel
<gensim.models.word2vec.word2vec at 0x230bb928da0>
</gensim.models.word2vec.word2vec>
word2vecmodel.train(
sentences : iterable of iterables格式,对于特别大量的文本,尽量考虑流式处理
total_examples = None : 句子总数,int,可直接使用model.corpus_count指定
total_words = None : 句中词条总数,int,该参数和total_examples至少要指定一个
epochs = None : 模型迭代次数,需要指定
其他带默认值的参数设定:
start_alpha=None, end_alpha=None, word_count=0, queue_factor=2,
report_delay=1.0, compute_loss=False, callbacks=()
w2vmodel.train(chapter.cut, \
total_examples = w2vmodel.corpus_count, epochs = 10)
(3444321, 6113050)
print(w2vmodel.wv["郭靖"].shape)
w2vmodel.wv["郭靖"]
(300,)
array([-5.71486771e-01, -6.11459553e-01, 9.88356650e-01, -2.19969201e+00,
-6.24286681e-02, -2.08215073e-01, -4.94846284e-01, 4.11184639e-01,
3.51217866e-01, -7.16320872e-01, 2.41676435e-01, -5.17797768e-01,
......
-5.74352980e-01, 3.34270656e-01, -8.82370621e-02, -2.53521979e-01,
6.62185490e-01, -1.17333210e+00, -5.62149405e-01, -1.21558267e-04,
-1.54235452e-01, 4.67433631e-01, -3.35694969e-01, -1.63811371e-01],
dtype=float32)
w2v模型的保存和复用:
w2vmodel.save(存盘路径及文件名称)
w2vmodel.load(存盘路径及文件名称)
w2vmodel.wv.most_similar(词条)
w2vmodel.wv.most_similar("郭靖",topn = 20)
[('黄蓉', 0.932035505771637),
('欧阳克', 0.8728183507919312),
('穆念慈', 0.7740538120269775),
('梅超风', 0.7715764045715332),
('李萍', 0.7549037337303162),
('完颜康', 0.7546292543411255),
('黄药师', 0.7424267530441284),
('陆冠英', 0.7395749688148499),
('杨康', 0.7385720014572144),
('鲁有脚', 0.7347890138626099),
('周伯通', 0.7241591811180115),
('裘千仞', 0.722597599029541),
('欧阳锋', 0.7211623787879944),
('华筝', 0.7194427847862244),
('洪七公', 0.7096649408340454),
('程瑶迦', 0.7055790424346924),
('穆易', 0.7018767595291138),
('那公子', 0.6987137198448181),
('那道人', 0.6943396329879761),
('一灯', 0.6929605007171631)]
w2vmodel.wv.most_similar(positive=['郭靖', '小红马'], \
negative=['黄药师'], topn = 5)
[('奔', 0.8444687128067017),
('过去', 0.7988641858100891),
('晕', 0.7967531681060791),
('刚', 0.7961419224739075),
('几步', 0.7911766767501831)]
print(w2vmodel.wv.similarity("郭靖", "黄蓉"))
print(w2vmodel.wv.similarity("郭靖", "杨康"))
print(w2vmodel.wv.similarity("郭靖", "杨铁心"))
0.93203545
0.73857194
0.6454911
w2vmodel.wv.doesnt_match("小红马 黄药师 鲁有脚".split())
'小红马'
1.2文档相似度
sklearn.metrics.pairwise.pairwise_distances(
X : 用于计算距离的数组
[n_samples_a, n_samples_a] if metric == 'precomputed'
[n_samples_a, n_features] otherwise
Y = None : 用于计算距离的第二数组,当metric != ‘precomputed’时可用
metric = ‘euclidean’ : 空间距离计算方式
scikit-learn原生支持 : ['cityblock', 'cosine', 'euclidean',
'l1', 'l2', 'manhattan'],可直接使用稀疏矩阵格式
来自scipy.spatial.distance : ['braycurtis', 'canberra',
'chebyshev', 'correlation', 'dice', 'hamming', 'jaccard',
'kulsinski', 'mahalanobis', 'matching', 'minkowski',
'rogerstanimoto', 'russellrao', 'seuclidean', 'sokalmichener',
'sokalsneath', 'sqeuclidean', 'yule'] 不支持稀疏矩阵格式
n_jobs = 1 : 用于计算的线程数,为-1时,所有CPU内核都用于计算
cleanchap = [ " ".join(m_cut(w)) for w in chapter.txt.iloc[:5]]
from sklearn.feature_extraction.text import CountVectorizer
countvec = CountVectorizer()
resmtx = countvec.fit_transform(cleanchap)
resmtx
<5x11623 sparse matrix of type '<class 'numpy.int64'>'
with 16884 stored elements in Compressed Sparse Row format>
</5x11623>
from sklearn.metrics.pairwise import pairwise_distances
pairwise_distances(resmtx, metric = 'cosine')
array([[0. , 0.63104216, 0.77665559, 0.78745025, 0.82985512],
[0.63104216, 0. , 0.62572437, 0.61666388, 0.73192845],
[0.77665559, 0.62572437, 0. , 0.51645443, 0.5299046 ],
[0.78745025, 0.61666388, 0.51645443, 0. , 0.42108002],
[0.82985512, 0.73192845, 0.5299046 , 0.42108002, 0. ]])
pairwise_distances(resmtx)
array([[ 0. , 290.85391522, 312.60678176, 315.54872841,
311.46267834],
[290.85391522, 0. , 266.95130642, 265.77622166,
277.24898557],
[312.60678176, 266.95130642, 0. , 233.9615353 ,
226.09290126],
[315.54872841, 265.77622166, 233.9615353 , 0. ,
202.57344347],
[311.46267834, 277.24898557, 226.09290126, 202.57344347,
0. ]])
from sklearn.feature_extraction.text import TfidfTransformer
txtlist = [ " ".join(m_cut(w)) for w in chapter.txt.iloc[:5]]
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(txtlist)
transformer = TfidfTransformer()
tfidf = transformer.fit_transform(X)
tfidf
pairwise_distances(tfidf[:5], metric = 'cosine')
array([[0. , 0.69112864, 0.84741572, 0.85725434, 0.89178365],
[0.69112864, 0. , 0.74381846, 0.70586805, 0.81759092],
[0.84741572, 0.74381846, 0. , 0.60083695, 0.63539482],
[0.85725434, 0.70586805, 0.60083695, 0. , 0.54123168],
[0.89178365, 0.81759092, 0.63539482, 0.54123168, 0. ]])
主要是用于基于LDA计算余弦相似度
需要使用的信息:
拟合完毕的lda模型
按照拟合模型时矩阵种类转换的需检索文本
需检索的文本
建模时使用的字典
from gensim import similarities
simmtx = similarities.MatrixSimilarity(corpus)
simmtx
<gensim.similarities.docsim.matrixsimilarity at 0x230bb8ec550>
</gensim.similarities.docsim.matrixsimilarity>
检索和第1章内容最相似(所属主题相同)的章节
simmtx = similarities.MatrixSimilarity(corpus)
simmtx
<gensim.similarities.docsim.matrixsimilarity at 0x230bb8ec438>
</gensim.similarities.docsim.matrixsimilarity>
simmtx.index[:2]
array([[0.00370857, 0.11125696, 0.00370857, ..., 0. , 0. ,
0. ],
[0. , 0.15784042, 0. , ..., 0. , 0. ,
0. ]], dtype=float32)
query = chapter.txt[1]
query_bow = dictionary.doc2bow(m_cut(query))
lda_vec = ldamodel[query_bow]
sims = simmtx[lda_vec]
sims = sorted(enumerate(sims), key=lambda item: -item[1])
sims
[(38, 0.011200049),
(1, 0.009635941),
(26, 0.0077462136),
......
(20, 0.0016734296),
(19, 0.0012708347),
(13, 0.0012344222)]
1.2.2 doc2vec(应多使用词袋模型的方式)
doc2vec建议多大量文本时候使用
word2vec用来计算词条相似度非常合适。
较短的文档如果希望计算文本相似度,可以将各自内部的word2vec向量分别进行平均,用平均后的向量作为文本向量,从而用于计算相似度。
但是对于长文档,这种平均的方式显然过于粗糙。
doc2vec是word2vec的拓展,它可以直接获得sentences/paragraphs/documents的向量表达,从而可以进一步通过计算距离来得到sentences/paragraphs/documents之间的相似性。
模型概况
分析目的:获得文档的一个固定长度的向量表达。
数据:多个文档,以及它们的标签,一般可以用标题作为标签。
影响模型准确率的因素:语料的大小,文档的数量,越多越高;文档的相似性,越相似越好。
import jieba
import gensim
from gensim.models import doc2vec
def m_doc(doclist):
reslist = []
for i, doc in enumerate(doclist):
reslist.append(doc2vec.TaggedDocument(jieba.lcut(doc), [i]))
return reslist
corp = m_doc(chapter.txt)
corp[:2]
[TaggedDocument(words=['第一回', ' ', '风雪', '惊变', '那', '说话', '人', '五十', '来', '岁', '年纪', ',', '一件', '青布', '长袍', '早洗', '得', '褪成', '了', '蓝灰', '带白', '。', '只',...... '听', '他', '两片', '梨花', '木, '过', '了', '一会', ',', '颜烈', '道', ':', '“', '娘子', '请', '自', '宽', '便', ',', '小人', '出去', '买', '了', '物品', '就', '回', '。', '”', '包惜弱', '点', '了', '点头', ',', '道', ':', '“', '相公', '可别', '太多', '花费', '了', '。', '”', '颜烈', '微笑', '道', ':', '“', '就', '可惜', '娘子', '在', '服丧', ',', '不能', '戴用', '珠宝', ',', '要', '多花钱', '也', '花', '不了', '。', '”', '], tags=[0]),
TaggedDocument(words=['第二回', ' ', '江南七怪', '颜烈', '跨出', '房门', ',', '过道', '中', '一个', ......'中年', '士人', '拖', '着', '鞋', '皮', ',', '踢', '跶', '踢', '跶', '的', '直响', ',', '一路打', '着', '哈欠', '迎面', '过来', ',', '那', '士人', '似笑非笑', ',', '挤眉弄眼', ',', ''没', '洗脸', '了', ',', '拿', '着', '一', '柄', '破烂', '的', '油纸', '黑扇', ',', '边摇边行', '。段天德', '吓', '得', '魂不附体', ',', '哪里', '还敢', '停留', ',', '拉', '了', '李萍', ',', '急奔', '而出', '。', '李萍大', '叫', ':', '“', '救命', '啊', ',', '我', '不', '去', ',', '救命', '啊', '!', '”', '终于', '声音', '越来越', '远', '。], tags=[1])]
d2vmodel = gensim.models.Doc2Vec(vector_size = 300,
window = 20, min_count = 5)
%time d2vmodel.build_vocab(corp)
Wall time: 1.88 s
d2vmodel.wv.vocab
{' ': <gensim.models.keyedvectors.vocab at 0x230b88bef98>,
'风雪': <gensim.models.keyedvectors.vocab at 0x230b88bedd8>,
'那': <gensim.models.keyedvectors.vocab at 0x230c4fea780>,
'说话': <gensim.models.keyedvectors.vocab at 0x230c4fea828>,
......
'曲三': <gensim.models.keyedvectors.vocab at 0x230c7f9f470>,
'掘': <gensim.models.keyedvectors.vocab at 0x230c7fb49e8>,
'最后': <gensim.models.keyedvectors.vocab at 0x230c7fb4a20>,
'一具': <gensim.models.keyedvectors.vocab at 0x230c7fb4a58>,
...}
</gensim.models.keyedvectors.vocab></gensim.models.keyedvectors.vocab></gensim.models.keyedvectors.vocab></gensim.models.keyedvectors.vocab></gensim.models.keyedvectors.vocab></gensim.models.keyedvectors.vocab></gensim.models.keyedvectors.vocab></gensim.models.keyedvectors.vocab>
newvec = d2vmodel.infer_vector(jieba.lcut(chapter.txt[1]))
d2vmodel.docvecs.most_similar([newvec], topn = 10)
[(33, 0.17437607049942017),
(36, 0.10029015690088272),
(22, 0.07945042848587036),
(18, 0.04506886377930641),
(14, 0.03940583020448685),
(23, 0.035881608724594116),
(6, 0.03350480645895004),
(31, 0.03314536064863205),
(16, 0.028236132115125656),
(13, 0.022862425073981285)]
1.3文档聚类
在得到文档相似度的计算结果后,文档聚类问题在本质上已经和普通的聚类分析没有区别。
注意:最常用的Kmeans使用的是平方欧氏距离,这在文本聚类中很可能无法得到最佳结果。
算法的速度和效果同样重要。
chapter.index = [raw.txt[raw.chap == i].iloc[0] for i in chapter.index]
chapter.head()
txtcut第一回 风雪惊变第一回 风雪惊变 那说话人五十来岁年纪,一件青布长袍早洗得褪成了蓝灰带白。只听他两…[第一回, , 风雪, 惊变, , , , , , , 那, 说话, 人, 五…第二回 江南七怪第二回 江南七怪 颜烈跨出房门,过道中一个中年士人拖着鞋皮,踢跶踢跶的直响,一路打着哈…[第二回, , 江南七怪, , , , , 颜烈, 跨出, 房门, ,, 过道, …第三回 黄沙莽莽第三回 黄沙莽莽 寺里僧众见焦木圆寂,尽皆悲哭。有的便为伤者包扎伤处,抬入客舍。 忽…[第三回, , 黄沙, 莽莽, , , , , 寺里, 僧众, 见, 焦木, 圆寂…第四回 黑风双煞第四回 黑风双煞 完颜洪熙笑道:”好,再打他个痛快。”蒙古兵前哨报来:”王罕亲自前来迎…[第四回, , 黑风双, 煞, , , , , 完颜洪熙, 笑, 道, :, “,…第五回 弯弓射雕第五回 弯弓射雕 一行人下得山来,走不多时,忽听前面猛兽大吼声一阵阵传来。韩宝驹一提缰…[第五回, , 弯弓, 射雕, , , , , 一行, 人下, 得, 山来, ,,…
import jieba
cuttxt = lambda x: " ".join(m_cut(x))
cleanchap = chapter.txt.apply(cuttxt)
cleanchap[:2]
第一回 风雪惊变 第一回 风雪 惊变 说话 五十 年纪 一件 青布 长袍 早洗 褪成 蓝灰 带白 两片 梨花 ...
第二回 江南七怪 第二回 江南七怪 颜烈 跨出 房门 过道 一个 中年 士人 直响 一路打 哈欠 迎面 士人 ...
Name: txt, dtype: object
from sklearn.feature_extraction.text import TfidfTransformer
vectorizer = CountVectorizer()
wordmtx = vectorizer.fit_transform(cleanchap)
transformer = TfidfTransformer()
tfidf = transformer.fit_transform(wordmtx)
tfidf
<40x43931 sparse matrix of type '<class 'numpy.float64'>'
with 129387 stored elements in Compressed Sparse Row format>
</40x43931>
from sklearn.cluster import KMeans
clf = KMeans(n_clusters = 5)
s = clf.fit(tfidf)
print(s)
clf.cluster_centers_
KMeans(n_clusters=5)
array([[0. , 0. , 0. , ..., 0. , 0.00281383,
0. ],
[0.00048249, 0. , 0. , ..., 0.00098597, 0. ,
0.00048249],
[0. , 0. , 0. , ..., 0. , 0. ,
0. ],
[0. , 0. , 0. , ..., 0. , 0. ,
0. ],
[0. , 0.00080214, 0.00080214, ..., 0. , 0. ,
0. ]])
clf.cluster_centers_.shape
(5, 43931)
clf.labels_
array([2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 1, 4, 1, 1, 1, 1, 1, 1, 1,
1, 4, 1, 1, 1, 1, 0, 0, 0, 1, 4, 1, 1, 1, 1, 1, 1, 1])
chapter['clsres'] = clf.labels_
chapter.head()
txtcutclsres第一回 风雪惊变第一回 风雪惊变 那说话人五十来岁年纪,一件青布长袍早洗得褪成了蓝灰带白。只听他两…[第一回, , 风雪, 惊变, , , , , , , 那, 说话, 人, 五…2第二回 江南七怪第二回 江南七怪 颜烈跨出房门,过道中一个中年士人拖着鞋皮,踢跶踢跶的直响,一路打着哈…[第二回, , 江南七怪, , , , , 颜烈, 跨出, 房门, ,, 过道, …2第三回 黄沙莽莽第三回 黄沙莽莽 寺里僧众见焦木圆寂,尽皆悲哭。有的便为伤者包扎伤处,抬入客舍。 忽…[第三回, , 黄沙, 莽莽, , , , , 寺里, 僧众, 见, 焦木, 圆寂…3第四回 黑风双煞第四回 黑风双煞 完颜洪熙笑道:”好,再打他个痛快。”蒙古兵前哨报来:”王罕亲自前来迎…[第四回, , 黑风双, 煞, , , , , 完颜洪熙, 笑, 道, :, “,…3第五回 弯弓射雕第五回 弯弓射雕 一行人下得山来,走不多时,忽听前面猛兽大吼声一阵阵传来。韩宝驹一提缰…[第五回, , 弯弓, 射雕, , , , , 一行, 人下, 得, 山来, ,,…3
chapter.sort_values('clsres').clsres
第三十回 一灯大师 0
第三十一回 鸳鸯锦帕 0
第二十九回 黑沼隐女 0
......
第十三回 五湖废人 4
第九回 铁枪破犁 4
Name: clsres, dtype: int32
chapgrp = chapter.groupby('clsres')
chapcls = chapgrp.agg(sum)
cuttxt = lambda x: " ".join(m_cut(x))
chapclsres = chapcls.txt.apply(cuttxt)
chapclsres
clsres
0 第二十九回 黑沼 隐女 郭靖 呼叫 召唤 小红马 地下 转眼之间 双雕 飞出 老远 雌雄 双...
1 第十四回 桃花 岛主 五男一女 走进 厅来 却是 江南 六怪 北南 故乡 日近 这天 太湖 ...
2 第一回 风雪 惊变 说话 五十 年纪 一件 青布 长袍 早洗 褪成 蓝灰 带白 两片 梨花 ...
3 第三回 黄沙 莽莽 寺里 僧众 焦木 圆寂 悲哭 伤者 包扎 伤处 抬入 客舍 巨钟 缸内 ...
4 第七回 比武招亲 江南 六怪 郭靖 晓行夜宿 东南 进发 非止 一日 大漠 草原 这天 张家...
Name: txt, dtype: object
import jieba.analyse as ana
ana.set_stop_words('停用词.txt')
for item in chapclsres:
print(ana.extract_tags(item, topK = 10))
['黄蓉', '郭靖', '一灯', '黄蓉道', '那书生', '渔人', '一灯大师', '农夫', '段皇爷', '郭靖道']
['郭靖', '黄蓉', '欧阳锋', '黄药师', '洪七公', '周伯通', '裘千仞', '武功', '郭靖道', '欧阳克']
['丘处机', '杨铁心', '包惜弱', '郭啸天', '段天德', '颜烈', '完颜洪烈', '柯镇恶', '金兵', '道长']
['郭靖', '铁木真', '柯镇恶', '韩小莹', '梅超风', '哲别', '朱聪', '韩宝驹', '拖雷', '华筝']
['郭靖', '黄蓉', '洪七公', '完颜康', '师父', '彭连虎', '陆冠英', '梁子翁', '欧阳克', '穆念慈']
在计算词条相似度时进行停用词清理,然后再进行拟合,思考为什么会有这样的结果出现。
在基于词袋模型,使用原始词频计算文本余弦相似度时,比较清理停用词前后的结果。
import jieba
import pandas as pd
tmpdf = pd.read_table('停用词.txt',names = ['w'], encoding = 'utf-8')
chapter['cut'] = chapter.txt.apply(jieba.lcut)
chapter['cut'] =[ w for w in chapter['cut'] if w not in list(tmpdf.w) ]
chapter.head()
Building prefix dict from the default dictionary ...
Loading model from cache C:\Users\A\AppData\Local\Temp\jieba.cache
Loading model cost 0.557 seconds.
Prefix dict has been built successfully.
txtcutchap1.0第一回 风雪惊变 那说话人五十来岁年纪,一件青布长袍早洗得褪成了蓝灰带白。只听他两…[第一回, , 风雪, 惊变, , , , , , , 那, 说话, 人, 五…2.0第二回 江南七怪 颜烈跨出房门,过道中一个中年士人拖着鞋皮,踢跶踢跶的直响,一路打着哈…[第二回, , 江南七怪, , , , , 颜烈, 跨出, 房门, ,, 过道, …3.0第三回 黄沙莽莽 寺里僧众见焦木圆寂,尽皆悲哭。有的便为伤者包扎伤处,抬入客舍。 忽…[第三回, , 黄沙, 莽莽, , , , , 寺里, 僧众, 见, 焦木, 圆寂…4.0第四回 黑风双煞 完颜洪熙笑道:”好,再打他个痛快。”蒙古兵前哨报来:”王罕亲自前来迎…[第四回, , 黑风双, 煞, , , , , 完颜洪熙, 笑, 道, :, “,…5.0第五回 弯弓射雕 一行人下得山来,走不多时,忽听前面猛兽大吼声一阵阵传来。韩宝驹一提缰…[第五回, , 弯弓, 射雕, , , , , 一行, 人下, 得, 山来, ,,…
from gensim.models.word2vec import Word2Vec
n_dim = 300
w2vmodel = Word2Vec(size = n_dim, min_count = 10)
w2vmodel.build_vocab(chapter.cut)
w2vmodel.train(chapter.cut, \
total_examples = w2vmodel.corpus_count, epochs = 10)
print(w2vmodel.wv["郭靖"].shape)
w2vmodel.wv["郭靖"]
(300,)
array([ 0.34924605, 0.21265522, 0.5632632 , 0.3580753 , 0.17115285,
0.48449898, 0.11169011, 0.33496168, 0.8114401 , 0.6040344 ,
0.27803087, -0.56468904, -0.05460463, -0.11949269, -0.08181898,
......
0.2831581 , 0.60918677, -0.17329499, 0.11961225, -0.30500183,
-0.31079102, -0.64060545, 0.03041249, 0.66229236, 0.88437986],
dtype=float32)
import jieba
import pandas as pd
tmpdf = pd.read_table('停用词.txt',names = ['w'], encoding = 'utf-8')
chapter['cut'].iloc[:5]= [ " ".join(m_cut(w)) for w in chapter.txt.iloc[:5] ]
chapter['cut'].iloc[:5]=[ w for w in chapter['cut'].iloc[:5] if w not in list(tmpdf.w) ]
from sklearn.feature_extraction.text import CountVectorizer
countvec = CountVectorizer()
resmtx = countvec.fit_transform(chapter['cut'].iloc[:5])
resmtx
<5x11623 sparse matrix of type '<class 'numpy.int64'>'
with 16884 stored elements in Compressed Sparse Row format>
</5x11623>
from sklearn.metrics.pairwise import pairwise_distances
pairwise_distances(resmtx, metric = 'cosine')
array([[0. , 0.63104216, 0.77665559, 0.78745025, 0.82985512],
[0.63104216, 0. , 0.62572437, 0.61666388, 0.73192845],
[0.77665559, 0.62572437, 0. , 0.51645443, 0.5299046 ],
[0.78745025, 0.61666388, 0.51645443, 0. , 0.42108002],
[0.82985512, 0.73192845, 0.5299046 , 0.42108002, 0. ]])
朴素贝叶斯算法(优先考虑使用)
2.1 sklearn实现
sklearn是标准的数据挖掘建模工具包,在语料转换为d2m矩阵结构之后,就可以使用所有标准的DM建模手段在sklearn中进行分析。
在sklearn中也实现了朴素贝叶斯算法,使用方式上也和其他模型非常相似。
raw12 = raw[raw.chap.isin([1,2])]
raw12ana = raw12.iloc[list(raw12.txt.apply(len) > 50), :]
raw12ana.reset_index(drop = True, inplace = True)
print(len(raw12ana))
raw12ana.head()
376
txtchap0那说话人五十来岁年纪,一件青布长袍早洗得褪成了蓝灰带白。只听他两片梨花木板碰了几下,左手…1.01那说话人将木板敲了几下,说道:”这首七言诗,说的是兵火过后,原来的家家户户,都变成了断墙…1.02″叶老汉和叶妈妈吓得呆了,扑将上去,搂住了儿子的尸体,放声大哭。那长官提起狼牙棒,一棒一…1.03″可是那金兵占了我大宋天下,杀人放火,奸淫掳掠,无恶不作,却又不见他遭到什么报应。只怪我…1.04村民中走出一个二十来岁的大汉,说道:”张先生,你可是从北方来吗?”说的是北方口音。张十五…1.0
import jieba
cuttxt = lambda x: " ".join(jieba.lcut(x))
raw12ana["cleantxt"] = raw12ana.txt.apply(cuttxt)
raw12ana.head()
<ipython-input-12-b42f436ca4f7>:3: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
raw12ana["cleantxt"] = raw12ana.txt.apply(cuttxt)
</ipython-input-12-b42f436ca4f7>
txtchapcleantxt0那说话人五十来岁年纪,一件青布长袍早洗得褪成了蓝灰带白。只听他两片梨花木板碰了几下,左手…1.0那 说话 人 五十 来 岁 年纪 , 一件 青布 长袍 早洗 得 褪成 了 蓝灰 带…1那说话人将木板敲了几下,说道:”这首七言诗,说的是兵火过后,原来的家家户户,都变成了断墙…1.0那 说话 人 将 木板 敲 了 几下 , 说道 : ” 这首 七言诗 , 说 的 是…2″叶老汉和叶妈妈吓得呆了,扑将上去,搂住了儿子的尸体,放声大哭。那长官提起狼牙棒,一棒一…1.0″ 叶老汉 和 叶 妈妈 吓 得 呆 了 , 扑 将 上去 , 搂住 了 儿子 的 …3″可是那金兵占了我大宋天下,杀人放火,奸淫掳掠,无恶不作,却又不见他遭到什么报应。只怪我…1.0″ 可是 那金兵 占 了 我 大宋 天下 , 杀人放火 , 奸淫掳掠 , 无恶不作 …4村民中走出一个二十来岁的大汉,说道:”张先生,你可是从北方来吗?”说的是北方口音。张十五…1.0村民 中 走出 一个二十 来 岁 的 大汉 , 说道 : ” 张 先生 , 你 可是…
from sklearn.feature_extraction.text import CountVectorizer
countvec = CountVectorizer()
wordmtx = countvec.fit_transform(raw12ana.cleantxt)
wordmtx
<376x6724 sparse matrix of type '<class 'numpy.int64'>'
with 13642 stored elements in Compressed Sparse Row format>
</376x6724>
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(wordmtx, raw12ana.chap,
test_size = 0.3, random_state = 111)
from sklearn import naive_bayes
NBmodel = naive_bayes.MultinomialNB()
NBmodel.fit(x_train, y_train)
x_test
<113x6724 sparse matrix of type '<class 'numpy.int64'>'
with 4127 stored elements in Compressed Sparse Row format>
</113x6724>
NBmodel.predict(x_test)
array([2., 2., 1., 2., 1., 2., 1., 1., 2., 1., 2., 1., 2., 2., 1., 2., 1.,
2., 1., 1., 2., 2., 1., 1., 2., 1., 2., 1., 1., 2., 1., 2., 1., 1.,
2., 1., 1., 1., 1., 1., 1., 2., 1., 1., 2., 2., 2., 1., 1., 1., 2.,
1., 1., 1., 2., 1., 2., 1., 2., 2., 2., 2., 1., 1., 1., 1., 1., 1.,
1., 1., 2., 2., 1., 1., 1., 1., 1., 2., 1., 2., 1., 1., 2., 2., 2.,
1., 1., 1., 2., 1., 1., 2., 1., 1., 1., 2., 2., 2., 2., 2., 1., 1.,
2., 1., 1., 2., 2., 2., 2., 1., 1., 2., 2.])
print('训练集:', NBmodel.score(x_train, y_train),
',验证集:', NBmodel.score(x_test, y_test))
训练集: 1.0 ,验证集: 0.9557522123893806
from sklearn.metrics import classification_report
print(classification_report(y_test, NBmodel.predict(x_test)))
precision recall f1-score support
1.0 0.94 0.98 0.96 61
2.0 0.98 0.92 0.95 52
accuracy 0.96 113
macro avg 0.96 0.95 0.96 113
weighted avg 0.96 0.96 0.96 113
将需要预测的文本转换为和建模时格式完全对应的d2m矩阵格式,随后即可进行预测。
countvec.vocabulary_
{'说话': 5703,
'五十': 765,
'年纪': 2855,
......
'握住': 3565,
'猎叉': 4588,
'随即': 6438,
...}
string = "杨铁心和包惜弱收养穆念慈"
words = " ".join(jieba.lcut(string))
words_vecs = countvec.transform([words])
words_vecs
<1x6724 sparse matrix of type '<class 'numpy.int64'>'
with 2 stored elements in Compressed Sparse Row format>
</1x6724>
NBmodel.predict(words_vecs)
array([1.])
from sklearn.linear_model import LogisticRegression
logitmodel = LogisticRegression()
logitmodel.fit(x_train, y_train)
print(classification_report(y_test, logitmodel.predict(x_test)))
precision recall f1-score support
1.0 0.94 0.98 0.96 61
2.0 0.98 0.92 0.95 52
accuracy 0.96 113
macro avg 0.96 0.95 0.96 113
weighted avg 0.96 0.96 0.96 113
2.2 NLTK实现
NLTK中内置了朴素贝叶斯算法,可直接实现文档分类。
数据集中语料的格式
用于训练的语料必须是分词完毕的字典形式,词条为键名,键值则可以是数值、字符、或者T/F
{‘张三’ : True, ‘李四’ : True, ‘王五’ : False}
{‘张三’ : 1, ‘李四’ : 1, ‘王五’ : 0}
{‘张三’ : ‘有’, ‘李四’ : ‘有’, ‘王五’ : ‘无’}
训练用数据集为list of list格式,每个成员为list[语料字典, 结果变量]
[{‘张三’ : 1, ‘李四’ : 1, ‘王五’ : 0}, ‘合格’],
[{‘张三’ : 0, ‘李四’ : 1, ‘王五’ : 0}, ‘不合格’]
考虑到过拟合问题,此处需要先拆分好训练集和测试集
model = NaiveBayesClassifier.train(training_data)
import nltk
from nltk import FreqDist
fdist1 = FreqDist(m_cut(chapter.txt[1]))
fdist2 = FreqDist(m_cut(chapter.txt[2]))
fdist3 = FreqDist(m_cut(chapter.txt[3]))
fdist1
FreqDist({'第一回': 1,
'风雪': 3,
'惊变': 1,
'说话': 9,
......
'一具': 1,
'黑色': 1,
'盘形': 1,
...})
from nltk.classify import NaiveBayesClassifier
training_data = [ [fdist1, 'chap1'], [fdist2, 'chap2'], [fdist3, 'chap3'] ]
NLTKmodel = NaiveBayesClassifier.train(training_data)
print(NLTKmodel.classify(FreqDist(m_cut("杨铁心收养穆念慈"))))
print(NLTKmodel.classify(FreqDist(m_cut("钱塘江 日日夜夜 包惜弱 颜烈 使出杨家枪"))))
chap3
chap2
nltk.classify.accuracy(NLTKmodel, training_data)
1.0
NLTKmodel.show_most_informative_features(5)
Most Informative Features
飞将 = None chap3 : chap2 = 1.0 : 1.0
几茎 = None chap2 : chap1 = 1.0 : 1.0
对射雕的前两个章节提取关键字,然后使用关键字而不是原始文本进行文档分类,比较这样两种方式的分类效果有何变化。
减少用于训练的样本量,考察使用朴素贝叶斯算法或者其他标准分类算法时,模型效果的变化趋势。
自行实现基于NLTK的按段落为单位进行章节分类的程序。
import jieba
import jieba.analyse
import jieba
chapter['cut'] = chapter.txt.apply(jieba.lcut)
chapter.head()
Building prefix dict from the default dictionary ...
Loading model from cache C:\Users\A\AppData\Local\Temp\jieba.cache
Loading model cost 0.555 seconds.
Prefix dict has been built successfully.
txtcutchap1.0第一回 风雪惊变 那说话人五十来岁年纪,一件青布长袍早洗得褪成了蓝灰带白。只听他两…[第一回, , 风雪, 惊变, , , , , , , 那, 说话, 人, 五…2.0第二回 江南七怪 颜烈跨出房门,过道中一个中年士人拖着鞋皮,踢跶踢跶的直响,一路打着哈…[第二回, , 江南七怪, , , , , 颜烈, 跨出, 房门, ,, 过道, …3.0第三回 黄沙莽莽 寺里僧众见焦木圆寂,尽皆悲哭。有的便为伤者包扎伤处,抬入客舍。 忽…[第三回, , 黄沙, 莽莽, , , , , 寺里, 僧众, 见, 焦木, 圆寂…4.0第四回 黑风双煞 完颜洪熙笑道:”好,再打他个痛快。”蒙古兵前哨报来:”王罕亲自前来迎…[第四回, , 黑风双, 煞, , , , , 完颜洪熙, 笑, 道, :, “,…5.0第五回 弯弓射雕 一行人下得山来,走不多时,忽听前面猛兽大吼声一阵阵传来。韩宝驹一提缰…[第五回, , 弯弓, 射雕, , , , , 一行, 人下, 得, 山来, ,,…
key1=jieba.analyse.extract_tags(chapter.txt[1])
key2=jieba.analyse.extract_tags(chapter.txt[2])
key=key1+key2
key
['杨铁心',
'包惜弱',
'郭啸天',
'颜烈',
'丘处机',
'杨二人',
......
'金兵',
'武功',
'道长',
'南希仁',
'全金发',
'李萍']
from sklearn.feature_extraction.text import CountVectorizer
countvec = CountVectorizer()
wordmtx = countvec.fit_transform(key)
wordmtx
<40x34 sparse matrix of type '<class 'numpy.int64'>'
with 40 stored elements in Compressed Sparse Row format>
</40x34>
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(wordmtx, raw12ana.chap[:40],
test_size = 0.3, random_state = 1)
from sklearn import naive_bayes
NBmodel = naive_bayes.MultinomialNB()
NBmodel.fit(x_train, y_train)
x_test
print('训练集:', NBmodel.score(x_train, y_train),
',验证集:', NBmodel.score(x_test, y_test))
训练集: 1.0 ,验证集: 1.0
from sklearn.feature_extraction.text import CountVectorizer
countvec = CountVectorizer()
wordmtx = countvec.fit_transform(raw12ana.cleantxt)
wordmtx
<376x6724 sparse matrix of type '<class 'numpy.int64'>'
with 13642 stored elements in Compressed Sparse Row format>
</376x6724>
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(wordmtx, raw12ana.chap,
test_size = 0.8, random_state = 111)
from sklearn import naive_bayes
NBmodel = naive_bayes.MultinomialNB()
NBmodel.fit(x_train, y_train)
from sklearn.metrics import classification_report
print(classification_report(y_test, NBmodel.predict(x_test)))
precision recall f1-score support
1.0 0.84 0.96 0.89 156
2.0 0.94 0.81 0.87 145
accuracy 0.88 301
macro avg 0.89 0.88 0.88 301
weighted avg 0.89 0.88 0.88 301
可见训练集过少会直接影响训练的效果
情感分析概述
3.1 基于词袋模型的分析
数据概况:
取自购物网站的正向、负向评价各约1万条。
import pandas as pd
dfpos = pd.read_excel("购物评论.xlsx", sheet_name = "正向", header=None)
dfpos['y'] = 1
dfneg = pd.read_excel("购物评论.xlsx", sheet_name = "负向", header=None)
dfneg['y'] = 0
df0 = dfpos.append(dfneg, ignore_index = True)
df0.head()
0y0感觉用这个手机下载MP3听很方便,用T-Flash卡装上歌,就可以当一个小MP3用了,很不错…11外观美观,速度也不错。上面一排触摸键挺实用。应该对得起这个价格。当然再降点大家肯定也不反对。…12我刚拿到书,也没有仔细阅读,就是粗粗的翻了点,觉得还行。里面是蓝黑两种颜色的,有些单词的下面…13对于二胡曲的精选,应该出版一个系列套装,可分别出售,单独购买。精品二胡曲是有年代和阶段性的,…14用了一年半的 e680 终于送小偷了。刚刚买了一台e850,用了三天,说说我自己的感受。1:…1
import jieba
cuttxt = lambda x: " ".join(jieba.lcut(x))
df0["cleantxt"] = df0[0].apply(cuttxt)
df0.tail()
0ycleantxt20577服务员太差,房间很吵,隔音不好,房间味道很重,很一般,不如稀土国际大酒店好,收费有低,还是四…0服务员 太 差 , 房间 很 吵 , 隔音 不好 , 房间 味道 很 重 , 很 一般 , …20578很早我就说等”爱氏晨曦”吃进蒙牛股份后,对蒙牛的质疑就会停止,如今已应验。想知道单是这一笔…0很早 我 就 说 等 ” 爱氏 晨曦 ” 吃进 蒙牛 股份 后 , 对 蒙牛 的 质疑 …205792——10岁是什么意思?我不认为有一本书可以覆盖这样的范围,事实上,我两岁的女儿不能理解这套…02 — — 10 岁 是 什么 意思 ? 我 不 认为 有 一 本书 可以 覆盖 这样 的 …20580刚住过这里,感觉不好,房间味道太大,一股子霉味,房间各种设施都很陈旧,我所预订的大床间,却没…0刚住 过 这里 , 感觉不好 , 房间 味道 太 大 , 一股 子 霉味 , 房间 各种 设…20581一本书200页,综合一下只有3页可看 却要花200页的钱 唉 唉0一 本书 200 页 , 综合 一下 只有 3 页 可 看 却 要 花 200 页 …
from sklearn.feature_extraction.text import CountVectorizer
countvec = CountVectorizer(min_df = 5)
wordmtx = countvec.fit_transform(df0.cleantxt)
wordmtx
<20582x12014 sparse matrix of type '<class 'numpy.int64'>'
with 513919 stored elements in Compressed Sparse Row format>
</20582x12014>
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(
wordmtx, df0.y, test_size=0.3)
x_train[0]
<1x12014 sparse matrix of type '<class 'numpy.int64'>'
with 14 stored elements in Compressed Sparse Row format>
</1x12014>
from sklearn.svm import SVC
clf=SVC(kernel = 'rbf', verbose = True)
clf.fit(x_train, y_train)
clf.score(x_train, y_train)
[LibSVM]
0.9535642396057472
from sklearn.metrics import classification_report
print(classification_report(y_test, clf.predict(x_test)))
precision recall f1-score support
0 0.87 0.90 0.88 3055
1 0.89 0.86 0.88 3120
accuracy 0.88 6175
macro avg 0.88 0.88 0.88 6175
weighted avg 0.88 0.88 0.88 6175
clf.predict(countvec.transform([df0.cleantxt[0]]))[0]
import jieba
def m_pred(string, countvec, model) :
words = " ".join(jieba.lcut(string))
words_vecs = countvec.transform([words])
result = model.predict(words_vecs)
if int(result[0]) == 1:
print(string, ":正向")
else:
print(string, ":负向")
comment = "外观美观,速度也不错。上面一排触摸键挺实用。应该对得起这个价格。当然再降点大家肯定也不反对。风扇噪音也不大。"
m_pred(comment, countvec, clf)
外观美观,速度也不错。上面一排触摸键挺实用。应该对得起这个价格。当然再降点大家肯定也不反对。风扇噪音也不大。 :正向
comment = "作为女儿6.1的礼物。虽然晚到了几天。等拿到的时候,女儿爱不释手,上洗手间也看,告知不好。上周末,告诉我她把火鞋和风鞋拿到学校,好多同学羡慕她。呵呵,我也看了其中的人鸦,只可惜没有看完就在老公的催促下睡了。说了这么多,归纳为一句:这套书买的值。"
m_pred(comment, countvec, clf)
作为女儿6.1的礼物。虽然晚到了几天。等拿到的时候,女儿爱不释手,上洗手间也看,告知不好。上周末,告诉我她把火鞋和风鞋拿到学校,好多同学羡慕她。呵呵,我也看了其中的人鸦,只可惜没有看完就在老公的催促下睡了。说了这么多,归纳为一句:这套书买的值。 :正向
3.2 基于分布式表达的分析(对于短文本来说,效果更优)
和词袋模型相比,分布式表达主要是改变了文本信息的提取方式。
目前主要使用gensim实现相应的算法。
注意:由于矩阵不再是频数值(正负想间),因此不能使用朴素贝叶斯算法来进行拟合。
import pandas as pd
dfpos = pd.read_excel("购物评论.xlsx", sheet_name = "正向", header=None)
dfpos['y'] = 1
dfneg = pd.read_excel("购物评论.xlsx", sheet_name = "负向", header=None)
dfneg['y'] = 0
df0 = dfpos.append(dfneg, ignore_index = True)
df0.head()
0y0感觉用这个手机下载MP3听很方便,用T-Flash卡装上歌,就可以当一个小MP3用了,很不错…11外观美观,速度也不错。上面一排触摸键挺实用。应该对得起这个价格。当然再降点大家肯定也不反对。…12我刚拿到书,也没有仔细阅读,就是粗粗的翻了点,觉得还行。里面是蓝黑两种颜色的,有些单词的下面…13对于二胡曲的精选,应该出版一个系列套装,可分别出售,单独购买。精品二胡曲是有年代和阶段性的,…14用了一年半的 e680 终于送小偷了。刚刚买了一台e850,用了三天,说说我自己的感受。1:…1
import jieba
df0['cut'] = df0[0].apply(jieba.lcut)
df0.head()
0ycut0感觉用这个手机下载MP3听很方便,用T-Flash卡装上歌,就可以当一个小MP3用了,很不错…1[感觉, 用, 这个, 手机, 下载, MP3, 听, 很, 方便, ,, 用, T, -,…1外观美观,速度也不错。上面一排触摸键挺实用。应该对得起这个价格。当然再降点大家肯定也不反对。…1[外观, 美观, ,, 速度, 也, 不错, 。, 上面, 一排, 触摸, 键, 挺, 实用…2我刚拿到书,也没有仔细阅读,就是粗粗的翻了点,觉得还行。里面是蓝黑两种颜色的,有些单词的下面…1[我刚, 拿到, 书, ,, 也, 没有, 仔细阅读, ,, 就是, 粗粗, 的, 翻, 了…3对于二胡曲的精选,应该出版一个系列套装,可分别出售,单独购买。精品二胡曲是有年代和阶段性的,…1[对于, 二胡曲, 的, 精选, ,, 应该, 出版, 一个系列, 套装, ,, 可, 分别…4用了一年半的 e680 终于送小偷了。刚刚买了一台e850,用了三天,说说我自己的感受。1:…1[用, 了, 一年, 半, 的, , e680, , 终于, 送, 小偷, 了, 。, …
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(
df0.cut, df0.y, test_size=0.3)
x_train[:2]
10965 [儿子, 1, 年, 7, 个, 月, ,, 虽然, 好多, 都, 不是, 很, 懂, ,,...
17209 [这家, 酒店, 绝对, 没有, 四星级, ,, 而且, 房间, 的, 隔音, 太, 差, ...
Name: cut, dtype: object
from gensim.models.word2vec import Word2Vec
n_dim = 300
w2vmodel = Word2Vec(vector_size = n_dim, min_count = 10)
w2vmodel.build_vocab(x_train)
%time w2vmodel.train(x_train, \
total_examples = w2vmodel.corpus_count, epochs = 10)
Wall time: 4.67 s
(6346434, 9495160)
w2vmodel.wv.most_similar("不错")
[('好', 0.6664835810661316),
('行', 0.6593450903892517),
('挺不错', 0.658033549785614),
('比较满意', 0.6418668627738953),
('很漂亮', 0.5996091365814209),
('还行', 0.5758983492851257),
('很快', 0.5542255640029907),
('整体', 0.5516241788864136),
('漂亮', 0.5488754510879517),
('说得过去', 0.5477145910263062)]
w2vmodel.wv.most_similar("失望")
[('遗憾', 0.7359662652015686),
('不爽', 0.6579391360282898),
('气愤', 0.647860586643219),
('后悔', 0.6342949271202087),
('不满', 0.6023170351982117),
('生气', 0.5882432460784912),
('上当', 0.5846213698387146),
('难得', 0.5696483254432678),
('糟糕', 0.5675068497657776),
('浅', 0.5560178756713867)]
对购物评论、微博等短文本而言,一般是将所有词向量的平均值作为分类算法的输入值。
pd.DataFrame([w2vmodel.wv[w] for w in df0.cut[0] if w in w2vmodel.wv]).head()
0123456789…2902912922932942952962972982990-0.9113322.487151-0.4453550.959004-0.077999-0.157231-0.5110120.6362100.123468-1.307333…-0.798626-0.1331262.0846860.0841970.662218-0.7118581.7726251.529452-0.640140-0.09114710.046230-0.0357921.241354-1.3543660.447580-0.5604201.2724241.154507-0.583416-0.777637…-1.0289600.141009-0.139010-0.353615-0.9384530.0849640.510275-0.6980840.632293-0.49319720.5882860.292953-0.215384-0.420847-0.803060-0.0338200.0183330.384169-0.659887-0.146808…0.2775451.0462610.7420070.2306530.011729-1.6647410.1186310.510197-0.013587-0.13856630.191487-0.297445-0.385975-1.030350-1.255563-1.2140320.6162300.202745-1.1332470.830488…1.589015-0.153522-0.118775-1.095460-0.661065-1.3192110.029742-0.847319-0.7235971.2763794-0.704394-0.0719390.1009930.326895-0.685714-0.722568-0.2050360.934630-0.2402660.022127…0.595830-0.101508-0.191669-0.558731-0.897231-0.376409-0.159503-0.5682330.4716850.287301
5 rows × 300 columns
def m_avgvec(words, w2vmodel):
return pd.DataFrame([w2vmodel.wv[w]
for w in words if w in w2vmodel.wv]).agg("mean")
%time train_vecs = pd.DataFrame([m_avgvec(s, w2vmodel) for s in x_train])
train_vecs.head()
Wall time: 2min 55s
0123456789…2902912922932942952962972982990-0.1388820.2439060.155527-0.057517-0.2433590.0385050.123457-0.029797-0.2510020.130891…-0.1585220.3286100.4685590.006440-0.0713260.0464290.262878-0.0735970.083408-0.13362710.1239530.2491460.031028-0.103072-0.012683-0.0612410.0167360.236264-0.238410-0.349272…-0.0948740.3161480.2838090.0352150.100668-0.1503880.1515850.2022990.011277-0.34662620.0096750.0635080.298085-0.113564-0.394117-0.197484-0.143916-0.264382-0.1652450.044551…-0.0770130.2193530.319499-0.054280-0.0175930.068092-0.043105-0.3146320.061136-0.3153243-0.2014780.054600-0.1972190.132496-0.1308590.0599310.0908970.447195-0.066142-0.080050…0.2165200.3367890.2427570.1923320.255502-0.0002680.000050-0.1004860.013850-0.16365240.0124180.231921-0.169535-0.0271080.1622330.0893450.1239970.351209-0.036844-0.328844…0.1541050.4719110.1310340.205431-0.0077950.1226200.1653090.214215-0.148311-0.170526
5 rows × 300 columns
%time train_vecs_t = pd.DataFrame([m_avgvec(x, w2vmodel) for x in x_test])
train_vecs_t
Wall time: 1min 14s
0123456789…2902912922932942952962972982990-0.360456-0.168126-0.1879020.139328-0.580499-0.4768090.3828650.8964780.0045190.060998…0.3379080.313125-0.248374-0.1927840.191395-0.0032970.034540-0.0243450.3077050.0600491-0.0065730.3641380.0565960.062842-0.164288-0.0388410.0045680.271801-0.263575-0.250043…-0.1078460.2474520.2252570.0200390.135461-0.1123770.059987-0.0933460.092084-0.3386792-0.342170-0.1075180.150887-0.012432-0.119799-0.1514690.0628100.317839-0.264509-0.119258…-0.1460240.2517000.4285590.1123630.0885080.0108390.1339460.158355-0.091741-0.3330993-0.0361960.3237470.038649-0.041602-0.247251-0.055818-0.0801030.083953-0.244907-0.281211…-0.2270690.3630510.4721900.0760830.067558-0.1418180.051008-0.112334-0.019767-0.42121040.0850830.1897930.0490330.066349-0.216909-0.0713970.0100420.301876-0.342764-0.218100…-0.1644970.4300710.1228700.0714520.140936-0.096815-0.089997-0.0065230.104536-0.479253…………………………………………………………6170-0.2649000.0843840.0112390.049277-0.1414440.1007490.3151260.146341-0.133169-0.027791…0.1471900.3365360.4516920.1759380.1920360.1654600.1625850.089151-0.057888-0.23366661710.026205-0.0718740.270545-0.027888-0.195445-0.299105-0.0790340.288189-0.127330-0.068026…-0.1921920.2486960.3235430.067723-0.0307340.0417970.171027-0.0150460.115095-0.2317216172-0.4050610.0058830.0379200.075662-0.0390780.1620150.0933000.189479-0.148963-0.012335…0.2102630.3911040.3873800.1361650.4232610.1318360.346203-0.0706950.047509-0.0274066173-0.062726-0.054550-0.029740-0.169576-0.004502-0.0923100.1810260.379483-0.213536-0.264653…0.0600710.4085610.3005020.1743860.0601650.0399830.1387490.1120430.105036-0.1806246174-0.1226030.1167250.177533-0.111880-0.154657-0.210409-0.0839180.100732-0.1648700.042741…-0.1960230.1223200.098776-0.089089-0.085931-0.149250-0.006701-0.1962860.078928-0.180735
6175 rows × 300 columns
train_vecs_t.isnull().any()
0 True
1 True
2 True
3 True
4 True
...
295 True
296 True
297 True
298 True
299 True
Length: 300, dtype: bool
from sklearn.svm import SVC
clf2 = SVC(kernel = 'rbf', verbose = True)
clf2.fit(train_vecs, y_train)
clf2.score(train_vecs, y_train)
[LibSVM]
0.8899146248351496
from sklearn.metrics import classification_report
print(classification_report(y_train, clf2.predict(train_vecs)))
precision recall f1-score support
0 0.89 0.89 0.89 7129
1 0.89 0.89 0.89 7278
accuracy 0.89 14407
macro avg 0.89 0.89 0.89 14407
weighted avg 0.89 0.89 0.89 14407
import jieba
def m_pred(string, model):
words = jieba.lcut(string)
words_vecs = pd.DataFrame(m_avgvec(words, w2vmodel)).T
result = model.predict(words_vecs)
if int(result[0]) == 1:
print(string, ":正向")
else:
print(string, ":负向")
comment = "作为女儿6.1的礼物。虽然晚到了几天。等拿到的时候,女儿爱不释手,上洗手间也看,告知不好。上周末,告诉我她把火鞋和风鞋拿到学校,好多同学羡慕她。呵呵,我也看了其中的人鸦,只可惜没有看完就在老公的催促下睡了。说了这么多,归纳为一句:这套书买的值。"
m_pred(comment, clf2)
作为女儿6.1的礼物。虽然晚到了几天。等拿到的时候,女儿爱不释手,上洗手间也看,告知不好。上周末,告诉我她把火鞋和风鞋拿到学校,好多同学羡慕她。呵呵,我也看了其中的人鸦,只可惜没有看完就在老公的催促下睡了。说了这么多,归纳为一句:这套书买的值。 :正向
在本章所用数据中,各抽取1千条正向、负向评论,重新拟合基于词袋的和基于分布式表达的模型,比较前两种模型效果的改变情况。
import pandas as pd
dfpos = pd.read_excel("购物评论.xlsx", sheet_name = "正向", header=None,nrows=1000)
dfpos['y'] = 1
dfneg = pd.read_excel("购物评论.xlsx", sheet_name = "负向", header=None,nrows=1000)
dfneg['y'] = 0
df0 = dfpos.append(dfneg, ignore_index = True)
df0.head()
0y0感觉用这个手机下载MP3听很方便,用T-Flash卡装上歌,就可以当一个小MP3用了,很不错…11外观美观,速度也不错。上面一排触摸键挺实用。应该对得起这个价格。当然再降点大家肯定也不反对。…12我刚拿到书,也没有仔细阅读,就是粗粗的翻了点,觉得还行。里面是蓝黑两种颜色的,有些单词的下面…13对于二胡曲的精选,应该出版一个系列套装,可分别出售,单独购买。精品二胡曲是有年代和阶段性的,…14用了一年半的 e680 终于送小偷了。刚刚买了一台e850,用了三天,说说我自己的感受。1:…1
4.1 自动摘要的python实现
chapter.txt[1]
'第一回 风雪惊变那说话人五十来岁年纪,一件青布长袍早洗得褪成了蓝灰带白。只听他两片梨花木板碰了几下,左手中竹棒在一面小羯鼓上敲起得得连声。唱道:“小桃无主自开花,烟草茫茫带晚鸦。几处败垣围故井,向来一一是人家。”那说话人将木板敲了几下,说道:“这首七言诗,,.......”颜烈道:“既有姓”包惜弱点了点头,道:“相公可别太多花费了。”颜烈微笑道:“就可惜娘子在服丧,不能戴用珠宝,要多花钱也花不了。’
def cut_sentence(intxt):
delimiters = frozenset('。!?')
buf = []
for ch in intxt:
buf.append(ch)
if delimiters.__contains__(ch):
yield ''.join(buf)
buf = []
if buf:
yield ''.join(buf)
sentdf = pd.DataFrame(cut_sentence(chapter.txt[1]))
sentdf
00第一回 风雪惊变 那说话人五十来岁年纪,一件青布长袍早洗得褪成了蓝灰带白。1只听他两片梨花木板碰了几下,左手中竹棒在一面小羯鼓上敲起得得连声。2唱道:”小桃无主自开花,烟草茫茫带晚鸦。3几处败垣围故井,向来一一是人家。4″ 那说话人将木板敲了几下,说道:”这首七言诗,说的是兵火过后,原来的家家户户,都变成了断………908包惜弱想要他另要一间客房,却又不知如何启齿才好,脸上一阵红一阵白,心事重重。909过了一会,颜烈道:”娘子请自宽便,小人出去买了物品就回。910″包惜弱点了点头,道:”相公可别太多花费了。911″颜烈微笑道:”就可惜娘子在服丧,不能戴用珠宝,要多花钱也花不了。912″
913 rows × 1 columns
sentdf['txtlen'] = sentdf[0].apply(len)
sentlist = sentdf[0][sentdf.txtlen > 20]
print(len(sentlist))
sentlist
583
0 第一回 风雪惊变      那说话人五十来岁年纪,一件青布长袍早洗得褪成了蓝灰带白。
1 只听他两片梨花木板碰了几下,左手中竹棒在一面小羯鼓上敲起得得连声。
4 ”  那说话人将木板敲了几下,说道:“这首七言诗,说的是兵火过后,原来的家家户户,都变成了断...
5 小人刚才说到那叶老汉一家四口,悲欢离合,聚了又散,散了又聚。
6 他四人给金兵冲散,好容易又再团聚,欢天喜地地回到故乡卫州,却见房屋已给金兵烧得干干净净,无可...
...
907 漱洗罢,颜烈与包惜弱一起吃了些点心,两人相对坐在房中。
908 包惜弱想要他另要一间客房,却又不知如何启齿才好,脸上一阵红一阵白,心事重重。
909   过了一会,颜烈道:“娘子请自宽便,小人出去买了物品就回。
910 ”包惜弱点了点头,道:“相公可别太多花费了。
911 ”颜烈微笑道:“就可惜娘子在服丧,不能戴用珠宝,要多花钱也花不了。
Name: 0, Length: 583, dtype: object
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
txtlist = [ " ".join(jieba.lcut(w)) for w in sentlist]
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(txtlist)
Building prefix dict from the default dictionary ...
Dumping model to file cache C:\Users\lenovo\AppData\Local\Temp\jieba.cache
Loading model cost 0.758 seconds.
Prefix dict has been built successfully.
tfidf_matrix = TfidfTransformer().fit_transform(X)
import networkx as nx
similarity = nx.from_scipy_sparse_matrix(tfidf_matrix * tfidf_matrix.T)
scores = nx.pagerank(similarity)
scores
{0: 0.0010912193346531665,
1: 0.0010514692451123236,
2: 0.0016169794514779936,
3: 0.0013256313810434896,
......
579: 0.0022975642232750905,
580: 0.0027147294491056168,
581: 0.0016757809711476844,
582: 0.0017710726716536757}
tops = sorted(scores.items(), key = lambda x: x[1], reverse = True)
tops[:3]
[(104, 0.003887937743683278),
(440, 0.0035158614971836305),
(442, 0.0034495123422054637)]
print(sentlist.iloc[tops[0][0]])
print(sentlist.iloc[tops[1][0]])
sentlist.iloc[tops[2][0]]
”郭啸天道:“自己兄弟,说什么还请不还请?
杨铁心再是一箭,射死了武官,抢将过去,只见那女子在地下挣扎着坐起身来,正是自己妻子。
'”包惜弱道:“在前面,给……给官兵捉去啦!'
topn = 5
topsent = sorted(tops[:topn])
abstract = ''
for item in topsent:
abstract = abstract + sentlist.iloc[item[0]] + "......"
abstract[:-6]
'”郭啸天道:“自己兄弟,说什么还请不还请?......杨铁心提起铁枪要出屋助战,郭啸天一把拉住,低声道:“道长叫咱们别出去。......杨铁心再是一箭,射死了武官,抢将过去,只见那女子在地下挣扎着坐起身来,正是自己妻子。......”包惜弱道:“在前面,给……给官兵捉去啦!......这时颜烈已走出房去,包惜弱问道:“这是什么?'
Original: https://blog.csdn.net/flytrybest/article/details/125481722
Author: ★追梦赤子心★
Title: 文本挖掘学习笔记(三):文档相似度、文档分类和情感分析
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/662986/
转载文章受原作者版权保护。转载请注明原作者出处!