一篇文章带你了解NLP文本预处理:步骤、示例 | 附github源码
文本数据无处不在,比如每天的 Facebook、Twitter新闻等等。数据是新的石油,文本是我们需要钻得更深的油井。在我们真正使用这种油之前,我们必须对它进行预处理,使它适合我们的机器。对于数据也是一样,我们必须对数据进行清理和预处理,以符合我们的目的。这篇文章将包括一些简单的方法来清理和预处理文本数据的文本分析任务。
数据集:2019冠状病毒疾病的 Twitter 数据集
语言:英文
基于上述标准,使用该方法有以下三个步骤:
1)清理和过滤所有非英语的推文/文本(保持数据一致性);
2)为复杂的文本数据创建一个简化版本;
3)对文本进行矢量化,并将嵌入保存以备将来分析之用。
步骤 1: 清洁和过滤文本
首先,为了简化文本,我们希望将文本标准化为只使用英文字符。此函数可以用来删除所有非英文字符。
def clean_non_english(txt):
txt = re.sub(r'\W+', ' ', txt)
txt = txt.lower()
txt = txt.replace("[^a-zA-Z]", " ")
word_tokens = word_tokenize(txt)
filtered_word = [w for w in word_tokens if all(ord(c) < 128 for c in w)]
filtered_word = [w + " " for w in filtered_word]
return "".join(filtered_word)
我们甚至可以通过删除这些停顿词来做得更好。停顿词是出现在英语句子中的常见词,对句子的意义没有多大帮助。我们将使用 nltk 包来过滤停顿词。由于我们的主要任务是使用单词云可视化推特数据的共同主题,这一步对于避免常见的单词如“ the”、“ a”等是必要的。然而,如果你的任务需要完整的句子结构,比如下一个单词预测或语法检查,你可以跳过这一步。
import nltk
nltk.download('punkt') # one time execution
nltk.download('stopwords')
from nltk.corpus import stopwords
stop_words = set(stopwords.words('english'))
def clean_text(english_txt):
try:
word_tokens = word_tokenize(english_txt)
filtered_word = [w for w in word_tokens if not w in stop_words]
filtered_word = [w + " " for w in filtered_word]
return "".join(filtered_word)
except:
return np.nan
对于推特数据来说,在清理之前我们需要考虑一个特殊的功能:mention(也就是我们常用的@功能)。您的数据可能具有这样的特性(或不具有这样的特性) ,并且这是个例,而不是通用的需求。因此,在盲目地清理和预处理数据之前要充分了解您的数据!
def get_mention(txt):
mention = []
for i in txt.split(" "):
if len(i) > 0 and i[0] == "@":
mention.append(i)
return "".join([mention[i] + ", " if i != len(mention) - 1 else mention[i] for i in range(len(mention))]
之前,我们清除了非英语字符。现在,我们删除非英语文本(语义上)。Langdetect 是一个可以用来检查文本语言的 python 包,它是 Google 语言检测库从 Java 到 Python 的直接接口。
from langdetect import detect
def detect_lang(txt):
try:
return detect(txt)
except:
return np.nan
然后我们可以过滤掉所有检测结果不是“ en”语言。
步骤 2: 简化复杂数据——定位?
对于数值数据,良好的处理方法是缩放、标准化和规范化。
对于范畴数据,有许多方法。两种常用方法是:Label Encoder (为每个标签分配一个不同的编号)和 One hot encoding (用0和1的矢量表示)。
本文将介绍一些降低数据复杂性的方法,尤其是位置数据。在我的数据集中,有一个表示位置的列,其中包含作者的地址。但是,我不能对这些原始数据进行太多的分析,因为它们太杂乱和复杂(包括城市、县、州和国家)。因此,我们可以将文本标准化,并将其缩减到“ country”级别(如果您感兴趣,可以缩减到 state)。一个处理位置数据的软件包已经准备好了。它可以识别正确的地址并将这些位置重新格式化为标准格式。然后,你可以选择保留任何你需要的信息。对我来说,state和country级别已经足够了。
from geopy.geocoders import Nominatim
geolocator = Nominatim(user_agent="twitter")
def get_nation(txt):
try:
location = geolocator.geocode(txt)
x = location.address.split(",")[-1]
return x
except:
return np.nan
步骤 3: 向量化和词嵌入
文本向量化是将文本转换为向量值以表示其含义。早些时候,我们使用one hot encoding的编码方法,可以将词汇转化词汇大小的向量,其中文本出现的地方使用值1,其他地方使用值0。现在,我们有更先进的方法,如 spacy,GloVe,甚至 bert 词嵌入。对于这个项目的范围,我将向您介绍 python 和 Jupiter 笔记本中的 GloVe。
首先,我们下载这些词嵌入库,你可以在这里手动下载,或者直接在你的笔记本上下载。
!wget http://nlp.stanford.edu/data/glove.6B.zip
!unzip glove*.zip
然后,我们创建一个函数对每个数据点进行矢量化。句子是每个单词的平均表示。对于空句,我们将其默认为零向量。
def vectorize(value, word_embeddings, dim = 100):
sentences = value.to_list()
sentence_vectors = []
for i in sentences:
if len(i) != 0:
v = sum([word_embeddings.get(w, np.zeros((dim,))) for w in i.split()])/(len(i.split())+0.001)
else:
v = np.zeros((dim,))
sentence_vectors.append(v)
sentence_vectors = np.array(sentence_vectors)
return sentence_vectors
最后,我们对整个数据集进行向量化,并将向量化的 numpy 数组保存为文件,这样我们就不必每次运行代码时都重复这个过程。向量化的版本将保存为 numpy 数组,其格式为.npy 文件。Numpy 软件包可以方便地存储和处理海量数组数据。
作为我个人的标准做法,我尝试在每个部分之后将所有数据保存为单独的文件,以便更灵活地评估数据和更改代码。
def vectorize_data(data = data, value = 'english_text', dim = 100):
# Extract word vectors
word_embeddings = {}
f = open('glove.6B.{}d.txt'.format(str(dim)), encoding='utf-8')
for line in f:
values = line.split()
word = values[0]
coefs = np.asarray(values[1:], dtype='float32')
word_embeddings[word] = coefs
f.close()
text_vec = vectorize(data[value], word_embeddings, dim)
np.save("vectorized_{}.npy".format(str(dim)), text_vec)
print("Done. Data:", text_vec.shape)
return True
总结
数据预处理,特别是文本数据预处理,可以说是一个非常麻烦的过程。机器学习工程师工作流程的很大一部分将用于这些清理和格式化数据(如果你的数据已经非常干净,那么你就很幸运了,并感谢所有的数据工程师使之成为现实)。