文本分析

用Py做文本分析4:文本向量化

2020-02-07  本文已影响0人  凡有言说

文本向量化即将信息数值化,方便后续的建模分析。

1.词袋模型

词袋模型将文本直接简化为一系列词的集合,然后对此编号,形成字典,最终将文本转化为特征向量。这里以“大鱼吃小鱼也吃虾米,小于吃虾米”为例。

词袋模型中,词和文本的关系相当于文本是一个袋子,然后把词直接放在袋子里。该模型的缺点在于:

下面我们用genism包来实现词袋模型,关于genism包的安装:
python3安装及加载gensim
windows安装gensim

首先是将文档进行分词,然后创建一个字典。在字典中,建立word和id的映射关系(第一个词是xx,第二个词是xx...)。最后把所有的单词取一个集合。

from gensim.corpora import Dictionary

text = [['human', 'interface', 'computer']]
dct = Dictionary(text)

#映射关系
dct.token2id

{'computer': 0, 'human': 1, 'interface': 2}

#文档数
dct.num_docs

1

#词条数
dct.num_pos

3

#向词典中增加词条
dct.add_documents([['cat', 'say', 'meow'], ['dog']])
dct.token2id

{'computer': 0,
 'human': 1,
 'interface': 2,
 'cat': 3,
 'meow': 4,
 'say': 5,
 'dog': 6}

dct.num_docs

3

下面我们来看一看另一种格式:BOW稀疏向量
比如一个字典里有100万个词,此时句子里只包含了10个词,如果生成一个长度为100万的向量,则大部分都是零,此时可以用BOW稀疏向量来解决。
list of (token_id, token_count) 第几个词出现几次
这样10个词的句子只需使用10个向量,大大降低了维度。

dct.doc2bow(['this', 'is', 'cat', 'not', 'a', 'dog'])

[(3, 1), (6, 1)]

#返回新出现的(不在字典中)的词
dct.doc2bow(['this', 'is', 'cat', 'not', 'a', 'dog'], return_missing = True)

([(3, 1), (6, 1)], {'a': 1, 'is': 1, 'not': 1, 'this': 1})

dct.doc2idx(['this', 'is', 'cat', 'not', 'a', 'dog'])

[-1, -1, 3, -1, -1, 6]

有时我们希望看到完整的,此时要使用"BOW长向量"。这里有两个转换思路:

2.文档-词条矩阵

2.1用Pandas库实现

基本的程序框架:

#分词及清理停用词函数
stoplist_path = 'D:/Files/program data/nlp/PythonData/停用词.txt'
stoplist = list(pd.read_csv(stoplist_path, names = ['w'], sep = 'aaa',
                           encoding = 'utf-8', engine = 'python').w)

import jieba
def m_cut(intext):
    return [w for w in jieba.cut(intext)
           if w not in stoplist and len(w) >1]

#数据框转换函数
def m_appdf(chapnum):
    tmpdf = pd.DataFrame(m_cut(chapter.txt[chapnum + 1]), columns = ['word'])
    tmpdf['chap'] = chapter.index[chapnum]
    return tmpdf

#全部读入并转换为数据框
df0 = pd.DataFrame(columns = ['word', 'chap']) #初始化结果数据框

for i in range(len(chapter)):
    df0 = df0.append(m_appdf(i))
df0.tail()

#输出为序列格式
df0.groupby(['word', 'chap']).agg('size').tail(10)

#直接输出为数据框
t2d = pd.crosstab(df0.word, df0.chap)
len(t2d)
t2d.head()

#计算各词条的总出现频数,并对低频词进行删减
totnum = t2d.agg(func = 'sum', axis = 1)
totnum
t2dclean = t2d.iloc[list(totnum >= 10)]
t2dclean.T

2.2用sklearn库实现

文本信息在向量化之前很难直接进行建模分析,而skleam库提供了一个从文本信息到数据挖掘模型间的桥梁,即CountVectorizer类。通过该类中的功能,可以较便捷地实现文档信息的向量化。

