NLP学习实践天池新人赛打卡第三天

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

文本表示方法 Part1

在机器学习算法的训练过程中,假设给定 N N N 个样本,每个样本有 M M M 个特征,这样组成了 N × M N×M N×M
的样本矩阵,然后完成算法的训练和预测。

但是在自然语言领域,上述方法却不可行:文本是不定长度的。文本表示成计算机能够运算的数字或向量的方法一般称为词嵌入(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]

缺点:每个单词的one-hot编码维度是整个词汇表的大小,维度非常巨大,编码稀疏,会使得计算代价变大。而且词与词之间没有相关性

Bag of Words

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

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

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

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

句子2:我 我 喜 欢 上 海
转换为 [2, 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()
array([[0, 1, 1, 1, 0, 0, 1, 0, 1],
       [0, 2, 0, 1, 0, 1, 1, 0, 1],
       [1, 0, 0, 1, 1, 0, 1, 1, 1],
       [0, 1, 1, 1, 0, 0, 1, 0, 1]], dtype=int64)

N-gram

N-gram与Count Vectors类似,不过加入了相邻单词组合成为新的单词,并进行计数
如果N取值为2,则句子1和句子2就变为:

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

详细的N-gram介绍可以看这篇博客自然语言处理NLP中的N-gram模型

TF-IDF

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

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

基于机器学习的文本分类

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

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

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(f1_score(train_df['label'].values[10000:], val_pred, average='macro'))
0.7414710556201648

使用全部数据的结果

import pandas as pd

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

# train_df = pd.read_csv('./train_set.csv', sep='\t', nrows=15000)
train_df = pd.read_csv('./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])
clf.fit(train_test[:150000], train_df['label'].values[:150000])

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

跑全部数据速度太慢,跑完差不多用了10分钟,还是先拿15000条跑着玩吧

0.814299885456091

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('./train_set.csv', sep='\t', nrows=15000)

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(f1_score(train_df['label'].values[10000:], val_pred, average='macro'))
0.8721598830546126

本章作业

  • 作业1:尝试改变TF-IDF的参数,并验证精度
  • 作业2:尝试使用其他机器学习模型,完成训练和验证

作业1

我们要调整的参数:

ngram_range:要提取的n-gram的n-values的下限和上限范围,在min_n <= n <= max_n区间的n的全部值。有时候我们觉得单个的词语作为特征还不足够,能够加入一些词组更好,就可以设置这个参数。ngram_range=(1, 3)表示统计三种类型的词:单个词,2个单词构成的词组,3个单词构成的词组。

max_features:用多少个单词构建词汇表,按语料词频排序。在大规模语料上训练TFIDF会得到非常多的词语,如果再使用了上一个设置加入了词组,那么我们词表的大小就会爆炸。出于时间和空间效率的考虑,可以限制最多使用多少个词语,模型会优先选取词频高的词语留下。

同样地,我们仅使用15000条训练样本来尝试

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('./train_set.csv', sep='\t', nrows=15000)
for i in range(1, 4):
    for j in [2000, 3000, 4000, 5000, 6000, 7000]:
        tfidf = TfidfVectorizer(ngram_range=(1, i), max_features=j)
        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(i, j, f1_score(train_df['label'].values[10000:], val_pred, average='macro'))
1 2000 0.8609053798476228
1 3000 0.858329649339088
1 4000 0.8601916764212559
1 5000 0.8603325900148268
1 6000 0.8603325900148268
1 7000 0.8603325900148268
2 2000 0.8584782097110735
2 3000 0.8719465729628795
2 4000 0.8794638920291346
2 5000 0.886402018449437
2 6000 0.8877841442863286
2 7000 0.8875087923712194
3 2000 0.8603842642428617
3 3000 0.8721598830546126
3 4000 0.8753945850878357
3 5000 0.8850817067811825
3 6000 0.8901406771892212
3 7000 0.8920634181410882
之后又补测了两组
4 5000 0.8849155025217313
4 6000 0.8884095725793182
4 7000 0.891603038208734
4 8000 0.8929861900360884
4 9000 0.891819829251606
5 5000 0.8853177666563177
5 6000 0.8890428095306815
5 7000 0.8899856202435279
5 8000 0.891256263020867
5 9000 0.8901292428375412

在这些参数里,可以看到ngram_range=(1,4),max_features=8000的结果是最好的

作业2

使用SVM和LR来进行训练和验证
SVM
这里使用的是SVC模型进行训练

import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn import svm
from sklearn.metrics import f1_score

train_df = pd.read_csv('./train_set.csv', sep='\t', nrows=15000)
tfidf = TfidfVectorizer(ngram_range=(1,4), max_features=8000)
train_test = tfidf.fit_transform(train_df['text'])
clf = svm.SVC(C=1.0, gamma=0.1)
clf.fit(train_test[:10000], train_df['label'].values[:10000])
val_pred = clf.predict(train_test[10000:])
print(f1_score(train_df['label'].values[10000:], val_pred, average='macro'))
0.8081017478499909

LR
使用LR进行训练

import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import f1_score

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

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

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

val_pred = clf.predict(train_test[10000:])
print(f1_score(train_df['label'].values[10000:], val_pred, average='macro'))
0.8806360528882696
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值