赞
踩
做文本分类这样的问题,需要从大量语料中提取特征,并将这些文本特征变换为数值特征。
假设我们有下面3个样本,怎么将他们转换为数值特征呢?
样本 | 文本 |
---|---|
1 | God is love |
2 | OpenGL on the GPU is fast |
3 | Doctor David is PHD |
这种所谓Bags of words
的特征,是将训练集中所有出现过的单词做成一个字典,统计每个单词出现的次数,作为特征。本文例子中有3个样本,共出现了13个单词,出去3个is是重复出现的,可获得一个由11个单词组成的字典。统计这11个单词在每个样本中的出现次数,可得:
Bags of words特征
样本 | david | doctor | fast | god | gpu | is | love | on | opengl | phd | the |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 |
2 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 1 |
3 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 |
我们也可以用sklearn
中的sklearn.feature_extraction.text.CountVectorizer
来获取Bags of words特征
。
基于sklearn获取Bags of words特征
的python代码
# 原始语料,3个文本
strs_train =[
'God is love',
'OpenGL on the GPU is fast',
'Doctor David is PHD']
# 提取特征
from sklearn.feature_extraction.text import CountVectorizer
count_vect = CountVectorizer()
X_train_counts = count_vect.fit_transform(strs_train)
X_train_counts.shape
# 查看数值特征
X_train_counts.todense()#转换成数值特征Bags of words
# 查看特征名
count_vect.vocabulary_#特征名
用代码计算得到的特征与理论统计得到的特征完全相同
TF
即词频
(Term Frequency)。Bags of words特征
统计的是单词的出现次数,这样在长文本中,单词的出现次数会大于短文本,可能造成不公平问题。所以TF特征
就被提出,用于统计词频。
TF=(某个单词在文本中的出现次数)/(文本中的总单词数)。
根据TF
的计算公式,可得TF特征
如下。
TF特征
样本 | david | doctor | fast | god | gpu | is | love | on | opengl | phd | the |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | 0 | 0.33 | 0 | 0.33 | 0.33 | 0 | 0 | 0 | 0 |
2 | 0 | 0 | 0.17 | 0 | 0.17 | 0.17 | 0 | 0.17 | 0.17 | 0 | 0.17 |
3 | 0.25 | 0.25 | 0 | 0 | 0 | 0.25 | 0 | 0 | 0 | 0.25 | 0 |
我们也可以用sklearn
中的sklearn.feature_extraction.text.TfidfTransformer
来获取TF特征
。
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer
# 先提取 Bags of words特征
count_vect = CountVectorizer()
X_train_counts = count_vect.fit_transform(strs_train)
# 再基于Bags of words特征,变换为TF特征
tf_transformer = TfidfTransformer(use_idf=False).fit(X_train_counts)
X_train_tf = tf_transformer.transform(X_train_counts)
X_train_tf.shape
# 查看数值特征
X_train_tf.todense()#转换成数值特征Bags of words
# 查看特征名
count_vect.vocabulary_#特征名
经计算,我们发现,代码算得到的特征与理论公式计算得到的特征数值不相同!!
这是什么情况呢?经查看sklearn
的源码。发现sklearn
计算TF的方式与理论公式不一致,它只对Bags of words特征
矩阵做了Normalization
,就将结果作为TF特征
。如果在计算TF特征
时,去掉Normalization
(代码TfidfTransformer(norm=None, use_idf=False).fit(X_train_counts)
),如下,就得到了与Bags of words特征
完全相同的结果。
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer
# 先提取 Bags of words特征
count_vect = CountVectorizer()
X_train_counts = count_vect.fit_transform(strs_train)
# 再基于Bags of words特征,变换为TF特征
tf_transformer = TfidfTransformer(norm=None, use_idf=False).fit(X_train_counts)
X_train_tf = tf_transformer.transform(X_train_counts)
X_train_tf.shape
# 查看数值特征
X_train_tf.todense()#转换成数值特征Bags of words
# 查看特征名
count_vect.vocabulary_#特征名
仔细想想sklearn
的做法也没有问题,TF特征
的提出,不就是为了去除文档大小对结果的影响吗。Normalization
不也能达到同样效果么。
并且我们这里也要明白,TF的是可以有不同的定义的,本文给出的是理论上用的最多的计算公式。但sklearn
计算TF就用了其他的方法。一些常用的TF定义见这里。
IDF
是逆文档频率
。逆文档频率 = log(语料中的文档总数/含有该词的文档数加1)。得到逆文档频率
后,TF-IDF = TF*IDF。
TF-IDF特征
样本 | david | doctor | fast | god | gpu | is | love | on | opengl | phd | the |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | 0 | 0.33*log(1.5) | 0 | 0.33*log(0.75) | 0.33*log(1.5) | 0 | 0 | 0 | 0 |
2 | 0 | 0 | 0.17*log(1.5) | 0 | 0.17*log(1.5) | 0.17*log(1.5) | 0 | 0.17*log(1.5) | 0.17*log(0.75) | 0 | 0.17*log(1.5) |
3 | 0.25*log(1.5) | 0.25*log(1.5) | 0 | 0 | 0 | 0.25*log(0.75) | 0 | 0 | 0 | 0.25*log(1.5) | 0 |
我们也可以用sklearn
中的sklearn.feature_extraction.text.TfidfTransformer
来获取TF-IDF特征
。
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer
# 先提取 Bags of words特征
count_vect = CountVectorizer()
X_train_counts = count_vect.fit_transform(strs_train)
# 再基于Bags of words特征,变换为TF-IDF特征
tfidf_transformer = TfidfTransformer()
X_train_tfidf = tfidf_transformer.fit_transform(X_train_counts)
X_train_tfidf.todense()
同理,sklearn
计算TF-IDF特征
的方法也和本文的理论公式有所区别,并且最终还对计算结果做了Normalization
。具体细节见源码注释。
FeatureHasher
能将string通过Hash算法Murmurhash3
,变为数值化的矩阵。
在使用FeatureHasher
前,需要将原始语料的字符格式变为如下格式。
[{'God': 1, 'is': 1, 'love': 1},
{'GPU': 1, 'OpenGL': 1, 'fast': 1, 'is': 1, 'on': 1, 'the': 1},
{'David': 1, 'Doctor': 1, 'PHD': 1, 'is': 1}]
完整代码如下:
from sklearn.feature_extraction import FeatureHasher
# 将原始数据Hash到10维Feature
h = FeatureHasher(n_features=10, non_negative=True)
# 将数据组成D格式
D=[]
for s in strs_train:
tmp = {}
for w in s.split(' '):
tmp[w] = 1
D.append(tmp)
f = h.transform(D)
f.toarray()
FeatureHasher
特征
样本 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | x10 |
---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
2 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 |
3 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 |
对于文本、字符串数据,我们有4种常用方法(Bags of words
,TF
,TF-IDF
,FeatureHasher
),将原始数据变为数值型数据。
本文例子所有源码参见Github。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。