小学期04

实验名称

逻辑回归用于讽刺文本检测

实验目的

  • 了解训练分类模型的基本原理;
  • 掌握模型解释及模型改进人流程;
  • 熟悉讽刺文本检测的逻辑回归方法;

实验背景

逻辑回归是统计学中经典的分类方法,是一种判别学习模型。本实验旨在解决网络评论中的讽刺性信 息。因此,本节实验针对这一现象,提出了一种基于逻辑回归用于讽刺文本检测模型,提取页面文字的 特征为样本进行词法分析。以词频和加权的方法,再通过分类逻辑回归模型进行分类,来甄别该页面是 否存在讽刺性内容。

实验原理

一、数据可视化探索

首先,使用条形图可视化讽刺和正常文本长度,这里利用 np.log1p 对数据进行平滑处理,压缩到一定 区间范围内。接下来,挑战需要利用 WordCloud 绘制讽刺文本和正常文本关键词词云图。然后计算出 不同子板块评论的总数。由于讽刺评论的标签为 1,正常评论为 0,所以通过 sum 求和操作就可以直接 求出讽刺评论的计数。同理,mean 即代表讽刺评论所占比例。

二、逻辑回归模型分类

接下来,我们训练讽刺评论分类预测模型。这里,我们使用 tf-idf 提取文本特征,并建立逻辑回归模 型。开始训练模型,我们可以发现,讽刺评论通常都喜欢使用 yes, clearly 等带有肯定意味的词句。接下 来,我们期望模型能得到进一步改进,所以再补充一个 subreddit 特征,同样完成切分。注意,这里 切分时一定要选择同一个 random_state,保证能和上面的评论数据对齐。改进后分类结果准确率应该 更高些。

实验步骤

一、环境准备

本实验在jupyter notebook进行开发。

二、代码编写

1、准备数据
本次挑战使用论文 A Large Self-Annotated Corpus for Sarcasm 提供的语料数据。
2、导包

#导入相关包 
import os 
import numpy as np 
import pandas as pd 
from sklearn.feature_extraction.text import TfidfVectorizer 
#导入逻辑回归包 
from sklearn.linear_model import LogisticRegression 
from sklearn.pipeline import Pipeline 
from sklearn.model_selection import train_test_split 
from sklearn.metrics import accuracy_score, confusion_matrix 
import seaborn as sns 
from matplotlib import pyplot as plt 
#导入警告过滤包 
import warnings 
warnings.filterwarnings('ignore')

然后,加载语料并预览。

