图片说明

使用sklearn实现TF-IDF特征计算

  1. 文本数据预处理:sklearn 中 CountVectorizer、TfidfTransformer 和 TfidfVectorizer
    文本数据预处理的第一步通常是进行分词,分词后会进行向量化的操作。在介绍向量化之前,我们先来了解下词袋模型。

1.词袋模型(Bag of words,简称 BoW )

词袋模型假设我们不考虑文本中词与词之间的上下文关系,仅仅只考虑所有词的权重。而权重与词在文本中出现的频率有关。

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

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

词袋模型有很大的局限性,因为它仅仅考虑了词频,没有考虑上下文的关系,因此会丢失一部分文本的语义。

在词袋模型统计词频的时候,可以使用 sklearn 中的 CountVectorizer 来完成。下面具体说明。

2.词频向量化

CountVectorizer 类会将文本中的词语转换为词频矩阵,例如矩阵中包含一个元素a[i][j],它表示j词在i类文本下的词频。它通过 fit_transform 函数计算各个词语出现的次数,通过get_feature_names()可获取词袋中所有文本的关键字,通过 toarray()可看到词频矩阵的结果。

官方文件中提到其参数很多默认值就很好,无需再改动,详细参数设置参见:点击打开链接。例子如下:

from sklearn.feature_extraction.text import CountVectorizer


corpus = [      'This is the first document.',
            'This is the second second document.',
            'And the third one.',
        'Is this the first document?',
        ]

vectorizer = CountVectorizer(min_df=1)
X = vectorizer.fit_transform(corpus)
feature_name = vectorizer.get_feature_names()
print (X)
print (feature_name)
print (X.toarray())

输出结果:

   (0, 1)        1
  (0, 2)        1
  (0, 6)        1
  (0, 3)        1
  (0, 8)        1
  (1, 5)        2
  (1, 1)        1
  (1, 6)        1
  (1, 3)        1
  (1, 8)        1
  (2, 4)        1
  (2, 7)        1
  (2, 0)        1
  (2, 6)        1
  (3, 1)        1
  (3, 2)        1
  (3, 6)        1
  (3, 3)        1
  (3, 8)        1
['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this']
[[0 1 1 ..., 1 0 1]
 [0 1 0 ..., 1 0 1]
 [1 0 0 ..., 1 1 0]
 [0 1 1 ..., 1 0 1]]

解释一下:
在输出中,左边的括号中的第一个数字是文本的序号i,第2个数字是词的序号j,注意词的序号是基于所有的文档的。第三个数字就是我们的词频。

可以看到一共有9个词,所以4个文本对应的都是9维的特征向量。

由于大部分文本都只会用词汇表中很少一部分的词,因此词向量中有大量的0,也就是说词向量是稀疏的。因此在实际应用中一般使用稀疏矩阵来存储。

3.TF-IDF处理

然而有些词在文本中尽管词频高,但是并不重要,这个时候就可以用TF-IDF技术。
某一特定文件内的高词语频率,以及该词语在整个文件集合中的低文件频率,可以产生出高权重的TF-IDF。因此,TF-IDF倾向于过滤掉常见的词语,保留重要的词语。

4.用sklearn进行TF-IDF预处理

第一种方法是在用 CountVectorizer 类向量化之后再调用 TfidfTransformer 类进行预处理。第二种方法是直接用TfidfVectorizer完成向量化与TF-IDF预处理。

4.1 CountVectorizer 结合 TfidfTransformer

依旧用上面的文本,实现如下:

from sklearn.feature_extraction.text import TfidfTransformer 
from sklearn.feature_extraction.text import CountVectorizer 


corpus = [          'This is the first document.',
        'This is the second second document.',
        'And the third one.',
        'Is this the first document?',
        ]


vectorizer=CountVectorizer()
transformer = TfidfTransformer()
tfidf = transformer.fit_transform(vectorizer.fit_transform(corpus)) 
weight = tfidf.toarray()
print(tfidf)
print('==========================================================')
print (weight)

#weight就是模型的输入,它的大小(m,n),m是文本个数,n是词库的大小

输出结果:

  (0, 8)        0.438776742859
  (0, 3)        0.438776742859
  (0, 6)        0.358728738248
  (0, 2)        0.541976569726
  (0, 1)        0.438776742859
  (1, 8)        0.272301467523
  (1, 3)        0.272301467523
  (1, 6)        0.222624292325
  (1, 1)        0.272301467523
  (1, 5)        0.853225736145
  (2, 6)        0.28847674875
  (2, 0)        0.552805319991
  (2, 7)        0.552805319991
  (2, 4)        0.552805319991
  (3, 8)        0.438776742859
  (3, 3)        0.438776742859
  (3, 6)        0.358728738248
  (3, 2)        0.541976569726
  (3, 1)        0.438776742859
