fork from Datawhale零基础入门NLP赛事 - Task3 基于机器学习的文本分类

在上一章节,我们对赛题的数据进行了读取,并在末尾给出了两个小作业。如果你顺利完成了作业,那么你基本上对Python也比较熟悉了。在本章我们将使用传统机器学习算法来完成新闻分类的过程,将会结束到赛题的核心知识点。

Task3 基于机器学习的文本分类

在本章我们将开始使用机器学习模型来解决文本分类。机器学习发展比较广,且包括多个分支,本章侧重使用传统机器学习,从下一章开始是基于深度学习的文本分类。

学习目标

  • 学会TF-IDF的原理和使用
  • 使用sklearn的机器学习模型完成文本分类

机器学习模型

机器学习是对能通过经验自动改进的计算机算法的研究。机器学习通过历史数据训练模型对应于人类对经验进行归纳的过程,机器学习利用模型对新数据进行预测对应于人类利用总结的规律对新问题进行预测的过程。

机器学习有很多种分支,对于学习者来说应该优先掌握机器学习算法的分类,然后再其中一种机器学习算法进行学习。由于机器学习算法的分支和细节实在是太多,所以如果你一开始就被细节迷住了眼,你就很难知道全局是什么情况的。

如果你是机器学习初学者,你应该知道如下的事情:

  1. 机器学习能解决一定的问题,但不能奢求机器学习是万能的;
  2. 机器学习算法有很多种,看具体问题需要什么,再来进行选择;
  3. 每种机器学习算法有一定的偏好,需要具体问题具体分析;

文本表示方法 Part1

在机器学习算法的训练过程中,假设给定 N N N个样本,每个样本有 M M M个特征,这样组成了 N × M N×M N×M的样本矩阵,然后完成算法的训练和预测。同样的在计算机视觉中可以将图片的像素看作特征,每张图片看作hight×width×3的特征图,一个三维的矩阵来进入计算机进行计算。

但是在自然语言领域,上述方法却不可行:文本是不定长度的。文本表示成计算机能够运算的数字或向量的方法一般称为词嵌入(Word Embedding)方法。词嵌入将不定长的文本转换到定长的空间内,是文本分类的第一步。

One-hot

这里的One-hot与数据挖掘任务中的操作是一致的,即将每一个单词使用一个离散的向量表示。具体将每个字/词编码一个索引,然后根据索引进行赋值。

One-hot表示方法的例子如下:

句子1:我 爱 北 京 天 安 门
句子2:我 喜 欢 上 海

首先对所有句子的字进行索引,即将每个字确定一个编号:

{
	'我': 1, '爱': 2, '北': 3, '京': 4, '天': 5,
  '安': 6, '门': 7, '喜': 8, '欢': 9, '上': 10, '海': 11
}

在这里共包括11个字,因此每个字可以转换为一个11维度稀疏向量:

