自然语言处理中的fastText模型应用

在当今信息爆炸的时代,大约80%的信息是非结构化的,而文本数据是其中最常见的一种。由于其混乱的特性,分析、理解、组织和排序文本信息成为了复杂且耗时的任务。自然语言处理(NLP)和文本分类技术在此背景下应运而生。文本分类是一种机器学习技术,它能够将文本自动分类到不同的类别中。企业可以利用分类器模型自动结构化各种文本,如电子邮件、法律文件、社交媒体帖子、聊天机器人消息、调查结果等,从而节省分析信息的时间,自动化业务流程,并做出数据驱动的业务决策。

加载fastText库

import pandas as pd import fasttext from sklearn.model_selection import train_test_split import re from gensim.parsing.preprocessing import STOPWORDS from gensim.parsing.preprocessing import remove_stopwords pd.options.display.max_colwidth = 1000

项目数据

数据集是一系列新闻文章标题及其讽刺(来自新闻媒体“The Onion”)和非讽刺(来自“HuffPost”)的注释。数据集链接:https://www.kaggle.com/rmisra/news-headlines-dataset-for-sarcasm-detection

数据变量包括:

  • is_sarcastic: 如果标题是讽刺的,则为1,否则为0
  • headline: 新闻文章标题
  • article_link: 原始文章链接

加载数据并检查变量和观测值的数量:

df_headline.shape # (26709, 3) df_headline.head(3) df_headline.is_sarcastic.value_counts() 0 14985 1 11724 df_headline.is_sarcastic.value_counts(normalize=True) 0 0.561047 1 0.438953

以下是一些讽刺和非讽刺标题的例子:

df_headline[df_headline['is_sarcastic']==1].head(3) df_headline[df_headline['is_sarcastic']==0].head(3)

文本预处理

为了提高模型性能,首先进行简单的文本预处理是至关重要的。在开始构建分类器之前,需要准备文本:将所有单词转换为小写,去除标点符号、特殊字符和数字。为此,让创建一个清理函数并将其应用于标题变量。

def clean_text(text): text = text.lower() text = re.sub(r'[^a-zA-Z0-9 @ []]', '', text) # 去除标点符号 text = re.sub(r' w * d + w *', '', text) # 去除数字 text = re.sub(' s {2,}', "", text) # 去除不必要的空格 return text df_headline['headline'] = df_headline['headline'].apply(clean_text)

数据分为训练和测试

在开始训练模型之前,需要按照以下方式分割数据。通常,80%的信息用于训练模型(根据数据量,样本大小可能会有所不同),20%用于测试(准确性验证)。

train, test = train_test_split(df_headline, test_size=0.2)

创建文本文件

接下来,需要准备txt格式的文件。默认文件格式应包括__label__。在数据集中,__label__0表示没有讽刺,但__label__1表示讽刺。

with open('train.txt', 'w') as f: for every_text, every_lbl in zip(train['headline'], train['is_sarcastic']): f.writelines(f '__label__ {every_lbl} {every_text} \n') with open('test.txt', 'w') as f: for every_text, every_lbl in zip(test['headline'], test['is_sarcastic']): f.writelines(f '__label__ {every_lbl} {every_text} \n')

使用fastText构建模型

要训练模型,需要设置fastText的输入文件及其名称:

model1 = fasttext.train_supervised('train.txt') def print_results(sample_size, precision, recall): precision = round(precision, 2) recall = round(recall, 2) print(f'{sample_size=}') print(f'{precision=}') print(f'{recall=}') print_results(*model1.test('test.txt')) sample_size=5342 precision=0.85 recall=0.85

结果虽然不是完美的,但看起来很有希望。

优化fastText的超参数

手动寻找最佳超参数可能会很耗时。默认情况下,fastText模型在训练过程中每个训练样本只包含五次,考虑到数据集中只有12,000个样本,这个数字相当小。可以通过手动优化epoch来增加每个样本的查看次数(也称为epoch):

model2 = fasttext.train_supervised('train.txt', epoch=25) print_results(*model2.test('test.txt')) sample_size=5342 precision=0.83 recall=0.83

