“达观杯”文本智能处理挑战赛(初步文本向量化表示)

文本向量化

将文本数据转换成计算机能够计算的数据。

1、词袋模型(Bag of Words Model)

词袋模型把文本(段落或者文档)被看作是无序的词汇集合,忽略语法甚至是单词的顺序,把每一个单词都进行统计,同时计算每个单词出现的次数,常常被用在文本分类中,如贝叶斯算法、LDA 和 LSA 等。

词袋模型首先会进行分词,在分词之后,通过统计每个词在文本中出现的次数,我们就可以得到该文本基于词的特征,如果将各个文本样本的这些词与对应的词频放在一起,就是我们常说的向量化。向量化完毕后一般也会使用TF-IDF进行特征的权重修正,再将特征进行标准化。 再进行一些其他的特征工程后,就可以将数据带入机器学习算法进行分类聚类了。

总结下词袋模型的三部曲:分词(tokenizing),统计修订词特征值(counting)与标准化(normalizing)。

与词袋模型非常类似的一个模型是词集模型(Set of Words,简称SoW),和词袋模型唯一的不同是它仅仅考虑词是否在文本中出现,而不考虑词频。也就是一个词在文本在文本中出现1次和多次特征处理是一样的。在大多数时候,我们使用词袋模型,后面的讨论也是以词袋模型为主。

当然,词袋模型有很大的局限性,因为它仅仅考虑了词频,没有考虑上下文的关系,因此会丢失一部分文本的语义。但是大多数时候,如果我们的目的是分类聚类,则词袋模型表现的很好。

from sklearn.feature_extraction.text import CountVectorizer
vectorizer=CountVectorizer()
corpus=["I come to China to travel", 
    "This is a car polupar in China",          
    "I love tea and Apple ",   
    "The work is to write some papers in science"] 
print(vectorizer.fit_transform(corpus))
print(vectorizer.fit_transform(corpus).toarray())
print(vectorizer.get_feature_names())

可以看到我们一共有19个词,所以4个文本都是19维的特征向量。而每一维的向量依次对应了下面的19个词。另外由于词"I"在英文中是停用词,不参加词频的统计

词袋模型存在两个很明显的问题:

1、如果我们直接将统计词频后的19维特征做为文本分类的输入,会发现有一些问题。比如第一个文本,我们发现"come","China"和“Travel”各出现1次,而“to“出现了两次。似乎看起来这个文本与”to“这个特征更关系紧密。但是实际上”to“是一个非常普遍的词,几乎所有的文本都会用到,因此虽然它的词频为2,但是重要性却比词频为1的"China"和“Travel”要低的多。如果我们的向量化特征仅仅用词频表示就无法反应这一点。因此我们需要进一步的预处理来反应文本的这个特征,而这个预处理就是TF-IDF。

2、由于大部分的文本都只会使用词汇表中的很少一部分的词,因此我们的词向量中会有大量的0。也就是说词向量是稀疏的。在实际应用中一般使用稀疏矩阵来存储。但是分词后的词汇表如果非常大,达到100万+,此时直接使用向量化的方法,将对应的样本对应特征矩阵载入内存,有可能将内存撑爆,在这种情况下就需要进行特征的降维,比如Hash Trick就是非常常用的文本特征降维方法,以及Word2Vec。

2、TFIDF

针对词袋模型存在的问题1,可以使用TF-IDF来处理,TF-IDF是Term Frequency - Inverse Document Frequency的缩写,即“词
频-逆文本频率”。它由两部分组成,TF和IDF。TF是词频,即文本中各个词的出现频率统计,并作为文本特征。IDF是“逆文本频率”。TF-IDF的主要思想是:如果某个词在一文档中出现的频率高,也即 TF 高;并且在语料库中其他文档中很少出现,即 DF 低,也即 IDF 高,则认为这个词具有很好的类别区分能力。

概括来讲, IDF反应了一个词在所有文本中出现的频率,如果一个词在很多的文本中出现,那么它的IDF值应该低,比如上文中的“to”。而反过来如果一个词在比较少的文本中出现,那么它的IDF值应该高。比如一些专业的名词如“Machine Learning”。这样的词IDF值应该高。一个极端的情况,如果一个词在所有的文本中都出现,那么它的IDF值应该为0。

IDF公式如下:
%E6%90%9C%E7%8B%97%E6%88%AA%E5%9B%BE20190304231704.jpg

其中,N代表语料库中文本的总数,而N(x)代表语料库中包含词x的文本总数,如果分母不加1,会存在分母为0的情况(比如某一个生僻词在语料库中没有,这样我们的分母为0, IDF没有意义了),所以常用的IDF我们需要做一些平滑,使语料库中没有出现的词也可以得到一个合适的IDF值。

