129在线民宿 UGC 数据挖掘实战--文本自动化标注和数据采样

文本自动化标注和数据采样

数据准备

首先使用 Pandas 加载在线数据表格,并查看数据维度和第一行数据。

import pandas as pd
data = pd.read_csv('https://labfile.oss.aliyuncs.com/courses/2628/1-2.csv')
print(data.shape)
data.head(1)

image.png

数据清洗
针对用户打分出现的问题进行处理,首先打印用户打分的去重数据

data['user_score'].unique()

我们发现用户打分出现了字符型数据,需要进行清理。

# 对字符型数据进行处理
data_clean = data[data.user_score != '信息不存在'].copy()

# 数据检查
data_clean['user_score'].unique()

用户打分数据标注
本实验通过有监督的训练用户情感分析模型,需要事先对语料进行标注。假设用户打分和用户情感极性一致,满足用户评论情感建模需求,可以对用户高于 3 分的评价标注为 1,否则为 0。

data_clean['label'] = data_clean['user_score'].apply(lambda x: 1
                                                     if float(x) > 3 else 0)

# 标签统计
data_clean['label'].groupby(data_clean['label']).count()

我们对语料标签进行条形图可视化,大致看出标签分布的差异。

import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline

# 定义画布大小
plt.rcParams['figure.figsize'] = (6.0, 6.0)

# 查看标签的分布情况
sns.countplot(data=data_clean, x='label')
plt.show()

通过标签占比图可清晰的看出标签数据分布上的差异,训练集上的数据失衡比例接近 10:1。

# 初始化饼图
plt.axes(aspect='equal')

# 标签聚合
counts = data_clean['label'].value_counts()

# 绘制饼图,设置百分比的格式,这里保留一位小数
plt.pie(x=counts,
        labels=pd.Series(
            counts.index).map({1: '1', 0: '0'}),
        autopct='%.2f%%')

# 显示图形
plt.show()

情感分析模型训练

依据统计学模型假设,假设用户评论中的词语之间相互独立,用户评价中的每一个词语都是一个特征,我们直接使用 TF-IDF 对用户评价提取特征,并对提取特征后的用户评价进行逻辑回归分类。
用户评论向量化
TF-IDF 是一种用于信息检索与数据挖掘的常用加权技术,常用于挖掘文章中的关键词,算法简单高效,当某个词在文章中的TF-IDF越大,那么这个词在这篇文章的重要性会越高,词频向量化只考虑每种词汇在该训练文本中出现的频率,而 TfidfVectorizer 除了考量某一词汇在当前训练文本中出现的频率之外,同时关注包含这个词汇的其它训练文本的出现情况。
本实验我们使用固定版本的 scikit-learn 以适应后期数据采样的需求。

!pip install scikit-learn==0.23.2
# 使用 TF-IDF 的方式对用户评论特征提取
from sklearn.feature_extraction.text import TfidfVectorizer

# 对测试集和训练集进行划分
from sklearn.model_selection import train_test_split

# 设置字典中词语的数量
max_dict_number = 3000
vectorizer = TfidfVectorizer(max_features=max_dict_number)

# 直接对分词后的用户评论进行特征提取
vectorizer.fit_transform(data_clean['text_cut'])

数据集合划分
按照训练集 8 成和测试集 2 成的比例对数据集进行划分,并检查划分之后的数据集数量。

# 开始数据划分
x_train_, y_train_, x_test, y_test = train_test_split(data_clean['text_cut'],
                                                      data_clean['label'],
                                                      test_size=0.2,
                                                      random_state=1)

# 通过建立起来的词典,开始对训练集和测试集合进行向量化
x_train = vectorizer.transform(x_train_)
y_train = vectorizer.transform(y_train_)

基准模型训练
逻辑回归(Logistic Regression)是一种用于解决二分类问题的机器学习方法,在线性回归的基础上,套用了一个 sigmod 函数,这个函数将线性结果映射到一个概率区间,并且通常以 0.5 分界线,这就使得数据的分类结果都趋向于在 0 和 1 两端,将用户评论进行向量化之后也可以用此方式预测用户情感。

from sklearn.linear_model import LogisticRegression
# 初始化逻辑回归模型
model_lr = LogisticRegression()

# 模型训练
%time model_lr.fit(x_train, x_test)
# 使用模型对测试集进行批量预测
normal_model_lr_result = model_lr.predict(y_train)

通过传入原始的标签和预测的标签可以直接将分类器性能进行度量,利用常用的分类模型评价指标对训练好的模型进行模型评价,accuracy_score 评价被正确预测的样本占总样本的比例,Precision 是衡量模型精确率的指标,它是指模型识别出的文档数与识别的文档总数的比率,衡量的是模型的查准率。Recall 召回率也称为敏感度,它是指模型识别出的相关文档数和文档库中所有的相关文档数的比率,衡量的是检索系统的查全率,表示正样本在被正确划分样本中所占的比例,f1_score 值是精确率与召回率的调和平均数,是一个综合性的指数。

from sklearn import metrics
# 使用列表收集测试结果
method, acc_list, f1_list = [], [], []

# 收集训练标签
method.append('normal')

# 收集 accuracy_score 分数
acc_list.append(metrics.accuracy_score(y_test, normal_model_lr_result))

# 收集 f1 分数
f1_list.append(metrics.f1_score(y_test, normal_model_lr_result))

数据采样