我:[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
爱:[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
...
海:[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
Bag of Words

Bag of Words(词袋表示),也称为Count Vectors,每个文档的字/词可以使用其出现次数来进行表示。

句子1:我 爱 北 京 天 安 门
句子2:我 喜 欢 上 海

直接统计每个字出现的次数,并进行赋值:

句子1:我 爱 北 京 天 安 门
转换为 [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]

句子2:我 喜 欢 上 海
转换为 [1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1]

在sklearn中可以直接CountVectorizer来实现这一步骤:

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_transform(corpus).toarray()
N-gram

N-gram与Count Vectors类似,不过加入了相邻单词组合成为新的单词,并进行计数。

如果N取值为2,则句子1和句子2就变为:

句子1:我爱 爱北 北京 京天 天安 安门
句子2:我喜 喜欢 欢上 上海
TF-IDF

TF-IDF 分数由两部分组成:第一部分是词语频率(Term Frequency),第二部分是逆文档频率(Inverse Document Frequency)。其中计算语料库中文档总数除以含有该词语的文档数量,然后再取对数就是逆文档频率。

TF(t)= 该词语在当前文档出现的次数 / 当前文档中词语的总数
IDF(t)= log_e(文档总数 / 出现该词语的文档总数)

基于机器学习的文本分类

接下来我们将对比不同文本表示算法的精度,通过本地构建验证集计算F1得分。

# Count Vectors + RidgeClassifier

import pandas as pd

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.linear_model import RidgeClassifier
from sklearn.metrics import f1_score
from sklearn.metrics import classification_report

train_df = pd.read_csv('./data/train_set.csv', sep='\t')

vectorizer = CountVectorizer(max_features=3000)#词袋模型
train_test = vectorizer.fit_transform(train_df['text'])#对字符训练

clf = RidgeClassifier()#岭回归器
clf.fit(train_test[:10000], train_df['label'].values[:10000])#训练

val_pred = clf.predict(train_test[10000:])#预测
print(classification_report(train_df['label'].values[10000:], val_pred))
print(f1_score(train_df['label'].values[10000:], val_pred, average='macro'))#f1宏平均
# 0.74
              precision    recall  f1-score   support

           0       0.75      0.84      0.79     37033
           1       0.73      0.89      0.80     35079
           2       0.90      0.92      0.91     29864
           3       0.81      0.81      0.81     21055
           4       0.72      0.73      0.73     14228
           5       0.78      0.63      0.70     11613
           6       0.91      0.73      0.81      9480
           7       0.83      0.59      0.69      8415
           8       0.83      0.55      0.66      7432
           9       0.84      0.65      0.73      5568
          10       0.89      0.72      0.80      4678
          11       0.79      0.54      0.64      2967
          12       0.94      0.60      0.73      1733
          13       0.82      0.57      0.68       855

    accuracy                           0.79    190000
   macro avg       0.82      0.70      0.75    190000
weighted avg       0.80      0.79      0.79    190000

0.7484250637618726
# TF-IDF +  RidgeClassifier

import pandas as pd

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import RidgeClassifier
from sklearn.metrics import f1_score

train_df = pd.read_csv('./data/train_set.csv', sep='\t')

tfidf = TfidfVectorizer(ngram_range=(1,3), max_features=3000)
train_test = tfidf.fit_transform(train_df['text'])

clf = RidgeClassifier()
clf.fit(train_test[:10000], train_df['label'].values[:10000])

val_pred = clf.predict(train_test[10000:])
print(classification_report(train_df['label'].values[10000:], val_pred))
print(f1_score(train_df['label'].values[10000:], val_pred, average='macro'))
# 0.87
              precision    recall  f1-score   support

           0       0.91      0.90      0.90     37033
           1       0.88      0.94      0.91     35079
           2       0.97      0.98      0.97     29864
           3       0.91      0.94      0.92     21055
           4       0.86      0.88      0.87     14228
           5       0.84      0.85      0.84     11613
           6       0.91      0.91      0.91      9480
           7       0.88      0.74      0.80      8415
           8       0.91      0.84      0.87      7432
           9       0.89      0.82      0.85      5568
          10       0.93      0.85      0.89      4678
          11       0.89      0.76      0.82      2967
          12       0.93      0.77      0.84      1733
          13       0.92      0.75      0.83       855

    accuracy                           0.90    190000
   macro avg       0.90      0.85      0.87    190000
weighted avg       0.90      0.90      0.90    190000

0.8745827044933814

本章小结

本章我们介绍了基于机器学习的文本分类方法,并完成了两种方法的对比。

本章作业

  1. 尝试改变TF-IDF的参数,并验证精度
  2. 尝试使用其他机器学习模型,完成训练和验证
# 1尝试改变TF-IDF的参数,并验证精度
# TF-IDF +  RidgeClassifier
# 利用贝叶斯调参

import pandas as pd
from bayes_opt import BayesianOptimization
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import RidgeClassifier
from sklearn.metrics import f1_score
train_df = pd.read_csv('./data/train_set.csv', sep='\t')
def rf_cv(ngram, max_features,alpha,tol):
    tfidf = TfidfVectorizer(ngram_range=(1,3), max_features=3000)
    train_test = tfidf.fit_transform(train_df['text'])

    clf = RidgeClassifier(alpha=alpha,tol=tol)
    clf.fit(train_test[:10000], train_df['label'].values[:10000])

    val_pred = clf.predict(train_test[10000:])
#     print(classification_report(train_df['label'].values[10000:], val_pred))
    return f1_score(train_df['label'].values[10000:], val_pred, average='macro')
# 0.87

from sklearn.linear_model import RidgeClassifier
rf_bo = BayesianOptimization(
    rf_cv,
    {
    'ngram': (2, 6),
    'max_features': (1000, 4000),
    'alpha':(0.3,3),
    'tol':(1e-6,1e-4)
    }
)
rf_bo.maximize()
|   iter    |  target   |   alpha   | max_fe... |   ngram   |    tol    |
-------------------------------------------------------------------------
| [0m 1       [0m | [0m 0.8681  [0m | [0m 2.152   [0m | [0m 3.863e+0[0m | [0m 2.425   [0m | [0m 8.535e-0[0m |
| [0m 2       [0m | [0m 0.8676  [0m | [0m 2.236   [0m | [0m 1.183e+0[0m | [0m 2.257   [0m | [0m 4.641e-0[0m |
| [0m 3       [0m | [0m 0.8641  [0m | [0m 2.88    [0m | [0m 3.894e+0[0m | [0m 4.485   [0m | [0m 6.543e-0[0m |
| [95m 4       [0m | [95m 0.8704  [0m | [95m 1.733   [0m | [95m 2.539e+0[0m | [95m 4.611   [0m | [95m 9.839e-0[0m |
| [95m 5       [0m | [95m 0.8763  [0m | [95m 0.6628  [0m | [95m 1.005e+0[0m | [95m 2.541   [0m | [95m 7.756e-0[0m |
| [95m 6       [0m | [95m 0.8776  [0m | [95m 0.3359  [0m | [95m 3.259e+0[0m | [95m 2.017   [0m | [95m 2.942e-0[0m |
| [0m 7       [0m | [0m 0.8635  [0m | [0m 2.97    [0m | [0m 3.122e+0[0m | [0m 5.947   [0m | [0m 7.861e-0[0m |
| [0m 8       [0m | [0m 0.8774  [0m | [0m 0.3933  [0m | [0m 1.947e+0[0m | [0m 2.107   [0m | [0m 8.47e-05[0m |
| [0m 9       [0m | [0m 0.8642  [0m | [0m 2.78    [0m | [0m 3.556e+0[0m | [0m 5.997   [0m | [0m 3.017e-0[0m |
| [95m 10      [0m | [95m 0.8776  [0m | [95m 0.3197  [0m | [95m 2.223e+0[0m | [95m 2.013   [0m | [95m 6.675e-0[0m |
| [0m 11      [0m | [0m 0.8772  [0m | [0m 0.4339  [0m | [0m 1.612e+0[0m | [0m 2.042   [0m | [0m 8.894e-0[0m |
| [0m 12      [0m | [0m 0.8776  [0m | [0m 0.344   [0m | [0m 1.768e+0[0m | [0m 2.018   [0m | [0m 1.034e-0[0m |
| [0m 13      [0m | [0m 0.8776  [0m | [0m 0.3253  [0m | [0m 2.375e+0[0m | [0m 2.049   [0m | [0m 5.766e-0[0m |
| [0m 14      [0m | [0m 0.8772  [0m | [0m 0.4575  [0m | [0m 3.997e+0[0m | [0m 2.134   [0m | [0m 1.636e-0[0m |
| [0m 15      [0m | [0m 0.8776  [0m | [0m 0.3355  [0m | [0m 3.352e+0[0m | [0m 2.011   [0m | [0m 6.579e-0[0m |
| [0m 16      [0m | [0m 0.8774  [0m | [0m 0.3935  [0m | [0m 2.093e+0[0m | [0m 2.065   [0m | [0m 7.945e-0[0m |
| [0m 17      [0m | [0m 0.864   [0m | [0m 2.899   [0m | [0m 1.745e+0[0m | [0m 2.037   [0m | [0m 2.221e-0[0m |
| [95m 18      [0m | [95m 0.8777  [0m | [95m 0.3     [0m | [95m 2.805e+0[0m | [95m 2.0     [0m | [95m 2.626e-0[0m |
| [0m 19      [0m | [0m 0.8776  [0m | [0m 0.3476  [0m | [0m 1.398e+0[0m | [0m 2.151   [0m | [0m 3.866e-0[0m |
| [0m 20      [0m | [0m 0.8777  [0m | [0m 0.3602  [0m | [0m 1.495e+0[0m | [0m 5.837   [0m | [0m 2.872e-0[0m |
| [0m 21      [0m | [0m 0.8776  [0m | [0m 0.3745  [0m | [0m 2.679e+0[0m | [0m 2.148   [0m | [0m 2.122e-0[0m |
| [95m 22      [0m | [95m 0.8778  [0m | [95m 0.312   [0m | [95m 1.502e+0[0m | [95m 2.081   [0m | [95m 8.752e-0[0m |
| [0m 23      [0m | [0m 0.8777  [0m | [0m 0.3133  [0m | [0m 2.923e+0[0m | [0m 2.076   [0m | [0m 4.092e-0[0m |
| [0m 24      [0m | [0m 0.8776  [0m | [0m 0.3244  [0m | [0m 1.006e+0[0m | [0m 5.775   [0m | [0m 3.082e-0[0m |
| [0m 25      [0m | [0m 0.8777  [0m | [0m 0.305   [0m | [0m 2.02e+03[0m | [0m 2.071   [0m | [0m 1.161e-0[0m |
| [0m 26      [0m | [0m 0.8776  [0m | [0m 0.3288  [0m | [0m 3.441e+0[0m | [0m 2.019   [0m | [0m 3.737e-0[0m |
| [0m 27      [0m | [0m 0.8776  [0m | [0m 0.3396  [0m | [0m 2.292e+0[0m | [0m 2.057   [0m | [0m 4.863e-0[0m |
| [0m 28      [0m | [0m 0.8776  [0m | [0m 0.3205  [0m | [0m 2.785e+0[0m | [0m 2.033   [0m | [0m 5.407e-0[0m |
| [0m 29      [0m | [0m 0.8776  [0m | [0m 0.3174  [0m | [0m 4e+03   [0m | [0m 2.044   [0m | [0m 2.684e-0[0m |
| [0m 30      [0m | [0m 0.8777  [0m | [0m 0.3037  [0m | [0m 1.462e+0[0m | [0m 2.294   [0m | [0m 8.832e-0[0m |
=========================================================================
# 2.尝试使用其他机器学习模型,完成训练和验证
# TF-IDF +  RidgeClassifier
from sklearn.linear_model import LinearRegression
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.neural_network import MLPRegressor
from xgboost.sklearn import XGBRegressor
from lightgbm.sklearn import LGBMRegressor
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics import f1_score
from sklearn.model_selection import cross_val_score
train_df = pd.read_csv('./data/train_set.csv', sep='\t')
tfidf = TfidfVectorizer(ngram_range=(1,3), max_features=3000)
train_test = tfidf.fit_transform(train_df['text'])
result = dict()

# models = [LinearRegression(),
#           DecisionTreeRegressor(),
#           RandomForestRegressor(),
#           GradientBoostingRegressor(),
#           MLPRegressor(solver='lbfgs', max_iter=100), 
#           XGBRegressor(n_estimators = 100, objective='reg:squarederror'), 
#           LGBMRegressor(n_estimators = 100)]

model = XGBRegressor(n_estimators = 100,objective='multi:softmax',num_class=14)
model.fit(X=train_test[:10000], y=train_df['label'].values[:10000])
val_pred = model.predict(train_test[10000:])
print( f1_score(train_df['label'].values[10000:], val_pred, average='macro'))
# for model in models:
#     model_name = str(model).split('(')[0]
# #     scores = cross_val_score(model, X=train_test[:10000], y=train_df['label'].values[:10000], verbose=0, cv = 5, scoring='f1_macro')
#     model.fit(X=train_test[:10000], y=train_df['label'].values[:10000])
#     val_pred = model.predict(train_test[10000:])
#     result[model_name] = f1_score(train_df['label'].values[10000:], val_pred, average='macro')
#     print(model_name + ' is finished')
# result = pd.DataFrame(result)
# result.index = ['cv' + str(x) for x in range(1, 6)]
# result
    

0.8760199049877919

由于训练时间比较长,所以只采用xgboost进行训练

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值