计算某一个词的TF-IDF值,如下:
%E6%90%9C%E7%8B%97%E6%88%AA%E5%9B%BE20190304231739.jpg
其中TF(x)指词x在当前文本中的词频。

TF-IDF小结:

TF-IDF是非常常用的文本挖掘预处理基本步骤,但是如果预处理中使用了Hash Trick,则一般就无法使用TF-IDF了,因为Hash Trick后我们已经无法得到哈希后的各特征的IDF的值。使用了IF-IDF并标准化以后,我们就可以使用各个文本的词特征向量作为文本的特征,进行分类或者聚类分析。

当然TF-IDF不光可以用于文本挖掘,在信息检索等很多领域都有使用。因此值得好好的理解这个方法的思想。

import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer

train = pd.read_csv('train_set.csv')
from sklearn.feature_extraction.text import TfidfTransformer  
from sklearn.feature_extraction.text import CountVectorizer  
vectorizer=CountVectorizer()
transformer = TfidfTransformer()
tfidf = transformer.fit_transform(vectorizer.fit_transform(train['word_seg'].head(10)))  
print(tfidf)
  (0, 2913)	0.15018495673463642
  (0, 2205)	0.023021181032819263
  (0, 1975)	0.5807151660405941
  (0, 538)	0.054161663361455774
  (0, 101)	0.1802219480815637
  (0, 2726)	0.054161663361455774
  (0, 2323)	0.017906626085869997
  (0, 1697)	0.020024660897951522
  (0, 1673)	0.016081162411277224
  (0, 2294)	0.054161663361455774
  (0, 603)	0.03216232482255445
  (0, 1772)	0.01096660746432796
  (0, 2203)	0.039602383312931415
  (0, 2414)	0.027080831680727887
  (0, 3440)	0.21933214928655917
  (0, 3233)	0.027080831680727887
  (0, 823)	0.054161663361455774
  (0, 480)	0.023021181032819263
  (0, 336)	0.023021181032819263
  (0, 2930)	0.027080831680727887
  (0, 813)	0.012021511763368601
  (0, 2958)	0.023021181032819263
  (0, 3364)	0.027080831680727887
  (0, 1548)	0.027080831680727887
  (0, 1473)	0.020140813059185844
  :	:
  (9, 377)	0.026936291863186575
  (9, 891)	0.013468145931593288
  (9, 2273)	0.013468145931593288
  (9, 2846)	0.013468145931593288
  (9, 2056)	0.013468145931593288
  (9, 511)	0.013468145931593288
  (9, 369)	0.013468145931593288
  (9, 2990)	0.026936291863186575
  (9, 2831)	0.013468145931593288
  (9, 125)	0.013468145931593288
  (9, 158)	0.013468145931593288
  (9, 2344)	0.013468145931593288
  (9, 1241)	0.013468145931593288
  (9, 580)	0.013468145931593288
  (9, 2230)	0.013468145931593288
  (9, 2150)	0.013468145931593288
  (9, 1257)	0.013468145931593288
  (9, 2026)	0.013468145931593288
  (9, 779)	0.013468145931593288
  (9, 591)	0.013468145931593288
  (9, 219)	0.013468145931593288
  (9, 3153)	0.013468145931593288
  (9, 2134)	0.013468145931593288
  (9, 493)	0.013468145931593288
  (9, 835)	0.013468145931593288

3、Word2Vec

Word2Vec 是 Google 团队2013年推出的,自提出后被广泛应用在自然语言处理任务中,并且受到它的启发,后续出现了更多形式的词向量模型。Word2Vec 主要包含两种模型:Skip-Gram 和 CBOW,值得一提的是,Word2Vec 词向量可以较好地表达不同词之间的相似和类比关系。

参数解释如下:

  • 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,则负采样将会被选择使用。
    详细参数说明可查看 Word2Vec 源代码。
from gensim.models import Word2Vec

#进行分词
def sentence2list(sentence):
    return sentence.strip().split()
train['word_seg'].head().apply(sentence2list)
0    [816903, 597526, 520477, 1179558, 1033823, 758...
1    [90540, 816903, 441039, 816903, 569138, 816903...
2    [816903, 1012629, 957974, 1033823, 328210, 947...
3    [563568, 1239563, 680125, 780219, 782805, 1033...
4    [816903, 816903, 816903, 139132, 816903, 31232...
Name: word_seg, dtype: object
#选取1000条数据进行模拟
sentences_train = list(train['word_seg'].head(1000).apply(sentence2list))
model = Word2Vec(sentences=sentences_train, sg=1, size=100,  window=5,  min_count=2,  negative=1, sample=0.001, hs=1, workers=4)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值