训练分类器中所使用的训练集的类别分布不均会导致模型在预测的时候带有很强烈的偏见,预测结果偏向数据量较多的一方。某类的样本数量很少,那么这个类别所提供的特征就不足以支撑模型的训练,对模型训练影响较大。一般解决标签失衡的解决方法主要有上采样和下采样,以下我们研究数据失衡对模型的影响。
首先安装 Imblearn ,它内置采样模块可以很好的处理数据比例失衡。

!pip install imblearn

随机上采样
过采样是补充那些数据量少的样本,使得不同标签的样本量达到均衡,原标签中 “0” 的标签最少,通过扩增之后达到了和“1” 标签相同的数量,本实验将使用随机复制类目较小的子类内容来达到数据平衡的目的,从采样结果来看,较少的一类得到的数据扩增。

# 使用imblearn进行随机过采样
from imblearn.over_sampling import RandomOverSampler

# 加载计数模块
from collections import Counter

# 设置随机种子为 1 , 使得每次采样结果相同
ros = RandomOverSampler(random_state=1)

# 开始对训练数据进行采样
X_ros_sampled, y_ros_sampled = ros.fit_resample(x_train, x_test)

# 查看采样结果
Counter(y_ros_sampled.values)

开始对随机上采样之后的数据进行训练情感分类模型,并统一对测试集进行预测。

# 加载 LogisticRegression 分类器
model_ros_sampled = LogisticRegression()

# 开始训练
%time model_ros_sampled.fit(X_ros_sampled, y_ros_sampled)

# 批量对测试集预测
model_ros_result = model_ros_sampled.predict(y_train)

对随机上采样训练集训练后的模型进行批量预测,并结果记录。

# 收集训练标签
method.append('ros')

# 收集 accuracy_score 分数
acc_list.append(metrics.accuracy_score(y_test, model_ros_result))

# 收集 f1 分数
f1_list.append(metrics.f1_score(y_test, model_ros_result))

SMOTE 采样
简单复制少数类样本形成多条记录的方式容易因为样本特征少而可能导致过拟合的问题。SMOTE 是基于“插值”来为少数类合成新的样本,通过 从 K 个近邻中随机挑选 N 个样本进行随机线性插值使得不同标签的样本量达到均衡,从采样结果来看,较少的一类得到的数据扩增。

# SMOTE过采样
from imblearn.over_sampling import SMOTE

# 加载采样器,设置随机种子为 1 ,使得每次采样结果相同
smote_ = SMOTE(random_state=1)

# 开始对训练数据进行训练
x_smote_resampled, y_smote_resampled = smote_.fit_resample(x_train, x_test)

# 查看采样结果
Counter(y_smote_resampled.values)

对 SMOTE 上采样过的数据进行模型的训练。

# 初始化 LogisticRegression 模型
model_smote = LogisticRegression()

# 开始训练
%time model_smote.fit(x_smote_resampled, y_smote_resampled)

# 批量对测试集预测
model_smote_result = model_smote.predict(y_train)

对 SMOTE 训练集训练后的模型进行批量预测,并结果记录。

# 收集训练标签
method.append('smote')

# 收集 accuracy_score 分数
acc_list.append(metrics.accuracy_score(y_test, model_smote_result))

# 收集 f1 分数
f1_list.append(metrics.f1_score(y_test, model_smote_result))

随机下采样
下采样又叫欠采样,是按照最少的标签数为基础,将其余类别样本数据进行裁剪,使得不同标签的样本量达到均衡。由于减少了标记较多的样本导致总的训练数据量变少,本实验将使用随机裁剪类目较多的子集来达到数据平衡的目的,我们看到采样后的数据按照较少的一方进行平衡。

from imblearn.under_sampling import RandomUnderSampler

# 加载采样器,设置随机种子为 1 , 使得每次采样结果相同
rus = RandomUnderSampler(random_state=1)

# 开始对训练数据进行训练
X_rus_sampled, y_rus_sampled = rus.fit_resample(x_train, x_test)

# 查看采样结果
Counter(y_rus_sampled.values)

对下采样后的数据开始训练模型。

# 初始化 LogisticRegression 模型
model_rusampled = LogisticRegression()

# 开始训练
%time model_rusampled.fit(X_rus_sampled, y_rus_sampled)

# 批量对测试集预测
model_rus_result = model_rusampled.predict(y_train)

对随机下采样训练集训练后的模型进行批量预测,并结果记录。

# 收集训练标签
method.append('rus')

# 收集 accuracy_score 分数
acc_list.append(metrics.accuracy_score(y_test, model_rus_result))

# 收集 f1 分数
f1_list.append(metrics.f1_score(y_test, model_rus_result))

结果分析
将结果存入 Dataframe 进行结果分析,normal 表示不进行采样,ros 表示随机上采样,smote 表示使用 smote 进行采样,rus 表示使用随机下采样,从结果来看 随机上采样在不破坏训练集数据的情况下,随机扩增数据较少的部分,起到了数据扩增的目的,上采样从准确度和 f1 值都是最高的,在解决情感分析中数据集合失衡的问题上,应该优先选用随机上采样对训练集进行扩充。

result_analysis = pd.DataFrame({
    'method': method,
    'acc_list': acc_list,
    'f1_list': f1_list, })

result_analysis.head()

你可能感兴趣的:(129在线民宿 UGC 数据挖掘实战--文本自动化标注和数据采样)