文本TF-IDF特征获取方法及文本向量化方法

 

一 获取文本的TF-IDF特征
1. 文本向量化特征的不足
    在将文本分词并向量化后,我们可以得到词汇表中每个词在各个文本中形成的词向量,比如在文本挖掘预处理之向量化与Hash Trick这篇文章中,我们将下面4个短文本做了词频统计:

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”] 
    不考虑停用词,处理后得到的词向量如下:

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

2. TF-IDF概述
  TF-IDF是Term Frequency –  Inverse Document Frequency的缩写,即“词频-逆文本频率”。它由两部分组成,TF和IDF。

  前面的TF也就是我们前面说到的词频,我们之前做的向量化也就是做了文本中各个词的出现频率统计,并作为文本特征,这个很好理解。关键是后面的这个IDF,即“逆文本频率”如何理解。在上一节中,我们讲到几乎所有文本都会出现的”to”其词频虽然高,但是重要性却应该比词频低的”China”和“Travel”要低。我们的IDF就是来帮助我们来反应这个词的重要性的,进而修正仅仅用词频表示的词特征值。

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

上面是从定性上说明的IDF的作用,那么如何对一个词的IDF进行定量分析呢?这里直接给出一个词x 的IDF的基本公式如下

                                                         IDF(x)=logN/N(x)

其中,N 代表语料库中文本的总数,而N(x) 代表语料库中包含词x 的文本总数。

  上面的IDF公式已经可以使用了,但是在一些特殊的情况会有一些小问题,比如某一个生僻词在语料库中没有,这样我们的分母为0, IDF没有意义了。所以常用的IDF我们需要做一些平滑,使语料库中没有出现的词也可以得到一个合适的IDF值。平滑的方法有很多种,最常见的IDF平滑后的公式之一为:

                                                        IDF(x)=log(N/(N(x)+1)) + 1

       有了IDF的定义,我们就可以计算某一个词的TF-IDF值了:

                                                         TF−IDF(x)=TF(x)∗IDF(x)

  其中TF(x) 指词x 在当前文本中的词频。

参考:http://www.cnblogs.com/pinard/p/6693230.html

3 测试代码
import numpy as np
import gensim
import time
import pickle
import csv, sys
from sklearn.feature_extraction.text import TfidfVectorizer
# #将原始数据数字化为tfidf特征
start_time = time.time()
#数据预处理
trainData = pd.read_csv(‘./new_data/train_set.csv’)
testData = pd.read_csv(‘./new_data/test_set.csv’)

#删掉训练数据集及测试数据集的“article”列
trainData.drop(columns=’article’, inplace=True)
testData.drop(columns=’article’, inplace=True)
print(trainData.shape) #(102277, 3)
print(testData.shape)  #(102277, 2)
print(trainData.head(500)) #查看前500行数据

allData = pd.concat(objs=[trainData, testData], axis=0, sort=True)
print(allData.shape)

# print(allData[trainData.shape[0]:10])
y_train = (trainData[‘class’] – 1).values  #DataFrame->np.ndarray
#特征工程
#TfidVectorlizer()可以将原始文本转为tf-idf的特征矩阵,从而为后续的文本相似度计算,主题模型及文本搜索排序等一系列应用奠定基础
vectorizer = TfidfVectorizer(ngram_range=(1,2), min_df=3, max_df=0.9, sublinear_tf=True)
#计算每个词出现的次数
tra = trainData[‘word_seg’]
features = vectorizer.fit_transform(tra[0:1000]) #得到tf-idf矩阵,稀疏矩阵表示
features = features.todense()  #tf-idf矩阵的稠密表示
print(features.shape, features[0, :100])

(1000, 40627)
 [[0.         0.         0.         0.         0.         0.
  0.         0.         0.01575517 0.         0.         0.
  0.         0.         0.         0.         0.         0.
  0.         0.         0.         0.         0.         0.
  0.         0.         0.03137093 0.         0.         0.
  0.         0.         0.         0.         0.         0.
  0.         0.         0.         0.         0.         0.
  0.         0.         0.         0.         0.         0.
  0.         0.         0.         0.         0.         0.
  0.         0.         0.         0.         0.         0.
  0.         0.         0.         0.         0.         0.
  0.         0.         0.         0.         0.         0.
  0.         0.         0.         0.         0.         0.
  0.         0.         0.         0.         0.         0.
  0.         0.         0.         0.         0.         0.
  0.         0.         0.         0.         0.         0.
  0.         0.         0.         0.        ]]

words = vectorizer.get_feature_names() #获取词袋中所有文本关键词
print(len(words))  #40627
print(‘word: ‘, words)
words:  [‘1000015’, ‘1000015 520477’, ‘1000087’, ‘1000230’, ‘1000246’, ‘100026’, ‘100026 520477’, ‘1000457’, ‘1000483’, ‘1000483 1033823’, ‘1000483 1062461’, ‘1000483 110494’, ‘1000483 1157817’, ‘1000483 1174272’, ‘1000483 1181092’, ‘1000483 1263122’, ‘1000483 133940’,…] 

for i in range(1000):
    for j in range(len(words)):
        if features[i, j] >1e-5:
            print(words[j], features[i, j])