train_df = pd.read_csv('train-balanced-sarcasm.csv') 
train_df.head()
labelcommentauthorsubredditscoreupsdownsdatecreated_utcparent_comment
00NC and NH.Trumpbartpolitics2-1-12016-102016-10-16 23:55:23Yeah, I get that argument. At this point, I'd ...
10You do know west teams play against west teams...Shbshb906nba-4-1-12016-112016-11-01 00:24:10The blazers and Mavericks (The wests 5 and 6 s...
20They were underdogs earlier today, but since G...Creepethnfl3302016-092016-09-22 21:45:37They're favored to win.
30This meme isn't funny none of the "new york ni...icebrothaBlackPeopleTwitter-8-1-12016-102016-10-18 21:03:47deadass don't kill my buzz
40I could use one of those tools.cush2pushMaddenUltimateTeam6-1-12016-122016-12-30 17:00:13Yep can confirm I saw the tool they use for th...

查看数据集变量类别信息。

train_df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1010826 entries, 0 to 1010825
Data columns (total 10 columns):
label             1010826 non-null int64
comment           1010773 non-null object
author            1010826 non-null object
subreddit         1010826 non-null object
score             1010826 non-null int64
ups               1010826 non-null int64
downs             1010826 non-null int64
date              1010826 non-null object
created_utc       1010826 non-null object
parent_comment    1010826 non-null object
dtypes: int64(4), object(6)
memory usage: 77.1+ MB

comment的数量小于其他特征数量,说明存在缺失值。这里直接将这些缺失数据样本删除

train_df.dropna(subset=['comment'], inplace=True)

输出数据标签,看一看类别是否平衡

train_df['label'].value_counts()
0    505405
1    505368
Name: label, dtype: int64

最后,将数据切分为训练和测试集

train_texts, valid_texts, y_train, y_valid = train_test_split(train_df['comment'], train_df['label'], random_state=17)

3、数据可视化探索

首先,使用条形图可视化讽刺和正常文本长度,这里利用 np.log1p 对数据进行平滑处理,压缩到一定 区间范围内。

#讽刺文本平滑压缩处理 train_df.loc[train_df['label'] == 1, 'comment'].str.len().apply( np.log1p).hist(label='sarcastic', alpha=.5)#正常文本平滑压缩处理 train_df.loc[train_df['label'] == 0, 'comment'].str.len().apply( np.log1p).hist(label='normal', alpha=.5)plt.legend()
<matplotlib.legend.Legend at 0x2010ecd5860>

在这里插入图片描述

可以看的,二者在不同长度区间范围(横坐标)的计数分布比较均匀。接下来,挑战需要利用 WordCloud 绘制讽刺文本和正常文本关键词词云图。

问题:参考 WordCloud 官方文档绘制两类评论文本词云图,可自定义样式效果

#导入词云包 from wordcloud import WordCloud, STOPWORDS#设置背景颜色是黑色,设置停用词为STOPWORDS,设置背景图片,设置最大现实字数2000,设置字体最大值 150,设置有30种随机生成状态,界面宽大小为400,高大小为800 wordcloud = WordCloud(background_color='black', stopwords=STOPWORDS, max_words=200, max_font_size=100, random_state=17, width=800, height=400)#图片输出尺寸设置 plt.figure(figsize=(16, 12)) #生成词云并注释为1 wordcloud.generate(str(train_df.loc[train_df['label'] == 1, 'comment'])) #显示词云 plt.imshow(wordcloud)
<matplotlib.image.AxesImage at 0x2010e99fbe0>

在这里插入图片描述

#图片输出尺寸设置 plt.figure(figsize=(16, 12)) #生成词云并注释为0 wordcloud.generate(str(train_df.loc[train_df['label'] == 0, 'comment'])) #显示词云 plt.imshow(wordcloud)
<matplotlib.image.AxesImage at 0x2010ebc9898>

在这里插入图片描述

词云非常好看,但往往看不出太多有效信息。

subreddit表示评论归属于 Reddit 论坛子板块信息。下面,我们使用 groupby 来确定各子板块讽刺评 论数量排序。

#计算出评论板块正常评论数,讽刺评论比例和讽刺评论数 sub_df = train_df.groupby('subreddit')['label'].agg([np.size, np.mean, np.sum]) #取出讽刺评论区前10 sub_df.sort_values(by='sum', ascending=False).head(10)
sizemeansum
subreddit
AskReddit656740.40145326365
politics394930.60534823907
worldnews263760.64251616947
leagueoflegends210340.54231211407
pcmasterrace189870.56665110759
news168910.60345710193
funny179390.4514748099
pics161520.4843367823
todayilearned141590.5475677753
GlobalOffensive137380.5520457584

上面的代码中,np.size可以计算出不同子板块评论的总数。由于讽刺评论的标签为 1,正常评论为 0, 所以通过 sum求和操作就可以直接求出讽刺评论的计数。同理,mean即代表讽刺评论所占比例。这是 一个分析处理小技巧。

问题:沿用以上数据,输出子板块评论数大于 1000 且讽刺评论比例排名前 10 的信息。下面我们使用 代码:

#取出评论数大于 1000 且讽刺评论比例排名前 10 的信息 sub_df[sub_df['size'] > 1000].sort_values(by='mean', ascending=False).head(10)
sizemeansum
subreddit
creepyPMs54660.7843034287
MensRights33550.6807752284
ShitRedditSays12840.661994850
worldnews263760.64251616947
Libertarian25620.6401251640
atheism73770.6395554718
Conservative18810.6395531203
TwoXChromosomes15600.632692987
fatlogic23560.6230901468
facepalm12680.617508783

同理,可以从用户的维度去分析讽刺评论的比例分布。下面就需要分析得出不同用户 author发表评论的 数量、讽刺评论的数量及比例。

问题:输出发表评论总数大于 300,且讽刺评论比例最高的 10 位用户信息。下面我们使用代码:

#计算出评论板块正常评论数,讽刺评论比例和讽刺评论数 sub_df = train_df.groupby('author')['label'].agg([np.size, np.mean, np.sum]) #取出评论数大于 300 且讽刺评论比例排名前 10 的信息 sub_df[sub_df['size'] > 300].sort_values(by='mean', ascending=False).head(10)
sizemeansum
author
NeonDisease4220.500000211
ShyBiDude894040.500000202
ivsciguy3420.500000171
mad-n-fla3180.500000159
mindlessrabble3020.500000151
pokemon_fetish4320.500000216
Biffingston8450.499408422

3、训练分类模型

接下来,我们训练讽刺评论分类预测模型。这里,我们使用 tf-idf 提取文本特征,并建立逻辑回归模 型。

# 使用 tf-idf 提取文本特征 tf_idf = TfidfVectorizer(ngram_range=(1, 2), max_features=50000, min_df=2) # 建立逻辑回归模型 logit = LogisticRegression(C=1, n_jobs=4, solver='lbfgs', random_state=17, verbose=1)# 使用 sklearn pipeline 封装 2 个步骤 ttfidf_logit_pipeline = Pipeline([('tf_idf', tf_idf), ('logit', logit)])

下面就可以开始训练模型了。由于数据量较大,代码执行时间较长,请耐心等待。

问题:训练讽刺文本分类预测模型,并得到测试集上的准确度评估结果。下面我们使用代码

#拟合训练模型 tfidf_logit_pipeline.fit(train_texts, y_train)#逻辑回归预测 valid_pred = tfidf_logit_pipeline.predict(valid_texts) #准确打分 accuracy_score(y_valid, valid_pred)
[Parallel(n_jobs=4)]: Using backend LokyBackend with 4 concurrent workers.[Parallel(n_jobs=4)]: Done   1 out of   1 | elapsed:   11.5s finished





0.7209866478824191

4、模型解释

接下来,挑战构建一个混淆矩阵的函数 plot_confusion_matrix。

#构建混淆矩阵函数(实际,预测,类别,不归一化,设置标题,设置图片大小,输出相近颜色,保存路径) def plot_confusion_matrix(actual, predicted, classes, normalize=False, title='Confusion matrix', figsize=(7, 7), cmap=plt.cm.Blues, path_to_save_fig=None):    #导入迭代函数     import itertools     #导入混淆矩阵函数     from sklearn.metrics import confusion_matrix     #导入实际和预测过的结果     cm = confusion_matrix(actual, predicted).T    if normalize:#如果归一化         cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]#转为浮点型并归一化        plt.figure(figsize=figsize)#生成图片     plt.imshow(cm, interpolation='nearest', cmap=cmap)#显示预测结果图片     plt.title(title)#设置标题     plt.colorbar()#设置颜色条     tick_marks = np.arange(len(classes))#从头到尾返回标记序列     plt.xticks(tick_marks, classes, rotation=90)#返回X坐标位置并旋转90度     plt.yticks(tick_marks, classes)#返回Y坐标位置        fmt = '.2f' if normalize else 'd'#归一化保留两位小数,否则是整型     thresh = cm.max() / 2.#取最大值的一半    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):        plt.text(j, i, format(cm[i, j], fmt), horizontalalignment="center",color="white" if cm[i, j] > thresh else "black")#输出图形信息,格式 化,水平对齐,颜色配置    plt.tight_layout()     plt.ylabel('Predicted label')#预测标签     plt.xlabel('True label')#真实标签        if path_to_save_fig:#图像保存         plt.savefig(path_to_save_fig, dpi=300, bbox_inches='tight')

应用 plot_confusion_matrix绘制出测试数据原始标签和预测标签类别的混淆矩阵。

#绘制出测试数据原始标签和预测标签类别的混淆矩阵 plot_confusion_matrix(y_valid, valid_pred, tfidf_logit_pipeline.named_steps['logit'].classes_,figsize=(8, 8))

在这里插入图片描述

实际上,这里利用 eli5 可以输出分类器在预测判定是文本特征的权重。下面我们使用eli5包并输出文 本特征权重:

先在终端输入:

import eli5 #输出文本特征权重 eli5.show_weights(estimator=tfidf_logit_pipeline.named_steps['logit'], vec=tfidf_logit_pipeline.named_steps['tf_idf'])

在这里插入图片描述

我们可以发现,讽刺评论通常都喜欢使用 yes, clearly 等带有肯定意味的词句。

5、模型改进

接下来,我们期望模型能得到进一步改进,所以再补充一个 subreddit特征,同样完成切分。注意,这 里切分时一定要选择同一个 random_state,保证能和上面的评论数据对齐。

subreddits = train_df['subreddit'] #保证能和上面的评论数据对齐 train_subreddits, valid_subreddits = train_test_split( subreddits, random_state=17)

接下来,同样使用 tf-idf 算法分别构建 2 个 TfidfVectorizer用于 comment和 subreddits的特征提取。

#特征参数设置 tf_idf_texts = TfidfVectorizer( ngram_range=(1, 2), max_features=50000, min_df=2)#构建子目录 tf_idf_subreddits = TfidfVectorizer(ngram_range=(1, 1))

问题:使用构建好的 TfidfVectorizer完成特征提取。下面我们使用代码:

#提取文本特征 X_train_texts = tf_idf_texts.fit_transform(train_texts) X_valid_texts = tf_idf_texts.transform(valid_texts) X_train_texts.shape, X_valid_texts.shape
((758079, 50000), (252694, 50000))
#提取子目录特征 X_train_subreddits = tf_idf_subreddits.fit_transform(train_subreddits) X_valid_subreddits = tf_idf_subreddits.transform(valid_subreddits) X_train_subreddits.shape, X_valid_subreddits.shape
((758079, 13255), (252694, 13255))

然后,将提取出来的特征拼接在一起。

from scipy.sparse import hstack #将训练文本特征与训练子目录特征拼接起来 X_train = hstack([X_train_texts, X_train_subreddits]) #将有效文本特征与有效子目录特征拼接起来 X_valid = hstack([X_valid_texts, X_valid_subreddits])X_train.shape, X_valid.shape
((758079, 63255), (252694, 63255))

最后,同样使用逻辑回归进行建模和预测。

问题:使用新特征训练逻辑回归分类模型并得到测试集上的分类准确度。下面我们使用代码:

#逻辑回归训练 logit.fit(X_train, y_train) #逻辑回归预测 valid_pred = logit.predict(X_valid) #打分结果 .accuracy_score(y_valid, valid_pred)
[Parallel(n_jobs=4)]: Using backend LokyBackend with 4 concurrent workers.[Parallel(n_jobs=4)]: Done   1 out of   1 | elapsed:   20.1s finished





0.7237805408913548

实验总结

以上我们介绍了使用条形图可视化讽刺和正常文本长度,挑战需要利用 WordCloud 绘制讽刺文本和正 常文本关键词词云图。然后计算出不同子板块评论的总数,同理,mean 即代表讽刺评论所占比例。我 们训练讽刺评论分类预测模型,使用 tf-idf 提取文本特征,并建立逻辑回归模型,训练模型,发现讽刺评 论通常都喜欢使用 yes, clearly 等带有肯定意味的词句。模型改进,再补充一个subreddit 特征,同样完成切分,保证能和上面的评论数据对齐,改进后分类结果准确率应该更高些。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值