RNN学习:利用LSTM,GRU层解决航空公司评论数据预测问题

2024-03-29 13:48

本文主要是介绍RNN学习:利用LSTM,GRU层解决航空公司评论数据预测问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

RNN学习:利用LSTM,GRU解决航空公司评论数据预测问题

文章目录

  • RNN学习:利用LSTM,GRU解决航空公司评论数据预测问题
    • 1.RNN的介绍
      • 1.1 LSTM的简单介绍
      • 1.2 GRU的简单介绍
    • 2.数据集的介绍
    • 3.读取数据并作预处理
    • 4.模型的搭建
    • 结语

1.RNN的介绍

​ RNN,即循环神经网络,即一般的神经网络同层节点与节点之间并无连接,比如CNN隐藏单元之间并没有连接,那么这相对于一些序列问题上的处理就会效果很差。如翻译单词,全文的意思必须是根据所有单词来进行判断。或判断说话人情绪,评论好坏,最终的输出要和前面所有的输入发生关系,所以这里学者们提出循环神经网络,让上一个节点会对下一个节点传递状态向量,每个节点之间输出两个值,一个是我们要的输出,还有一个就是状态向量,该向量输入下一个下一个节点,最终输出为二维数据(None,units)units为RNN的隐藏单元数。

在这里插入图片描述

1.1 LSTM的简单介绍

​ 刚才我们说明了RNN会不断的向下一个节点传递状态,但是经过长时间的多次传递,最终传递的状态可能会引起梯度爆炸或梯度消失等问题,为了解决这个问题,学者们又提出了LSTM层来解决这个问题,LSTM层的内部存在一些门,他会通过训练门的参数控制了上一状态我们需要遗忘多少,并且在这一层状态的更新。

在这里插入图片描述

可以看到在这一个单元中上一层的输出ht-1和状态Ct-1都传递了进来从而经过我们的门来控制该单元遗忘并更新状态。

1.2 GRU的简单介绍

GRU是LSTM结构的一种变体,他可以做到与LSTM性能相当的情况下,计算量会比LSTM减少,他的网络结构如下

在这里插入图片描述

可以看到他作为LSTM的变体,与LSTM的相似之处,他也会有前一次的状态(但是不会有前一层的输出传入)向他传入并且通过训练控制前一次状态在本单元的遗忘与更新。

2.数据集的介绍

