数据预处理
学习如何在使用LSTM模型之前,使用NLTK对数据进行清洗和预处理。
我需要回顾一下
加载数据集
我们将使用世界杯推文数据集。通过 pandas 加载该数据集,并展示部分推文样本。
从 CSV 文件读取数据到 pandas DataFrame 中
1import pandas as pd 2 3df = pd.read_csv("/usr/local/notebooks/worldcup-tweets.csv") 4print(df.head())
在上述代码中:
-
第1行:我们导入
pandas库并简写为pd,用于读取 CSV 文件。 -
第2–3行:调用 pandas 的
read_csv()方法来加载世界杯推文数据集。最后调用 DataFrame 的head()方法打印出文件的前几行。
使用 NLTK 进行数据处理
该数据集中包含了一些对判断推文情感(正面或负面)无用的字符,例如标点符号和特殊字符。因此我们需要将这些内容从推文中移除。
同时,还需要将 sentiment 列转换为数值形式表示,这可以通过 scikit-learn 提供的 LabelEncoder 实现。
此外,推文中还包含一些不利于情感分析的词语,比如英语中的常见词:the、at、and 等,这类词被称为停用词(stopwords)。我们将借助 nltk 库来去除这些停用词。首先定义一个函数以移除所有英文停用词,并将其应用于推文列。
移除停用词
1import nltk 2from nltk.corpus import stopwords 3nltk.download('stopwords', quiet=True) 4 5def remove_stop_words(tweets): 6 tweets_minus_sw = [] 7 stop_words = stopwords.words('english') 8 tweets = tweets.split() 9 cleaned_tweets = [tweets_minus_sw.append(word) for word in tweets if word.lower() not in stop_words] 10 cleaned_tweets = ' '.join(tweets_minus_sw) 11 return cleaned_tweets 12 13df['tweets'] = df['tweets'].apply(remove_stop_words) 14print(df)
在上述代码中:
-
第1–2行:导入
nltk库以及来自nltk.corpus的stopwords模块。 -
第3行:调用
nltk.download()方法下载stopwords数据集,设置quiet=True以关闭下载日志输出。 -
第5–11行:定义
remove_stop_words()函数,用于移除输入文本中的停用词并返回清理后的结果。函数内部:第6行:创建空列表
tweets_minus_sw,用于存储去除停用词后的单词。第7行:从
stopwords模块获取英文停用词列表。第8行:调用
split()方法将输入字符串拆分为单词列表。第9行:使用
for循环遍历每个单词,若其小写形式不在停用词列表中,则添加至tweets_minus_sw。第10–11行:使用
' '.join()将列表合并成字符串并返回。
-
第13–14行:将
remove_stop_words函数应用到 DataFramedf的tweets列上以清除停用词,最后打印处理后的 DataFrame。
接下来,我们也把情感列转换为数值表示。
对正面与负面情感进行编码
1from sklearn.preprocessing import LabelEncoder 2 3labelencoder = LabelEncoder() 4df = df.assign(sentiment = labelencoder.fit_transform(df["sentiment"])) 5print(df)
在上述代码中:
-
第1行:从
sklearn.preprocessing模块导入LabelEncoder。 -
第3行:创建一个
LabelEncoder类的实例。 -
第4行:使用
LabelEncoder的fit_transform()方法将sentiment列的值转换为数值形式。 -
第5行:打印 DataFrame
df,此时可以看到sentiment列已变为数值。
我们对比一下原始推文与去除停用词后的推文。
观察部分推文可以发现,像 this、was、a 这样的词已被删除,但仍然能看到一些特殊字符存在。接下来我们解决这个问题。
移除标点符号和特殊字符
目前情感列已经完成数值化处理,但推文仍是文本格式,还需将其向量化。
我们首先从推文中移除标点符号和其他特殊字符。
使用正则表达式移除标点符号及其他特殊字符
1import re 2 3def re_sub(review_sentence): 4 review = re.sub('[^a-zA-Z]', ' ', review_sentence) 5 return review 6 7df['tweets'] = df['tweets'].map(re_sub) 8docs = df['tweets'] 9print(docs)
在上述代码中:
-
第1行:导入
re模块,用于支持正则表达式操作。 -
第3–5行:定义
re_sub()函数以移除非字母字符。函数内部使用re.sub()方法将所有非字母字符替换为空格,并将结果存入变量review,最后返回该变量。 -
第7行:将
re_sub函数映射到数据集的tweets列,并更新其值。 -
第8–9行:将
tweets列的数据赋值给变量docs并打印输出。
去除重复项
我们先从数据集中删除重复的记录。
从数据集中删除重复项
1print("去重前总行数:", len(df)) 2 3df = df.drop_duplicates() 4 5print("去重后总行数:", len(df))
在上述代码中:
-
第1行:打印 DataFrame
df的行数,初始为 1040 行。 -
第3行:调用 DataFrame 的
drop_duplicates()方法,移除世界杯推文数据集中的重复行。 -
第5行:再次打印 DataFrame 的行数,显示重复项已被移除,总行数由 1040 减少至 1035。
文本向量化
我们将使用 scikit-learn 的 TfidfVectorizer 函数将文本数据转换为数值表示。该函数需要指定最大特征数量。
1from jax import numpy as jnp 2from sklearn.feature_extraction.text import TfidfVectorizer 3from sklearn.model_selection import train_test_split 4 5vectorizer = TfidfVectorizer(max_features=10000) 6X = vectorizer.fit_transform(docs).toarray() 7X_train, X_test , y_train, y_test = train_test_split(docs, labels , test_size = 0.20, random_state=0) 8 9print("X_train\n", X_train) 10print("\nX_test\n", X_test)
我们使用 Keras 的 TextVectorization 层将文本转换为整数形式。该函数可自动过滤标点符号并将文本转为小写。我们传入参数 max_features 设为 5000,表示词汇表大小限制为 5000。你可以调整此数值,观察模型性能的变化。
定义好向量化层后,需将其应用于训练数据,通过调用 adapt 方法实现。该方法会根据提供的数据集构建词汇表,并在指定了 max_tokens 时进行截断。可通过调用 get_vocabulary 方法查看生成的词汇表。
1import tensorflow as tf 2 3max_features = 5000 # 最大词汇量 4batch_size = 128 5max_len = 25 # 输出序列的固定长度(用于填充) 6 7vectorize_layer = tf.keras.layers.TextVectorization(standardize='lower_and_strip_punctuation', max_tokens=max_features, output_mode='int', output_sequence_length=max_len) 8vectorize_layer.adapt(X_train) 9 10print(vectorize_layer.get_vocabulary())
我们可以使用训练好的向量化层将训练集和测试集转换为数值形式。
1X_train_padded = vectorize_layer(X_train) 2X_test_padded = vectorize_layer(X_test) 3 4print(X_train_padded) 5print(X_test_padded)
创建 tf.data 数据集
为了更高效地将数据加载到 LSTM 模型中,我们生成并预取训练集和测试集的小批量数据。首先创建一个 tf.data.Dataset。
1training_data = tf.data.Dataset.from_tensor_slices((X_train_padded, y_train)) 2validation_data = tf.data.Dataset.from_tensor_slices((X_test_padded, y_test)) 3 4training_data = training_data.batch(batch_size) 5validation_data = validation_data.batch(batch_size)
接着预取一个批次的数据,打乱顺序,并以 NumPy 数组形式返回。其中 tfds.dataset_as_numpy 可将 tf.data.Dataset 转换为 NumPy 数组的可迭代对象。
1import tensorflow_datasets as tfds 2 3def get_train_batches(): 4 ds = training_data.prefetch(1) 5 ds = ds.shuffle(3, reshuffle_each_iteration=True) 6 return tfds.as_numpy(ds)