手把手教你学Word2Vec系列一之Corpora and Vector Spaces

[说明]其实Word2Vec非常有用,使用起来也很简单,但总有一些跟我一样懒的娃娃不爱看文档,所以就有了这一系列博客。
Python下的Word2Vec的使用需要安装gensim,安装教程:gensim官网安装教程
本人英文水平有限,还是建议看官方教程,gensim官网使用教程

语料与向量空间

日志记录:

import logging

logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)

将String转为向量

如何将一个String文档转为向量呢?
这里的方法是,首先将语料库的词进行去停用词处理,再为剩下的词赋于一个ID,ID与词的对应关系被称为字典(dictionary)。再用字典来表示文档。

所以,首先我们的目的是要得到语料的字典(dictionary)。

'''假设目前的小小语料库由九个document组成的,每个document只有一个句子'''
documents = ["Human machine interface for lab abc computer applications",
              "A survey of user opinion of computer system response time",
              "The EPS user interface management system",
              "System and human system engineering testing of EPS",
              "Relation of user perceived response time to error measurement",
              "The generation of random binary unordered trees",
              "The intersection graph of paths in trees",
              "Graph minors IV Widths of trees and well quasi ordering",
              "Graph minors A survey"]

'''处理文档(如果是中文先要分词),使用一个小的停用词列表来删除常用词(什么是停用词呢,停用词通常是没有特别语义或者语义特别广泛的词,一般根据不同的任务停用词列表是不同的,也就是说,停用词表是根据不同任务而人为加入的停用词的集合),删除在语料种只出现一次的词'''
stoplist = set('for a of the and to in'.split())
'''删除常用词/停用词'''
texts = [[word for word in document.lower().split() if word not in stoplist] for document in documents]
'''删除只出现一次的词,frequency用于记录每个词的出现频率'''
frequency = defaultdict(int)
for text in texts:
    for token in text:
        frequency[token] += 1
texts = [[token for token in text if frequency[token] > 1] for text in texts]

'''打印texts,观察处理后的每个document'''
pprint(texts)
'''观察打印出的结果(一篇文档仅用几个词来表示,这种方式有一个专门的术语:bag-of-word,又名词袋)'''
输出:[['human', 'interface', 'computer'],
 ['survey', 'user', 'computer', 'system', 'response', 'time'],
 ['eps', 'user', 'interface', 'system'],
 ['system', 'human', 'system', 'eps'],
 ['user', 'response', 'time'],
 ['trees'],
 ['graph', 'trees'],
 ['graph', 'minors', 'trees'],
 ['graph', 'minors', 'survey']]
'''使用整数来表示问题(即特征)的ID,根据ID就可以mapping到ID表示的特征,这种mapping关系被称为字典'''
dictionary = corpora.Dictionary(texts)
'''将字典存入硬盘'''
dictionary.save('/tmp/deerwester.dict')

'''打印dictionary'''
print(dictionary)
输出:Dictionary(12 unique tokens: ['survey', 'eps', 'computer', 'human', 'minors']...)

'''打印dictionary中的词与ID'''
print(dictionary.token2id)
输出:{'survey': 3, 'eps': 8, 'computer': 1, 'human': 2, 'minors': 11, 'system': 7, 'time': 5, 'user': 4, 'interface': 0, 'response': 6, 'trees': 9, 'graph': 10}

到目前为止,我们就得到dictionary啦!

解释一下官网的“question-answer pair”,字面意义就是一个问题一个答案,例如:问题[system在预料中出现了几次?]-答案[一次],二者作为一个整体,不可分割,在这里,question表示特征(feature),answer表示这个特征的量化。

那如何将文档转换为向量呢,这里就要用到上述的字典啦!

'''假设新的文档是如下这样一句话'''
new_doc = "Human computer interaction"
'''使用函数doc2bow()将文档转为向量,函数doc2bow()简单地数了下不同词出现的次数,把每个词转换为相应的ID,然后以向量的形式输出.'''
new_vec = dictionary.doc2bow(new_doc.lower().split())
'''输出转为的向量'''
print(new_vec)  
输出:[(1, 1), (2, 1)]
'''词"interaction"没有出现在字典中,所以被忽略。因此,我们用来训练的语料一定要尽可能大,尽可能包含可能出现的词。那么,如何理解这个向量呢?
(1, 1)表示ID为1的词(computer)出现了1次
(2, 1)表示ID为2的词(Human)出现了1次
'''

试试将整个文档转为向量吧!

'''使用相同的方式'''
corpus = [dictionary.doc2bow(text) for text in texts]
'''存储,以备后续使用'''
corpora.MmCorpus.serialize('/tmp/deerwester.mm', corpus)
'''输出corpus,可以看到,以这种方式存储文档,还是很节省空间滴'''
print(corpus)
输出:[(0, 1), (1, 1), (2, 1)]
[(1, 1), (3, 1), (4, 1), (5, 1), (6, 1), (7, 1)]
[(0, 1), (4, 1), (7, 1), (8, 1)]
[(2, 1), (7, 2), (8, 1)]
[(4, 1), (5, 1), (6, 1)]
[(9, 1)]
[(9, 1), (10, 1)]
[(9, 1), (10, 1), (11, 1)]
[(3, 1), (10, 1), (11, 1)]

可以看到,这种方式是将整个语料加载到内存,然后进行一系列的向量化处理。看似没什么问题,但是,如果我们的语料非常大该怎么办?接下来就来介绍下genmis的内存友好特性。

Corpus Streaming – 一次加载一个文档

class MyCorpus(object):
    # sparse vector inside __iter__
    def __iter__(self):
        for line in open('mycorpus.txt'):
            # 假设每行一个文档,词用空格分开
            yield dictionary.doc2bow(line.lower().split())

# 并不会将整个语料加载到内存
corpus_memory_friendly = MyCorpus()  
print(corpus_memory_friendly)
'''虽然输出与上述是一样的,但是这里每次只加载一行,所以无论你的语料有多大都木有关系。'''
# 一次只加载一个向量
for vector in corpus_memory_friendly:  
    print(vector)

把对语料的处理都放在iter(self)方法里。
这里是mycorpus文件内容:mycorpus.txt
使用另外一种方式也可以达到这样的效果:

from six import iteritems
# 获得词的统计信息
dictionary = corpora.Dictionary(line.lower().split() for line in open('mycorpus.txt'))
# 获得停用词的ID
stop_ids = [dictionary.token2id[stopword] for stopword in stoplist
            if stopword in dictionary.token2id]
# 获取只出现了一次的词的ID
once_ids = [tokenid for tokenid, docfreq in iteritems(dictionary.dfs) if docfreq == 1]
# 删除停用词和只出现了一次的词
dictionary.filter_tokens(stop_ids + once_ids)
# 删除多余的空格
dictionary.compactify()  
print(dictionary)
输出:Dictionary(12 unique tokens: ['interface', 'minors', 'time', 'survey', 'computer']...)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值