赞
踩
文本向量化的方法有很多:
one-hot 词汇表征方法最后形成的结果是一种稀疏编码结果,在深度学习应用于 NLP 任务之前, 这种表征方法在传统的 NLP 模型中已经取得了很好的效果。但是这种表征方法有两个缺陷: 一是容易造成维数灾难,10000 个单词的词汇表不算多,但对于百万级、千万级的词汇表简直无法忍受。
- 对于句子、篇章,常用的离散表示方法是词袋模型,词袋模型以 One-Hot 为基础,忽略词表中词的顺序和语法关系, 通过记录词表中的每一个词在该文本中出现的频次来表示该词在文本中的重要程度,解决了 One-Hot 未能考虑词频的问题
- 词袋(Bag Of Word) 模型是最早的以词语为基本单元的文本向量化方法。词袋模型,也称为计数向量表示(Count Vectors). 文档的向量表示可以直接使用单词的向量进行求和得到
- 与词袋模型原理类似,Bi-gram 将相邻两个词编上索引,N-gram 将相邻 N 个词编上索引
TF-IDF(词频-逆文档频率法,Term Frequency-Inverse Document Frequency) 作为一种加权方法, TF-IDF 在词袋模型的基础上对次出现的频次赋予 TF-IDF 权值,对词袋模型进行修正,进而表示该词在文档集合中的重要程度
- 统计各词在文档中的 TF-IDF 值(词袋模型 + IDF 值)
- 词袋模型、Bi-gram、N-gram 都是基于计数得到的,而 TF-IDF 则是基于频率统计得到的
- 在利用 TF-IDF 进行特征提取时,若词 α 在某篇文档中出现频率较高且在其他文档中出现频率较低时, 则认为α可以代表该文档的特征,具有较好的分类能力,那么α作为特征被提取出来
TF-IDF 的分数代表了词语在当前文档和整个语料库中的相对重要性。TF-IDF 分数由两部分组成
TF(Term Frequency):词语频率
TF(t)=词语在当前文档出现的次数/当前文档中词语的总数TF(t)
- TF 判断的是该字/词语是否是当前文档的重要词语,但是如果只用词语出现频率来判断其是否重要可能会出现一个问题, 就是有些通用词可能也会出现很多次,如:a、the、at、in 等,当然一般我们会对文本进行预处理时去掉这些所谓的停用词(stopwords), 但是仍然会有很多通用词无法避免地出现在很多文档中,而其实它们不是那么重要
IDF(Inverse Document Frequency):逆文档频率
IDF(t)=loge(文档总数/出现该词语的文档总数)
- IDF 用于判断是否在很多文档中都出现了词词语,即很多文档或所有文档中都出现的就是通用词。 出现该词语的文档越多,IDF 越小,其作用是抑制通用词的重要性
将上述求出的 TF 和 IDF 相乘得到的分数 TF-IDF,就是词语在当前文档和整个语料库中的相对重要性
TF-IDF 与一个词在当前文档中出现次数成正比,与该词在整个语料库中的出现次数成反比
共现:即共同实现,比如:一句话中共同出现,或一篇文章中共同出现
共现矩阵构造时需要给出共同出现的距离一个规范– 窗口
- 如果窗口宽度是 2,那就是在当前词的前后各 2 个词的范围内共同出现, 可以想象,其实是一个总长为 5 的窗口依次扫过所有文本,同时出现在其中的词就说它们共现
当前词与自身不存在共现,共现矩阵实际上是对角矩阵
word2vec 通常有两个版本的语言模型:
- 一种是给定上下文词,需要我们来预测中间目标词,这种模型叫做
连续词袋模型
(Continuous Bag-of-Wods Model,CBOW)- 另一种是给定一个词语,我们来根据这个词预测它的上下文,这种模型叫做
skip-gram 模型
。而且每个模型都有两种策略
优点:简单快捷
缺点:数据稀疏、耗时耗空间、不能很好地展示词与词之间的相似关系,且还未考虑到词出现的频率,因而无法区别词的重要性
- One-hot 的第一个问题是:One-hot 的基本假设是词之间的
语义和语法关系是相互独立
的,仅仅从两个向量是无法看出两个词汇之间的关系的,这种独立性不适合词汇语义的运算;- One-hot 的第二个问题是:
维度爆炸
问题,随着词典规模的增大,句子构成的词袋模型的维度变得越来越大,矩阵也变得超稀疏,这种维度的爆增,会大大耗费计算资源。
import os import numpy as np import pandas as pd import jieba def doc2onthot_matrix(file_path): """ 文本向量化 One-Hot 1.文本分词 """ # (1)读取待编码的文件 with open(file_path, encoding = "utf-8") as f: docs = f.readlines() # (2)将文件每行分词,分词后的词语放入 words 中 words = [] for i in range(len(docs)): docs[i] = jieba.lcut(docs[i].strip("\n")) words += docs[i] # (3)找出分词后不重复的词语,作为词袋,是后续 onehot 编码的维度, 放入 vocab 中 vocab = sorted(set(words), key = words.index) # (4)建立一个 M 行 V 列的全 0 矩阵,M 是文档样本数,这里是行数,V 为不重复词语数,即编码维度 M = len(docs) V = len(vocab) onehot = np.zeros((M, V)) for i, doc in enumerate(docs): for word in doc: if word in vocab: pos = vocab.index(word) onehot[i][pos] = 1 onehot = pd.DataFrame(onehot, columns = vocab) return onehot if __name__ == "__main__": data_dir = "" corpus = os.path.join(data_dir, "aaa.txt") onehot = doc2onthot_matrix(corpus) print(onehot)
优点:
- 方法简单,当语料充足时,处理简单的问题如文本分类,其效果比较好
缺点:
- 数据稀疏、维度大
- 无法保留词序信息
- 存在语义鸿沟的问题
优点:
- 考虑了词的顺序
缺点:
- 词向量急剧膨胀
def ngrams(input_list, n): return [input_list[i:i+n] for i in range(len(input_list)-n+1)] # 定义文档 document = "This is a sentence for n-gram example." # 分词 words = document.lower().split() # 生成 bi-gram bigrams = ngrams(words, 2) print("Bi-grams:", bigrams) # 生成 tri-gram trigrams = ngrams(words, 3) print("Tri-grams:", trigrams) # 生成 4-gram fourgrams = ngrams(words, 4) print("Four-grams:", fourgrams) #Bi-grams: [['this', 'is'], ['is', 'a'], ['a', 'sentence'], ['sentence', 'for'], ['for', 'n-gram'], ['n-gram', 'example.']] #Tri-grams: [['this', 'is', 'a'], ['is', 'a', 'sentence'], ['a', 'sentence', 'for'], ['sentence', 'for', 'n-gram'], ['for', 'n-gram', 'example.']] #Four-grams: [['this', 'is', 'a', 'sentence'], ['is', 'a', 'sentence', 'for'], ['a', 'sentence', 'for', 'n-gram'], ['sentence', 'for', 'n-gram', 'example.']]
优点:
- 简单快速,结果比较符合实际情况
缺点:
- 单纯以”词频”衡量一个词的重要性,不够全面,有时重要的词可能出现次数并不多
- 无法体现词的位置信息,出现位置靠前的词与出现位置靠后的词,都被视为重要性相同,这是不正确的
- 高效,Mikolov 在论文中指出一个优化的单机版本一天可以训练上千亿个词
文档向量化可以使用如下步骤实现:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。