class sklearn.feature_extraction.text.CountVectorizer(
        input = 'content' : {'filename', 'file', 'content'}
        encoding = 'utf-8'
        stop_words = None
        min_df / max_dif : float in range[0.0, 1.0] or int, default = 1/1.0
              词频绝对值/比例的阈值,在此范围之外的将被剔除
              小数格式说明提供的是百分比,如0.05指的是5%的阈值
)
from sklearn.feature_extraction.text import CountVectorizer
countvec = CountVectorizer()

analyze = countvec.build_analyzer()
analyze('郭靖 和 哀牢山 三十六 剑 。')

['郭靖', '哀牢山', '三十六']

CountVectorizer.fit_transform(raw_documents)

x = countvec.fit_transform(['郭靖 和 哀牢山 三十六 剑 。','黄蓉 和 郭靖 郭靖'])
type(x)

#将稀疏矩阵转换为标准格式矩阵
x.todense()

matrix([[1, 1, 1, 0],
        [0, 0, 2, 1]], dtype=int64)

#词汇列表,获取每个列对应的词条
countvec.get_feature_names()

['三十六', '哀牢山', '郭靖', '黄蓉']

#词条字典
countvec.vocabulary_

{'郭靖': 2, '哀牢山': 1, '三十六': 0, '黄蓉': 3}

接下来我们用sklearn生成射雕的章节d2m矩阵

#将文档数据框处理为空格分隔词条的文本格式
rawchap = [' '.join(m_cut(w)) for w in chapter.txt]

#生产bow稀疏矩阵
from sklearn.feature_extraction.text import CountVectorizer
countvec = CountVectorizer(min_df = 10) #出现10次以上的才纳入分析
res = countvec.fit_transform(rawchap)
res

#转换为标准格式的d2m矩阵
res.todense()

#词汇列表,获取每个列对应的词条
countvec.get_feature_names()

3.N-gram

已介绍的词袋模型有一定的缺陷,完全无法利用语序信息

Bi-gram:进一步保留顺序信息,两个两个词条地看

N-gram:考虑更多的前后词

离散表示方式面临的问题

4.分布式表示

分布式的思想是通过文本的上下文信息去发现目标文本的含义。具体来说:

在操作的过程中

一个简单模型在大数据量上的表现会比复杂模型在小数据量上的表现更好,数据中包含的信息量决定一切。

4.1共线矩阵

共线矩阵想表示的是一句话中词A和哪些词共同出现了。


image.png

窗口长度越长,则信息量越丰富,但是数据量也会越大。一般设为5-10。共线矩阵的一大特点在于其行/列数值自然就表示出各个词汇的相似度。但直接将其作为词向量会出现如下问题:

解决的思路是构造低维稠密向量作为词的分布式表示(25-1000)

但用SVD也面临一些问题:

4.2NNLM

NNLM是一个前馈的神经网络模型,只考虑了前文出现的内容

在具体计算的时候

image.png

整个网络由输入层、投射层、隐含层和输出层构成。

经过投射层的处理后,输入的向量就成了(N-1)*M维。

虽然该模型已经对数据做了降维处理,但是计算量依旧很大,需要使用GPU来计算。

4.3word2vec模型

word2vec模型的出发点是降低神经网络的计算量,但相比较NNLM也做了其他有益的改进。

本质上,word2vec只是一个线性分类器。背后支撑word2vec是大量的语料,虽然模型粗糙,但是语料多了后保留的信息就多。显然,短语料是不适合用word2vec来分析。

为了降低运算量,word2vec使用了softmax

还是用负例采样

当然,word2vec仍然存在一些问题:

word2vec就是用一个一层的神经网络(CBOW的本质)把one-hot形式的词向量映射为分布式形式的词向量,为了加快训练速度,用了Hierarchical softmax,negative sampling 等trick(MaybeSheWill)。

参考资料:
Python数据分析--玩转文本挖掘
了解N-Gram模型
语言模型:从n元模型到NNLM
神经网络语言模型(NNLM)
理解 NNLM
世上最通俗的理解word2vec
无痛理解word2vec

上一篇下一篇

猜你喜欢

热点阅读