本次使用的是Twitter 美国航空公司情绪:2015年2月美国航空公司的Twitter数据,分类为正面,负面和中性推文(https://www.kaggle.com/crowdflower/twitter-airline-sentiment)

在这里插入图片描述

整个数据集使用CSV格式存储,这种文件格式是一种经常用来数据科学存储数据的纯文本文件,可以用EXCEL直接打开。

可以看到该数据集上有该评价的好坏有neural,positive,negative三种,关于评价的具体 文本是text下的,我们在此次任务中只会用到评价文本(作为数据),情绪好坏作为我们的标签,也就是真值。

3.读取数据并作预处理

​ 首先先清楚我们的目标在预处理过程,是想要提取一个序列(这个序列是由我们的评论转换的),和一个标签(标签也要数字化),那么我们接下来就开始从CSV格式文件中提取文本和标签并分别将他们转化成序列和数字。

import tensorflow as tf
keras=tf.keras
layers=keras.layers
import numpy as np
import pandas as pd
import re
data=pd.read_csv('../input/twitter-airline-sentiment/Tweets.csv')
data.head()#文件内部数据太多使用这个默认查看前五行

在这里插入图片描述

然后我们此次只需要提取每个人评论的text,和评论观点的倾向,所以我们提取以下两列

data=data[['airline_sentiment','text']]
data.head()

在这里插入图片描述

我们成功提取每个评论的情绪,和文本,接下来我们先将情绪用数字表示,可以先查看有多少种情绪

data.airline_sentiment.value_counts()#使用该方法可以查看每个值的个数
negative    9178
neutral     3099
positive    2363
Name: airline_sentiment, dtype: int64

可以看到这里有三个倾向的情绪,消极,中立,积极,那么也就是说这是一个多分类单标签问题,那么我们直接对每个情绪进行编码然后转化即可

sentiment_to_index={'positive':0,'neutral':1,'negative':2}
def to_index(sentiment):#写函数来转化return sentiment_to_index.get(sentiment)
data['sentiment']=data.airline_sentiment.apply(to_index)
del data['airline_sentiment'] #删除原有的一列
data.head()

在这里插入图片描述

可以看到我们的标签被成功的转化成对应的数字标签。

并且我们还要注意一点,消极的评论远远多余积极的评论,我们在训练分类问题上最好是将每个类别上的数据的数量都保持一致,防止模型对于某些分类的特征过分学习。也就是说我们在这里使用消极和中立的数量都必须被降为和积极一样,那么这里我们就直接使用切片,对于series数据切片使用iloc函数

data_positive=data[data.airline_sentiment=='positive']
data_negative=data[data.airline_sentiment=='negative']
data_neutral=data[data.airline_sentiment=='neutral']
data_negative=data_negative.iloc[:len(data_positive)]  
data_neutral=data_neutral.iloc[:len(data_positive)]
len(data_negative),len(data_neutral),len(data_positive)(2363, 2363, 2363) #可以看到我们将三个数据全部转化为相同个数

那么接下来我们合并我们的这些数据并且使用sample方法随机打乱(sample的用法是从原有数据随机抽出一部分数据,但是如果我们把抽出数据的规模等于所有数据,就相当于打乱)

data=pd.concat([data_negative,data_positive,data_neutral])
data=data.sample(len(data))  #smaple的意思是从dataframe中随机抽取指定数量的数据
data.head()

那么接下来我们就将每个文本转化为一个序列,怎么转化呢,其实很简单,那就是将每个句子里的单词映射成一个数字,那么整个句子就成为了一个数字序列,那么如何来完成了,接下来我们开始贴代码

token=re.compile('[A-Za-z]+|[!?,.()]')
#我们设置匹配的时候不要特殊字符,只要标点符号和字母,并且大小写不会影响单词原意,我这里也直接将所有大写转化成小写
def constractor_text(text):res_text=token.findall(text)res_text=[word.lower() for word in res_text]return res_text
#上面是使用re库提供的一个正则匹配方法在除去特殊符号其他均匹配情况下效果显著
new_data=data.text.apply(constractor_text)
data['text']=new_data
data.head()

在这里插入图片描述

那么接下里我们将单词全部映射成一个个数字其实想法很简单,先做一个集合将所有单词添加进集合吗,由于集合本身的特性,会自动删除重复的,然后我们将该集合中的单词转化成字典,就可以将单词转化成序列了,这里也简单的贴代码

word_list=list(word_set) #因为集合并没有下标这个概念,所以为了后面的方便我们转化成列表
word_dict=dict((k,v+1) for v,k in enumerate(word_list))
word_dict#同时为了防止填充单词之后填充0影响结果我们将所有数据,转化
{'win': 1,'DEFINITELY': 2,'gfc': 3,'OI': 4,'pearl': 5,'briughy': 6,'necessity': 7,'flyingwithUS': 8,'agreement': 9,...

这里需要非常注意的一点就是,每个评论的数据都是有一定长度的,但最后为了规范化我们一定是要将所有评论长度都处理到相同长度,那么我们填充的数字一般用0来填充,所以我们在字典里不能对0进行赋值,防止影响结果,所以我这里将所有单词对应的编号加一。可以看到我们单词编号从一开始。

好的有了单词的转换表,那么我们接下来编写函数将句子转换成序列

def word_to_vector(text):vector=[word_dict.get(word,0) for word in text]return vector
data['text']=data.text.apply(word_to_vector)
data_text=data['text']
data_text.head()8263    [3228, 11239, 9075, 694, 1133, 4364, 10324, 10...
4953    [1721, 11079, 870, 10, 11285, 9390, 10642, 724...
5489    [1721, 443, 6165, 4999, 4859, 4806, 7367, 7013...
2452    [3436, 10200, 6758, 10, 310, 1660, 8275, 10324...
8219    [3228, 11460, 10774, 10324, 1291, 6804, 516, 7...
Name: text, dtype: object

这里我们可以看到每个句子就都被转换为对应的序列,那么我们接下里将所有向量处理成完全一样的长度,

maxlen=max(len(x) for x in data_text)
max_word=len(word_set)+1
data_text=keras.preprocessing.sequence.pad_sequences(data_text.values,maxlen=maxlen)
data_text.shape
(7089, 40)

可以看到每个序列都被填充到了长度为40,那么我们接下来提取标签然后制作dataset,划分测试集与训练集

label=data.sentiment.values
test_count=int(7089*0.2)
train_count=7089-test_count
test_data=train_data.take(test_count)
train_data=train_data.skip(test_count)
train_data=train_data.shuffle(train_count).repeat().batch(64)
test_data=test_data.batch(64)

划分完毕后我们总算是完成了我们数据的预处理,接下来开始我们模型的搭建。

4.模型的搭建

我们输入的是一个长度为40的序列,但这样并不适合我们模型对他的处理,对此已经有提出词嵌入方法,WORD2VEC的方法,即将每个单词转化成固定维度的向量,向量之间差的大小,表示每个单词之间关系的大小(我理解为单词之间的相似性),这里我们可以用RGB表示颜色的方式来理解,每个颜色的值都可以用一个三维向量来表示,对于单词就是我们设置一个几十个维度的词向量,假设所有词都可以用这个高维向量来表示,那么具体怎么转换,有多种方法,我们这里使用keras提供的embelding层来将所有单词转换成我们设定维度的向量

model=keras.Sequential()
#Embedding层可以吧文本映射为一个密集向量
model.add(layers.Embedding(max_word,50,input_length=maxlen))
#然后我们多次未见的主角GRU登场,用它来处理这种序列数据效果是十分好的
model.add(layers.GRU(64))#LSTM的参数是一个隐藏单元数
model.add(layers.Dense(3,activation='softmax'))
#最后输出这是一个三分类的问题,所以我们激活函数用softmax
model.compile(optimizer=keras.optimizers.Adam(0.0001),loss='sparse_categorical_crossentropy',metrics=['acc'])
#设置模型的优化器这里没什么好说的

5.训练结果分析与网络调整

model.fit(train_data,steps_per_epoch=train_count//64,epochs=10,validation_data=test_data,validation_steps=test_count//64)

这里我们开始训练查看结果却发现

在这里插入图片描述

网络已经达到严重过拟合,测试集准确率极高,但验证集却非常低,两者相差达到20%,那么为了抑制过拟合我这里采取两种方法一是增加网络深度,添加Dropout层抑制过拟合

model=keras.Sequential()
#Embedding层可以吧文本映射为一个密集向量
model.add(layers.Embedding(max_word,50,input_length=maxlen))
model.add(layers.GRU(64))#LSTM的参数是一个隐藏单元数
model.add(layers.Dropout(0.2))
model.add(layers.Dense(32,activation='relu'))
model.add(layers.Dropout(0.2))
model.add(layers.Dense(16,activation='relu'))
model.add(layers.Dense(3,activation='softmax'))

,二是我将数据增加一倍,(等于是复制了一遍数据再,打乱),最终数据翻倍达到14000多条那么我们再次开始训练,查看结果

Epoch 15/15
177/177 [==============================] - 6s 34ms/step - loss: 0.0542 - acc: 0.9852 - val_loss: 0.1551 - val_acc: 0.9592

可以看到在训练最后,过拟合被抑制了,模型无论在训练集,测试集都达到了极高的正确率

结语

本篇博客简单介绍了RNN网络,并且非常具体的展示了如何从CSV文件读取数据,预处理并制作成模型可以接收的数据,在最后利用GRU搭建模型,并且对于训练结果产生过拟合如何去抑制方面做了处理,如果有任何建议或者问题欢迎评论区指出,谢谢!

这篇关于RNN学习:利用LSTM,GRU层解决航空公司评论数据预测问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/858763

相关文章

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

Java利用JSONPath操作JSON数据的技术指南

《Java利用JSONPath操作JSON数据的技术指南》JSONPath是一种强大的工具,用于查询和操作JSON数据,类似于SQL的语法,它为处理复杂的JSON数据结构提供了简单且高效... 目录1、简述2、什么是 jsONPath?3、Java 示例3.1 基本查询3.2 过滤查询3.3 递归搜索3.4

Spring事务中@Transactional注解不生效的原因分析与解决

《Spring事务中@Transactional注解不生效的原因分析与解决》在Spring框架中,@Transactional注解是管理数据库事务的核心方式,本文将深入分析事务自调用的底层原理,解释为... 目录1. 引言2. 事务自调用问题重现2.1 示例代码2.2 问题现象3. 为什么事务自调用会失效3

mysql出现ERROR 2003 (HY000): Can‘t connect to MySQL server on ‘localhost‘ (10061)的解决方法

《mysql出现ERROR2003(HY000):Can‘tconnecttoMySQLserveron‘localhost‘(10061)的解决方法》本文主要介绍了mysql出现... 目录前言:第一步:第二步:第三步:总结:前言:当你想通过命令窗口想打开mysql时候发现提http://www.cpp

MySQL大表数据的分区与分库分表的实现

《MySQL大表数据的分区与分库分表的实现》数据库的分区和分库分表是两种常用的技术方案,本文主要介绍了MySQL大表数据的分区与分库分表的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录1. mysql大表数据的分区1.1 什么是分区?1.2 分区的类型1.3 分区的优点1.4 分

Mysql删除几亿条数据表中的部分数据的方法实现

《Mysql删除几亿条数据表中的部分数据的方法实现》在MySQL中删除一个大表中的数据时,需要特别注意操作的性能和对系统的影响,本文主要介绍了Mysql删除几亿条数据表中的部分数据的方法实现,具有一定... 目录1、需求2、方案1. 使用 DELETE 语句分批删除2. 使用 INPLACE ALTER T

SpringBoot启动报错的11个高频问题排查与解决终极指南

《SpringBoot启动报错的11个高频问题排查与解决终极指南》这篇文章主要为大家详细介绍了SpringBoot启动报错的11个高频问题的排查与解决,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一... 目录1. 依赖冲突:NoSuchMethodError 的终极解法2. Bean注入失败:No qu

Python Dash框架在数据可视化仪表板中的应用与实践记录

《PythonDash框架在数据可视化仪表板中的应用与实践记录》Python的PlotlyDash库提供了一种简便且强大的方式来构建和展示互动式数据仪表板,本篇文章将深入探讨如何使用Dash设计一... 目录python Dash框架在数据可视化仪表板中的应用与实践1. 什么是Plotly Dash?1.1

springboot报错Invalid bound statement (not found)的解决

《springboot报错Invalidboundstatement(notfound)的解决》本文主要介绍了springboot报错Invalidboundstatement(not... 目录一. 问题描述二.解决问题三. 添加配置项 四.其他的解决方案4.1 Mapper 接口与 XML 文件不匹配

MySQL新增字段后Java实体未更新的潜在问题与解决方案

《MySQL新增字段后Java实体未更新的潜在问题与解决方案》在Java+MySQL的开发中,我们通常使用ORM框架来映射数据库表与Java对象,但有时候,数据库表结构变更(如新增字段)后,开发人员可... 目录引言1. 问题背景:数据库与 Java 实体不同步1.1 常见场景1.2 示例代码2. 不同操作