目录
1. 加载购物评论数据集
从第一节课开始,通过 RNN 循环神经网络,来加载电商的评论,通过评论得出,客户究竟是好评、中评还是差评。
加载数据:
若字体为黑色,说明 PyCharm 没有安装 csv 插件,需要按下面的步骤进行安装。
file --> setting --> plugins --> Installed --> 搜索【csv Plugin】即可。
字体为下图所示的绿色,即为正确。
查看数据信息
- 读取数据,查看数据信息
import pandas as pd
df = pd.read_csv("../data/Clothing Reviews.csv")
print(df.info())
从下图可知,总的记录数是 23846 条,对于评论数据,Review Text 列,最好将它转为 String 类型,方便我们后续分析,做字符串的处理。
类型转换
df['Review Text'] = df['Review Text'].astype(str)
x_train = df['Review Text']
y_train = df['Rating']
文本转成向量
from tensorflow.keras.preprocessing.text import Tokenizer
# 创建词典的索引, 默认词典大小20000
dict_size = 20000
tokenizer = Tokenizer(num_words=dict_size)
# jieba: 停用词,标点符号,词性.....
tokenizer.fit_on_texts(x_train) #训练x_train,得到词索引
print(len(tokenizer.word_index), tokenizer.index_word)
# 把评论的文本转化序列编码
x_train_tokenized = tokenizer.texts_to_sequences(x_train)
print(x_train_tokenized) # 2 维的列表
for v in x_train_tokenized[:10]:
print(v, len(v))
1.1 进行文本处理
此时,已经拿到了特征和目标值。文本数据是无法直接参与神经网络的,首先要先转换为向量,一共有3步。1.把评论条数对应的词(下面代码中的words),映射成数字,需要通过 Tokenizer
来完成;2.把文本转换成序列编码,就是第一步映射的编码;3.转换成矩阵。在进入神经网络的时候,还要经过词嵌入
from tensorflow.keras.preprocessing.text import Tokenizer # 标记器(每一个词,以我们的数值做映射,)
words = ['LaoWang has a Wechat account.', 'He is not a nice person.', 'Be careful.'] # 把这句话中每一个单词,映射成我们的数值
tokenizer = Tokenizer(num_words=15) # 上面三句话中,词的总数不超过 15 个(估算的值), num_words 设置单词的数量
tokenizer.fit_on_texts(words)
word_index = tokenizer.word_index
print(word_index, len(word_index)) # print 1
# 把文本转化为序列编码
sequences = tokenizer.texts_to_sequences(words)
print(sequences) # print 2
# 文本转化为矩阵
one_hot_matrix = tokenizer.texts_to_matrix(words, mode='binary')
# 向量化是构建神经网络的第一步
print(tokenizer.word_index.keys()) # print 3
print(one_hot_matrix, one_hot_matrix.shape) # print 4
上面代码的输出为:
D:\Anaconda\python.exe "D:\pycharm\PyCharm Community Edition 2020.2\plugins\python-ce\helpers\pydev\pydevd.py" --cmd-line --multiproc --qt-support=auto --client 127.0.0.1 --port 61977 --file E:/09-code/11-自然语言处理与知识图谱/pypro/chapters01/demo03_文本转向量.py
pydev debugger: process 1665180 is connecting
Connected to pydev debugger (build 202.6397.98)
2023-05-22 21:15:47.445945: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'cudart64_110.dll'; dlerror: cudart64_110.dll not found
2023-05-22 21:15:47.446528: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.
{'a': 1, 'laowang': 2, 'has': 3, 'wechat': 4, 'account': 5, 'he': 6, 'is': 7, 'not': 8, 'nice': 9, 'person': 10, 'be': 11, 'careful': 12} 12
[[2, 3, 1, 4, 5], [6, 7, 8, 1, 9, 10], [11, 12]]
dict_keys(['a', 'laowang', 'has', 'wechat', 'account', 'he', 'is', 'not', 'nice', 'person', 'be', 'careful'])
[[0. 1. 1. 1. 1. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 1. 0. 0. 0. 0. 1. 1. 1. 1. 1. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1. 0. 0.]] (3, 15)
假设所有的词的条数为 20000
条,
用的词越多,它就越靠前,
评论里面会有一些不符合评论的单词,我们是需要进行过滤的,
一个 List 是一条评论,评论是有长有短的
查看一下,前10条的评论,每条评论有多少个字
x_train_tokenized 是一个 2 维的List,
为了更好的显示出来它大概的一个分布,可以通过可视化的方式,来做一个呈现(展示评论的长度),大概瞅了一眼,多少评论的长度在 200左右,故用200作为最大长度,10作为步长。
从下图可以看出,20000条评论中,大概的分布为从0到120,长度为90的评论数量比较多一些,长度为40的评论数量也比较多一些,所有的评论数都是125以内,如果我们不想裁切我们不等长的评论数据,我们就要把评论里面不等长的评论转换成等长
把不等长的评论,转换为等长的评论
转成 120 之后,原来是 7,现在是120,填充了很多0,注意:填充放到前面还是放到后面,可以通过设置参数的方式进行控制。
2. 构建 RNN 神经网络(DNN、CNN、RNN、GNN)
本节课,如何将电商评论的数据,给它加载进来,转换成词向量之后,再构建我们的 RNN 神经网络,通过刚刚的描述可以看出来,整个自然语言处理的话,主要分成 2 部分,第一部分是把文本转换成词向量,第二部分是神经网络的构建。
词向量的部分,在前面已经或多或少的讲过一些,本节课先回顾词向量的概念。下图代码中,我们总的词典的大小是 15,而每个样本的评论的长度是6,接下来,如何进行词嵌入呢?
上图中,model.add()中的参数input_dim
表示词典的总长度,output_dim
是你要压缩的维度,input_length
是我们每条评论输出的长度,本例中,经过设置之后,每条评论的长度统一设为6.
假设上图中 words 中的 3 句话,就是 3 条评论,然后去除重复后,做成映射,
然后通过 pad_seqences
,将不同长度的评论转换成相同长度的评论,
首先进行序列化,序列化之后转成 one-hot 编码的矩阵,这个部分主要是方便理解词嵌入(可以省略),序列化可以直接转换成词嵌入后的结果,
词嵌入主要解决2个问题,把高维的空间映射到低维,第二个问题,体现词与词之间的关系。
2.2 有了词向量,如何构建神经网络
词嵌入
构建 RNN 神经网络
3. 多循环神经网络原理分析
import pandas as pd
import tensorflow as tf
tf.random.set_seed(1)
df = pd.read_csv("../data/Clothing Reviews.csv")
print(df.info())
df['Review Text'] = df['Review Text'].astype(str)
x_train = df['Review Text']
y_train = df['Rating']
# print(y_train.unique())
from tensorflow.keras.preprocessing.text import Tokenizer
# 创建词典的索引,默认词典大小20000
dict_size = 14848
tokenizer = Tokenizer(num_words=dict_size)
# jieba: 停用词,标点符号,词性.....
tokenizer.fit_on_texts(x_train)
print(len(tokenizer.word_index), tokenizer.index_word)
# # 把评论的文本转化序列编码
x_train_tokenized = tokenizer.texts_to_sequences(x_train)
#
# # 通过指定长度,把不等长list转化为等长
from tensorflow.keras.preprocessing.sequence import pad_sequences
max_comment_length = 120
x_train = pad_sequences(x_train_tokenized, maxlen=max_comment_length)
for v in x_train[:10]:
print(v, len(v))
文本输入之后,首先要构建词向量,
# 构建RNN神经网络
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, SimpleRNN, Embedding
import tensorflow as tf
rnn = Sequential()
# 对于rnn来说首先进行词向量的操作
rnn.add(Embedding(input_dim=dict_size, output_dim=60, input_length=max_comment_length))
# (None, 120, 60) ==> [评论数,每条评论的长度,词向量] ==> [评论数,词向量]
# [batch,feature len] @ [feature len, hideen len] ==> [batch,hidden len]
# [batch,hidden len] @ [hidden len hidden len] ==> [batch,hideen len]
# [b,60] @ [60,100] ==> [b,100] wx
# [b,100] @ [100,100] ==> [b,100] ub
rnn.add(SimpleRNN(units=100)) # 第二层构建了100个RNN神经元
# [b,100] @ [100,10] ==> [b,10]
rnn.add(Dense(units=10, activation=tf.nn.relu))
# [b,10] @ [10,5] ==> [b,5]
rnn.add(Dense(units=6, activation=tf.nn.softmax)) # 输出分类的结果
rnn.compile(loss='sparse_categorical_crossentropy', optimizer="adam", metrics=['accuracy'])
print(rnn.summary())
result = rnn.fit(x_train, y_train, batch_size=64, validation_split=0.3, epochs=1)
print(result)
print(result.history)
# {'loss': [1.2024492025375366], 'accuracy': [0.5624087452888489],
# 'val_loss': [1.0709134340286255], 'val_accuracy': [0.5675560832023621]}
输出:
我们之前所说的循环神经网络,它是一个序列结构,每条评论有120个词,会一个词一个词进入到循环神经网络中去,每个词都有60个特征。举个例子,假设神经网络每一秒钟可以处理
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding (Embedding) (None, 120, 60) 890880 # [评论数,每条评论的长度,词向量]
simple_rnn (SimpleRNN) (None, 100) 16100
dense (Dense) (None, 10) 1010
dense_1 (Dense) (None, 6) 66
=================================================================
Total params: 908,056
Trainable params: 908,056
Non-trainable params: 0
_________________________________________________________________
None
257/257 [==============================] - 13s 40ms/step - loss: 1.2221 - accuracy: 0.5588 - val_loss: 1.2004 - val_accuracy: 0.5484
<keras.callbacks.History object at 0x0000026A011760A0>
{'loss': [1.2220793962478638], 'accuracy': [0.5588199496269226], 'val_loss': [1.2003711462020874], 'val_accuracy': [0.5483962297439575]}
每个词进来的时候,都有 60 个特征,在