==========================================================
[[0.         0.43877674 0.54197657 0.43877674 0.         0.
  0.35872874 0.         0.43877674]
 [0.         0.27230147 0.         0.27230147 0.         0.85322574
  0.22262429 0.         0.27230147]
 [0.55280532 0.         0.         0.         0.55280532 0.
  0.28847675 0.55280532 0.        ]
 [0.         0.43877674 0.54197657 0.43877674 0.         0.
  0.35872874 0.         0.43877674]]

4.2 用 TfidfVectorizer

实现代码如下:

from sklearn.feature_extraction.text import TfidfVectorizer

corpus = [       'This is the first document.',
        'This is the second second document.',
        'And the third one.',
        'Is this the first document?',
        ]

tfidf2 = TfidfVectorizer()
re = tfidf2.fit_transform(corpus)
print (re)

输出:

  (0, 8)        0.438776742859
  (0, 3)        0.438776742859
  (0, 6)        0.358728738248
  (0, 2)        0.541976569726
  (0, 1)        0.438776742859
  (1, 8)        0.272301467523
  (1, 3)        0.272301467523
  (1, 6)        0.222624292325
  (1, 1)        0.272301467523
  (1, 5)        0.853225736145
  (2, 6)        0.28847674875
  (2, 0)        0.552805319991
  (2, 7)        0.552805319991
  (2, 4)        0.552805319991
  (3, 8)        0.438776742859
  (3, 3)        0.438776742859
  (3, 6)        0.358728738248
  (3, 2)        0.541976569726
  (3, 1)        0.438776742859

总结一下:
TfidfVectorizer类和TfidfTransformer

vectorizer=CountVectorizer()
transformer=TfidfTransformer()
tfidf=transformer.fit_transform(vectorizer.fit_transform(corpus))

等价于:

transformer=TfidfVectorizer()
tfidf2=transformer.fit_transform(corpus)

利用TF-IDF提取文本特征,XGBoost文本分类实战演练

# -*- coding: utf-8 -*-
import xgboost as xgb
import csv
import jieba
#jieba.load_userdict('wordDict.txt')
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer


# 读取训练集
def readtrain(path):
    with open(path, 'rt',encoding='utf8') as csvfile:
        reader = csv.reader(csvfile)
        column1 = [row for row in reader]
    content_train = [i[1] for i in column1] # 第一列为文本内容,并去除列名
    opinion_train = [int(i[0])-1 for i in column1] # 第二列为类别,并去除列名
    print '训练集有 %s 条句子' % len(content_train)
    train = [content_train, opinion_train]
    return train

def stop_words():
    stop_words_file = open('stop_words_ch.txt', 'r',encoding='utf8')
    stopwords_list = []
    for line in stop_words_file.readlines():
        stopwords_list.append(line[:-1])
    return stopwords_list

# 对列表进行分词并用空格连接
def segmentWord(cont):
    stopwords_list = stop_words()
    c = []
    for i in cont:
        text = ""
        word_list = list(jieba.cut(i, cut_all=False))
        for word in word_list:
            if word not in stopwords_list and word != '\r\n':
                text += word
                text += ' '
        c.append(text)
    return c

def segmentWord1(cont):
    c = []
    for i in cont:
        a = list(jieba.cut(i))
        b = " ".join(a)
        c.append(b)
    return c

train = readtrain('data/training.csv')
train_content = segmentWord1(train[0])
train_opinion = np.array(train[1])     # 需要numpy格式
print "train data load finished"
test = readtrain('data/testing.csv')
test_content = segmentWord(test[0])
print 'test data load finished'

#train_content是一个列表,每个元素是每条文本分词之后用空格连接的

vectorizer = CountVectorizer()
tfidftransformer = TfidfTransformer()
tfidf = tfidftransformer.fit_transform(vectorizer.fit_transform(train_content))
weight = tfidf.toarray()
print tfidf.shape
test_tfidf = tfidftransformer.transform(vectorizer.transform(test_content))
test_weight = test_tfidf.toarray()
print test_weight.shape


dtrain = xgb.DMatrix(weight, label=train_opinion)
dtest = xgb.DMatrix(test_weight)  # label可以不要,此处需要是为了测试效果
param = {'max_depth':6, 'eta':0.5, 'eval_metric':'merror', 'silent':1, 'objective':'multi:softmax', 'num_class':11}  # 参数
evallist  = [(dtrain,'train')]  # 这步可以不要,用于测试效果
num_round = 100  # 循环次数
bst = xgb.train(param, dtrain, num_round, evallist)
preds = bst.predict(dtest)
with open('XGBOOST_OUTPUT.csv', 'w') as f:
    for i, pre in enumerate(preds):
        f.write(str(i + 1))
        f.write(',')
        f.write(str(int(pre) + 1))
        f.write('\n')

参考链接
Sklearn TFIDF中文计算问题以及解决方法
文本数据预处理:sklearn 中 CountVectorizer、TfidfTransformer 和 TfidfVectorizer
文本分类实战--从TFIDF到深度学习(附代码)