end_time = time.time() print(‘预处理将原始特征转为tfidf特征耗费时间:{}min’.format((end_time – start_time)/60))

 
二 词嵌入向量

词嵌入向量就是将每个词汇用相应的词向量表示出来

start_time = time.time()

dataPath = ‘E:/Jupyter/ML_algorithm/DAGUAN/data_set/’
featurePath =  ‘E:/Jupyter/ML_algorithm/DAGUAN/feature/’
probaPath = ‘E:/Jupyter/ML_algorithm/DAGUAN/proba/’
modelPath = ‘E:/Jupyter/ML_algorithm/DAGUAN/model/’
resultPath = ‘E:/Jupyter/ML_algorithm/DAGUAN/result/’
end_time = time.time()

#获取训练数据
trainData = pd.read_csv(dataPath + ‘train_set.csv’)
# testData = pd.read_csv(dataPath + ‘test_set.csv’)
sentencesTrain = list(trainData.loc[:, ‘word_seg’].apply(sentence2list))
# sentencesTest = list(testData.loc[:, ‘word_seg’].apply(sentence2list))
sentences = sentencesTrain #+ sentencesTest
print(len(sentences[:1000]))
#训练开始
#构造一个Gensim内建的word2vec模型的对象(即将原始的one-hot向量转化为word2vec向量),这里可以指定模型训练的参数,
# 例如采用的模型(skip-gram或CBoW),embedding向量的维度等。
print(‘开始训练’)
model = gensim.models.Word2Vec(sentences[:1000])
print(‘训练完成’)

#提取词汇表及vectors,并保存
wv = model.wv
vocab_list = wv.index2word
word_idx_dict = {}
for idx, word in enumerate(vocab_list):
    word_idx_dict[word] = idx
    print(word)
提取的词汇表:
520477
816903
1033823
995362
920327
834740
460600
54111
1226448
1025743
990423
526298
766772
441513
655201

#获取词对应的向量矩阵,每个词用hidden_size=100维的向量表示
vector_arr = wv.vectors
#vector_arr = np.concatenate((np.zeros(vector_size)[np.newaxis, :], vector_arr), axis=0)
print(vector_arr[-1, :])

[-5.58310188e-03 -1.62638258e-02  2.74756309e-02  3.25317569e-02
  4.47434448e-02 -9.84906312e-03  3.46671492e-02  2.54789870e-02
 -2.62763264e-04 -5.54048922e-04  1.03918938e-02 -3.79535370e-02
 -1.12973852e-02  1.53128905e-02 -3.15685011e-02  2.94700284e-02
 -8.49447176e-02  1.61190964e-02 -1.02630975e-02  1.42310970e-02
 -1.98065601e-02  3.56848352e-02  1.20295258e-02  8.43964517e-03
 -2.65352000e-02  2.82944273e-03 -1.21877473e-02  1.72928050e-02
  1.92776248e-02 -1.30845362e-03  4.31248080e-03 -1.97703298e-02
  8.30913149e-03  1.88934673e-02  1.51997106e-02 -2.96001835e-03
 -3.83375189e-03 -2.25680731e-02 -1.21829780e-02 -1.10103028e-04
 -2.56033409e-02 -3.41300340e-03 -1.56783294e-02 -2.37424430e-02
 -1.46737155e-02 -5.22687696e-02 -3.21379937e-02 -1.24334302e-02
  1.21471304e-02  9.21720173e-03  1.16867227e-02  5.27860969e-03
  1.47960708e-02 -2.46758778e-02  2.96511538e-02 -1.23530487e-03
  1.35757693e-03  7.17068836e-03 -4.32422245e-03 -2.35857558e-03
 -4.76549603e-02 -2.87641361e-02  2.48347558e-02  1.04202039e-03
  1.73103604e-02 -1.86920278e-02  1.80483088e-02  1.41925672e-02
 -3.06954291e-02  5.58880670e-03 -1.55242654e-02 -5.74624049e-04
 -3.40817347e-02 -6.03811955e-03 -1.77477871e-03  6.75395876e-03
 -1.96221471e-03 -5.21902554e-02 -4.21170564e-03 -5.12500387e-03
  1.49128065e-02 -3.51021551e-02 -2.78988741e-02  1.69550255e-02
 -1.06061203e-02 -5.41857304e-03  7.59190554e-03  8.93548969e-03
  1.24874795e-02  1.74063221e-02  3.11601907e-02  2.30186172e-02
  1.90577153e-02  3.00532920e-05 -1.71778332e-02  3.54922377e-02
 -2.72225812e-02 -1.71572098e-03 -1.81493734e-03  3.35018104e-03]

print(‘\n’)
#访问最后一个词汇对应的向量表示:
print(vector_arr[word_idx_dict[word], :])

保存模型
fw_wordidx = open(featurePath + ‘word_seg_word_idx_dict.pkl’, ‘wb’)
fw_vectors = open(featurePath + ‘word_seg_vectors_arr.pkl’, ‘wb’)

pickle.dump(word_idx_dict, fw_wordidx)
pickle.dump(vector_arr, fw_vectors)

fw_wordidx.close()
fw_vectors.close()

end_time = time.time()
print(‘耗时:{}s’.format(end_time-start_time))
 

点赞