XGBoost 实现文本分类与sklearn NLP库TfidfVectorizer

2021-12-23 00:31:12 浏览数 (3)

1. 背景

在文本分类任务中经常使用XGBoost快速建立baseline,在处理文本数据时需要引入TFIDF将文本转换成基于词频的向量才能输入到XGBoost进行分类。这篇博客将简单阐述XGB进行文本分类的实现与部分原理。

2. 实现

代码语言:txt复制
import pandas as pd
import xgboost as xgb
import jieba
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn import metrics
from sklearn.model_selection import train_test_split
from matplotlib import pyplot

def word_seg(x):
    content = str(x['a'])   ' '   str(x['b'])
    for i in string.punctuation   ''.join([r'N', 't', 'n', '(', ')', ',', '。', ':', '】', '【']):
        content = content.replace(i, '')
    return ' '.join(jieba.lcut(content))
train_data = pd.read_csv('./data/train.csv')
train_data['content'] = train_data.apply(word_seg, axis=1)

x_train, x_test, y_train, y_test = train_test_split(train_data['content'], train_data['label'], test_size=0.2)
# 将语料转化为词袋向量,根据词袋向量统计TF-IDF
vectorizer = CountVectorizer(max_features=5000)
tf_idf_transformer = TfidfTransformer()
tf_idf = tf_idf_transformer.fit_transform(vectorizer.fit_transform(x_train))
x_train_weight = tf_idf.toarray()  # 训练集TF-IDF权重矩阵
tf_idf = tf_idf_transformer.transform(vectorizer.transform(x_test))
x_test_weight = tf_idf.toarray()  # 测试集TF-IDF权重矩阵

#基于Scikit-learn接口的分类
# 训练模型
eval_set = [(x_train_weight, y_train), (x_test_weight, y_test)]
model = xgb.XGBClassifier(max_depth=6, learning_rate=0.1, n_estimators=60, objective='binary:logistic')
model.fit(x_train_weight, y_train, eval_set=eval_set, verbose=True)
y_predict = model.predict(x_test_weight)

results = model.evals_result()
results
epochs = len(results['validation_0']['logloss'])
x_axis = range(0, epochs)
# plot log loss
fig, ax = pyplot.subplots()
ax.plot(x_axis, results['validation_0']['logloss'], label='Train')
ax.plot(x_axis, results['validation_1']['logloss'], label='Test')
ax.legend()
pyplot.ylabel('Log Loss')
pyplot.title('XGBoost Log Loss')
pyplot.show()
代码语言:txt复制
#利用训练完的模型直接测试
# xgb_model = xgb.Booster(model_file='data/xgb_model')  # init model #加载模型
# dtest = xgb.DMatrix('data/test.buffer')  #加载数据
# xgb_test(dtest,xgb_model)


# y_predict = model.predict(dtest)  # 模型预测
label_all = [0, 1]
confusion_mat = metrics.confusion_matrix(y_test, y_predict)
df = pd.DataFrame(confusion_mat, columns=label_all)
df.index = label_all
print('准确率:n', metrics.accuracy_score(y_test, y_predict))
print('confusion_matrix: n', df)
print('分类报告: n', metrics.classification_report(y_test, y_predict))
print('AUC: %.4f' % metrics.roc_auc_score(y_test, y_predict))
代码语言:txt复制
准确率:
 0.9730405840669959
confusion_matrix: 
        0      1
0  48544      0
1   2511  42085
分类报告: 
               precision    recall  f1-score   support

           0       0.95      1.00      0.97     48544
           1       1.00      0.94      0.97     44596

    accuracy                           0.97     93140
   macro avg       0.98      0.97      0.97     93140
weighted avg       0.97      0.97      0.97     93140

AUC: 0.9718

3. TfidfVectorizer原理

这里简单介绍下scikit-learn自然语言文本处理的一个开源方法——TfidfVectorizer,该方法分别是由两种方法 CountVectorizer 与 TfidfTransformer 的结合,下面进行说明,说明之前给出三个文档链接(本文基本翻译自官方文档):

(文档在手天下我有,有问题看文档)

方法一:TfidfVectorizer 方法二:CountVectorizer、TfidfTransformer

好了进入正文

TfidfVectorizer 处理文本语言的主要中心思想也就是 TF-IDF (词频-逆文档频率),由于本篇文章的重点是介绍该模块,所以不过多对 TF-IDF 说明,有需要的这里给出之前写的比较详细的文章可以参考——TF-IDF及相关知识

TfidfVectorizer 的使用相当于先调用了 CountVectorizer 方法,然后再调用 TfidfTransformer 方法,所以想了解 TfidfVectorizer 还得从后面两个方法说起。

CountVectorizer:

功能:

将文本文档集合转换为计数的稀疏矩阵。内部的实现方法为调用scipy.sparse.csr_matrix模块。并且,如果在调用CountVectorizer() 时不提供先验词典并且不使用执行某种特征选择的分析器,则特征词的数量将等于通过该方法直接分析数据找到的词汇量。