正如看到的,模型的准确性并没有提高。改变过程速度的另一种方法是增加(或减少)算法的学习率。这对应于模型在处理每个样本后的变化量。学习率为0意味着模型根本不会变化,因此不会学到任何东西。好的学习率范围在0.1-1.0之间。也可以手动优化这个超参数,使用参数lr:

model3 = fasttext.train_supervised('train.txt', epoch=10, lr=1.0) print_results(*model3.test('test.txt')) sample_size=5342 precision=0.83 recall=0.83

最后,可以通过使用词的二元组而不是仅仅使用单个字来提高模型的性能。这在分类任务中尤为重要,例如分析情感、定义批评、讽刺等,其中词序很重要。为此,将在模型中包含一个参数wordNgrams等于2。

model4 = fasttext.train_supervised('train.txt', epoch=10, lr=1.0, wordNgrams=2) print_results(*model4.test('test.txt')) sample_size=5342 precision=0.86 recall=0.86

通过这一系列的步骤,能够将准确性从86%提高:

  • 文本预处理;
  • 改变epoch的数量(使用参数epoch,标准范围[5-50]);
  • 改变学习率(使用参数lr,标准范围[0.1-1.0]);
  • 使用词的n-gram(使用参数wordNgrams,标准范围[1-5])。

还可以通过添加参数autotune Metric通过评估特定标签来适应超参数的搜索:

model5 = fasttext.train_supervised('train.txt', autotuneValidationFile='test.txt') print_results(*model5.test('test.txt')) sample_size=5342 precision=0.87 recall=0.87

fastText自动调整功能优化超参数以获得最高的F1。为此,需要包含模型参数autotune ValidationFile和测试数据集:

model6 = fasttext.train_supervised('train.txt', autotuneValidationFile='test.txt', autotuneMetric="f1:__label__1") print_results(*model6.test('test.txt')) sample_size=5342 precision=0.87 recall=0.87

让保存模型结果并创建一个函数来对新数据进行分类:

model6.save_model('optimized.model') model.quantize(input='train.txt', retrain=True)

fastText还能够压缩模型以产生一个更小的文件,通过量化牺牲很少的性能。

还可以模拟新数据并测试模型对真实标题的效果。这将使用Kaggle上的新闻聚合数据集:https://www.kaggle.com/uciml/news-aggregator-dataset

df_headline_test = pd.read_csv('uci-news-aggregator.csv') df_headline_test.TITLE.head(3)

让对新标题应用文本分类函数,并创建具有预测标签及其概率的变量:

df_headline_test['TITLE'] = df_headline_test['TITLE'].apply(clean_text) def predict_sarcasm(text): return model.predict(text, k=1) df_headline_test['predict_score'] = df_headline_test.TITLE.apply(predict_sarcasm) df_headline_test['predict_score'] = df_headline_test['predict_score'].astype(str) df_headline_test[['label','probability']] = df_headline_test.predict_score.str.split(" ",expand=True) df_headline_test['label'] = df_headline_test['label'].str.replace("(", '') df_headline_test['label'] = df_headline_test['label'].str.replace(")", '') df_headline_test['label'] = df_headline_test['label'].str.replace("__", ' ') df_headline_test['label'] = df_headline_test['label'].str.replace(",", '') df_headline_test['label'] = df_headline_test['label'].str.replace("'", '') df_headline_test['label'] = df_headline_test['label'].str.replace("label", '') df_headline_test['probability'] = df_headline_test['probability'].str.replace("array", '') df_headline_test['probability'] = df_headline_test['probability'].str.replace("(", '') df_headline_test['probability'] = df_headline_test['probability'].str.replace(")", '') df_headline_test['probability'] = df_headline_test['probability'].str.replace("[", '') df_headline_test['probability'] = df_headline_test['probability'].str.replace("]", '') df_headline_test = df_headline_test.drop(columns=['predict_score']) df_headline_test.label.value_counts(normalize=True)

输出结果:

0 0.710827 1 0.289173
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485