文本数据(非结构化数据)转换成计算机能够计算的数据。有两种常用的模型:词袋和词向量模型。
词袋模型看起来好像一个口袋把所有词都装进去,但却不完全如此。在自然语言处理和信息检索中作为一种简单假设,词袋模型把文本(段落或者文档)被看作是无序的词汇集合,忽略语法甚至是单词的顺序,把每一个单词都进行统计,同时计算每个单词出现的次数,常常被用在文本分类中,如贝叶斯算法、LDA 和 LSA 等。
对于 for 循环多次直接用到列表推导式。在 Python 中,列表推导式的效率比 for 快很多,尤其在数据量大的时候效果更明显.
import jieba
#定义停用词、标点符号
punctuation = [",","。", ":", ";", "?"]
#定义语料
content = ["机器学习带动人工智能飞速的发展。",
"深度学习带动人工智能飞速的发展。",
"机器学习和深度学习带动人工智能飞速的发展。"
]
# 对语料进行分词
segs_1 = [jieba.lcut(con) for con in content]
print(segs_1)
#去掉停止词
tokenized = []
for sentence in segs_1:
words = []
for word in sentence:
if word not in punctuation:
words.append(word)
tokenized.append(words)
print("\n去除停止词后:",tokenized)
# 把所有的分词结果放到一个袋子(List)里面,也就是取并集,再去重,获取对应的特征词。
#求并集
bag_of_words = [ x for item in segs_1 for x in item if x not in punctuation]
print(bag_of_words)
#去重
bag_of_words = list(set(bag_of_words))
print(bag_of_words)
# 以去重后的特征词顺序和去除停止词后的分词进行词袋化
bag_of_word2vec = []
for sentence in tokenized:
tokens = [1 if token in sentence else 0 for token in bag_of_words ]
bag_of_word2vec.append(tokens)
print(bag_of_word2vec)
词袋数据可作为分类/预测/深度模型 的输入数据。
import jieba
#定义停用词、标点符号
punctuation = [",","。", ":", ";", "?"]
#定义语料
content = ["机器学习带动人工智能飞速的发展。",
"深度学习带动人工智能飞速的发展。",
"机器学习和深度学习带动人工智能飞速的发展。"
]
# 对语料进行分词
segs_1 = [jieba.lcut(con) for con in content]
print(segs_1)
#去掉停止词
tokenized = []
for sentence in segs_1:
words = []
for word in sentence:
if word not in punctuation:
words.append(word)
tokenized.append(words)
print("\n去除停止词后:",tokenized)
from gensim import corpora
import gensim
#tokenized是去标点之后的
dictionary = corpora.Dictionary(tokenized)
#保存词典到内存中
dictionary.save('deerwester.dict')
# dictionary2 = corpora.Dictionary.load('deerwester.dict')#加载词典
print(dictionary)
print(dictionary.token2id)
# 函数 doc2bow(),作用只是计算每个不同单词的出现次数,将单词转换为其整数单词 id 并将结果作为稀疏向量返回。
corpus = [dictionary.doc2bow(sentence) for sentence in segs_1]
print(corpus )
词袋数据可作为分类/预测/深度模型 的输入数据。
深度学习带给自然语言处理最令人兴奋的突破是词向量(Word Embedding)技术。词向量技术是将词语转化成为稠密向量。在自然语言处理应用中,词向量作为机器学习、深度学习模型的特征进行输入。因此,最终模型的效果很大程度上取决于词向量的效果。
给词向量一个定义,词向量就是要用某个固定维度的向量去表示单词。也就是说要把单词变成固定维度的向量,作为机器学习(Machine Learning)或深度学习模型的特征向量输入。
这个模型是如何定义数据的输入和输出呢?一般分为CBOW(Continuous Bag-of-Words 与Skip-Gram两种模型。CBOW模型的训练输入是某一个特征词的上下文相关的词对应的词向量,而输出就是这特定的一个词的词向量。 Skip-Gram模型和CBOW的思路是反着来的,即输入是特定的一个词的词向量,而输出是特定词对应的上下文词向量。CBOW对小型数据库比较合适,而Skip-Gram在大型语料中表现更好。
Word2Vec解决了词袋模型的第二个缺点(词袋模型不会尝试学习基础单词的含义。)。
Word2Vec是一种较新的模型,该模型使用浅层神经网络将单词嵌入到低维向量空间中。结果是一组词向量,其中在向量空间中靠在一起的向量根据上下文具有相似的含义,而彼此远离的词向量具有不同的含义。例如,strong和powerful会彼此靠近,strong并且Paris会相对较远。Word2Vec模型,我们可以计算文档中每个单词的向量。
该模型有两个版本,并且Word2Vec 类同时实现了这两个版本:
from gensim.models import Word2Vec
import jieba
#定义停用词、标点符号
punctuation = [",","。", ":", ";", ".", "'", '"', "’", "?", "/", "-", "+", "&", "(", ")"]
sentences = [
"长江是中国第一大河,干流全长6397公里(以沱沱河为源),一般称6300公里。流域总面积一百八十余万平方公里,年平均入海水量约九千六百余亿立方米。以干流长度和入海水量论,长江均居世界第三位。",
"黄河,中国古代也称河,发源于中华人民共和国青海省巴颜喀拉山脉,流经青海、四川、甘肃、宁夏、内蒙古、陕西、山西、河南、山东9个省区,最后于山东省东营垦利县注入渤海。干流河道全长5464千米,仅次于长江,为中国第二长河。黄河还是世界第五长河。",
"黄河,是中华民族的母亲河。作为中华文明的发祥地,维系炎黄子孙的血脉.是中华民族民族精神与民族情感的象征。",
"黄河被称为中华文明的母亲河。公元前2000多年华夏族在黄河领域的中原地区形成、繁衍。",
"在兰州的“黄河第一桥”内蒙古托克托县河口镇以上的黄河河段为黄河上游。",
"黄河上游根据河道特性的不同,又可分为河源段、峡谷段和冲积平原三部分。 ",
"黄河,是中华民族的母亲河。"
]
# 去标点符号(注:这里并没用进行去除停止词,完整的步骤应包括去除停止词)
sentences = [jieba.lcut(sen) for sen in sentences]
tokenized = []
for sentence in sentences:
words = []
for word in sentence:
if word not in punctuation:
words.append(word)
tokenized.append(words)
# print(sentences)
print(tokenized)
# 增加ID: 当然,也可以不进行此步骤,因为列表本身就有下标索引。
# from gensim import corpora
# dictionary = corpora.Dictionary(tokenized)
# print(dictionary)
# print(dictionary.token2id)
#
"""
sg=1 是 skip-gram 算法,对低频词敏感;默认 sg=0 为 CBOW 算法。
size 是输出词向量的维数,值太小会导致词映射因为冲突而影响结果,值太大则会耗内存并使算法计算变慢,一般值取为100到200之间。
window 是句子中当前词与目标词之间的最大距离,3表示在目标词前看3-b 个词,后面看 b 个词(b 在0-3之间随机)。
min_count 是对词进行过滤,频率小于 min-count 的单词则会被忽视,默认值为5。
negative 和 sample 可根据训练结果进行微调,sample 表示更高频率的词被随机下采样到所设置的阈值,默认值为 1e-3。
hs=1 表示层级 softmax 将会被使用,默认 hs=0 且 negative 不为0,则负采样将会被选择使用。
"""
model = Word2Vec(tokenized, sg=1, size=100, window=5, min_count=2, negative=1, sample=0.001, hs=1, workers=4)
model.save('model') #保存模型
model = Word2Vec.load('model') #加载模型
# 模型训练好之后,接下来就可以使用模型,可以用来计算句子或者词的相似性、最大匹配程度等。
print(model.similarity('黄河', '黄河')) #黄河和黄河自己的相似度
print(model.similarity('黄河', '长江'))#黄河和长江的相似度
# 预测最接近的词,预测与黄河和母亲河最接近,而与长江不接近的词:注:返回的每个词后面是相似度大小
print(model.most_similar(positive=['黄河', '母亲河'], negative=['长江']))
# [(词语,相似度大小),(词语,相似度大小),(词语,相似度大小),(词语,相似度大小),]就作为一个可以替代原来的词袋模型的训练数据。
Doc2Vec 是 Mikolov 在 Word2Vec 基础上提出的另一个用于计算长文本向量的工具。在 Gensim 库中,Doc2Vec 与 Word2Vec 都极为相似。但两者在对输入数据的预处理上稍有不同,Doc2vec 接收一个由 LabeledSentence 对象组成的迭代器作为其构造函数的输入参数。其中,LabeledSentence 是 Gensim 内建的一个类,它接收两个 List 作为其初始化的参数:word list 和 label list。
Doc2Vec 也包括两种实现方式:DBOW(Distributed Bag of Words)和 DM (Distributed Memory)。DBOW 和 DM 的实现,二者在 gensim 库中的实现用的是同一个方法,该方法中参数 dm = 0 或者 dm=1 决定调用 DBOW 还是 DM。Doc2Vec 将文档语料通过一个固定长度的向量表达。
Word2Vec模型可以计算文档中每个单词的向量。但是,如果我们要为整个文档计算一个向量,该怎么办?我们可以对文档中每个单词的向量进行平均-尽管这是快速而粗略的,但它通常很有用。但是,有更好的方法…那就是Doc2Vec,基本思想是:就像文档中有另一个像单词一样的浮动单词矢量一样起作用,它有助于所有训练预测,并且像其他单词矢量一样进行更新,但是我们将其称为doc矢量。
Doc2Vec有两种实现:
for c in tokenized:
print(c)
#定义数据预处理类,作用是给每个文章添加对应的标签
from gensim.models.doc2vec import Doc2Vec,LabeledSentence
doc_labels = ["长江","黄河","黄河","黄河","黄河","黄河","黄河"]
punctuation = [",","。", ":", ";", "?"]
#定义语料
class LabeledLineSentence(object):
def __init__(self, doc_list, labels_list):
self.labels_list = labels_list
self.doc_list = doc_list
def __iter__(self):
for idx, doc in enumerate(self.doc_list):
yield LabeledSentence(words=doc,tags=[self.labels_list[idx]])
# model = Doc2Vec(content,dm=1, size=100, window=8, min_count=5, workers=4)
# model.save('model')
# model = Doc2Vec.load('model')
# 上面定义好了数据预处理函数,我们将 Word2Vec 中分词去标点后的数据,进行转换:
iter_data = LabeledLineSentence(tokenized, doc_labels)
# 定义模型参数
model = Doc2Vec(dm=1, size=100, window=8, min_count=5, workers=4)
model.build_vocab(iter_data)
# 训练模型, 设置迭代次数1000次,start_alpha 为开始学习率,end_alpha 与 start_alpha 线性递减
model.train(iter_data,total_examples=model.corpus_count,epochs=1000,start_alpha=0.01,end_alpha =0.001)
#根据标签找最相似的,这里只有黄河和长江,所以结果为长江,并计算出了相似度
print(model.docvecs.most_similar('黄河'))
# 对黄河和长江标签做相似性计算:
print(model.docvecs.similarity('黄河','长江'))
gensim 中Fasttext 模型架构和Word2Vec的模型架构差几乎一样,只不过在模型词的输入部分使用了词的n-gram的特征。这里需要讲解一下n-gram特征的含义。举个例子,如果原词是一个很长的词:你吃了吗。jieba分词结果为[“你”,“吃了”,“吗”]。
所以发现没,n-gram的意思将词中连续的n个词连起来组成一个单独的词。
如果使用unigram和bigram的特征,词的特征就会变成:[“你”,“吃了”,“吗”,“你吃了”,“吃了吗”]这么一长串。使用n-gram的词向量使得Fast-text模型可以很好的解决未登录词(OOV——out-of-vocabulary)的问题。