代码说明:

代码语言:txt复制
from sklearn.feature_extraction.text import CountVectorizer

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

vectorizer = CountVectorizer()		# ()这里不提供先验词典
# vectorizer.fit(corpus)			# 先fit训练传入的文本数据
# X = vectorizer.transform(corpus)		# 然后对文本数据进行标记并转换为稀疏计数矩阵
X = vectorizer.fit_transform(corpus)		# 可以fit、transform一起使用替代上面的两行

print(vectorizer.get_feature_names())	# 获得模型直接分析数据找到的词汇量(上面单词的集合)
print(X.toarray())	# 直接打印X输出的是每个词的位置
代码语言:txt复制
['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this']

[[0 1 1 1 0 0 1 0 1]        # 4行 数据样本
 [0 2 0 1 0 1 1 0 1]        # 9列 特征单词
 [1 0 0 1 1 0 1 1 1]
 [0 1 1 1 0 0 1 0 1]]

参数简单说明:

以上为最简单的 CountVectorizer 模块的使用,我们几乎没有使用任何的参数和方法,但依然能达到一个较好的【文本—>词向量稀疏矩阵 】的效果,部分参数如下。

input : string {‘filename’, ‘file’, ‘content’}

encoding : string, ‘utf-8’ by default.

stop_words : string {‘english’}, list, or None (default)

max_df : float in range 0.0, 1.0 or int, default=1.0

min_df : float in range 0.0, 1.0 or int, default=1

max_features : int or None, default=None

TfidfTransformer:

功能:

将计数矩阵(如上图所示)转换为标准化的 tf 或 tf-idf 表示。Tf 表示术语频率,而tf-idf表示术语频率乘以逆文档频率。这是信息检索中常用的术语加权方案,在文档分类中也有很好的用途。用于计算项的 tf-idf 的公式是 tf-idf(d,t)= tf(t)* idf(d,t)。

代码说明:

代码语言:txt复制
from sklearn.feature_extraction.text import TfidfTransformer

transform = TfidfTransformer()    # 使用TF-IDF(词频、逆文档频率)应用于稀疏矩阵
Y = transform.fit_transform(X)    # 使用上面CountVectorizer处理后的 X 数据
print(Y.toarray())                # 输出转换为tf-idf后的 Y 矩阵,同样直接打印 Y 输出每个数据的位置
print(vectorizer.get_feature_names())    # 打印特征名
代码语言:txt复制
[[0.         0.46979139 0.58028582 0.38408524 0.         0.
  0.38408524 0.         0.38408524]
 [0.         0.6876236  0.         0.28108867 0.         0.53864762
  0.28108867 0.         0.28108867]
 [0.51184851 0.         0.         0.26710379 0.51184851 0.
  0.26710379 0.51184851 0.26710379]
 [0.         0.46979139 0.58028582 0.38408524 0.         0.
  0.38408524 0.         0.38408524]]
['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this']

参数简单说明:

以上为直接使用 TfidfTransformer 转换 CountVectorizer 处理后的计数矩阵为标准化的 tf-idf 矩阵【词向量稀疏矩阵—>标准化tf-idf】的效果,下面给出其部分参数。

norm : ‘l1’, ‘l2’ or None, optional

    Norm used to normalize term vectors. None for no normalization.

use_idf : boolean, default=True

    Enable inverse-document-frequency reweighting.

smooth_idf : boolean, default=True

    Smooth idf weights by adding one to document frequencies, as if an extra document was seen containing every term in the collection exactly once. Prevents zero divisions.

sublinear_tf : boolean, default=False

    Apply sublinear tf scaling, i.e. replace tf with 1 log(tf).

最后可以简单的描述下TfidfVectorizer了

TfidfVectorizer

功能:

前文说过 TfidfVectorizer 相当于两者的结合使用,先后调用 CountVectorizer 和 TfidfTransformer 两种方法(简化了代码,但运算思想还是不变),并且参数的使用基本一致。

代码说明:

代码语言:txt复制
from sklearn.feature_extraction.text import TfidfVectorizer

VT = TfidfVectorizer()		# 先后调用CountVectorizer和TfidfTransformer两种方法(简化了代码,但运算思想还是不变)
result = VT.fit_transform(corpus)
print(result.toarray())
print(VT.get_feature_names())
代码语言:txt复制
[[0.         0.46979139 0.58028582 0.38408524 0.         0.
  0.38408524 0.         0.38408524]
 [0.         0.6876236  0.         0.28108867 0.         0.53864762
  0.28108867 0.         0.28108867]
 [0.51184851 0.         0.         0.26710379 0.51184851 0.
  0.26710379 0.51184851 0.26710379]
 [0.         0.46979139 0.58028582 0.38408524 0.         0.
  0.38408524 0.         0.38408524]]
['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this']

可以看到与上面 CountVectorizer 和 TfidfTransformer 处理后的结果一致,确实为两者的结合使用。

参数及使用方法与 CountVectorizer和TfidfTransformer 一致,这里不再描述。

0 人点赞