破解上下文的密码 自然语言处理中的词向量化技术

上下文密码破解的词向量化技术

你搬到了一个远离你的国家的新城镇,在那里你碰巧在咖啡店里遇到了某个人。一个年轻的女人,和你差不多年纪,瞬间你们就开始了对话。这是因为你们俩都懂英语。就在你很高兴遇到会说你的语言的人的时候,服务员用本地语言过来点餐了。好吧,你的新朋友愿意当个翻译。当你回到公寓后,你在互联网上翻找了一番,寻找学习本地语言的课程。因此,共同语言对于两个实体之间的正常交流是至关重要的。

Photo by daan evers on Unsplash

在人工智能领域中,自然语言处理是一项令人兴奋的技术。令人着迷的是,机器能够理解你用母语说的话。这促进了人类与计算机之间的顺畅互动。但是,难道不应该有一种共同的交流语言才能实现这一点吗?我们知道,人类说着各种各样的语言,如英语、西班牙语、法语、印地语、普通话等等。但是计算机唯一知道的语言是二进制。它们的整个世界都是由 0 和 1 组成的。

如果计算机能理解数字,而我们能理解英语等语言,那么就应该有一种将自然语言转化为数字的方法。Word2vec 就是拯救我们的工具。

Word2vec 将句子中的单词表示为连续空间中的向量。这些向量捕捉了单词在不同上下文中的语义关系。相似的单词有相似的向量。下图展示了这样一个向量空间的二维表示(实际 NLP 问题中向量空间的维度要远大于 2)。

我们可以看到类似的单词如 walk 和 run 靠近彼此。而 smile 和 Radiology 是不相关的单词,它们相距很远。彼此靠近的单词被称为可替换的单词,也就是说,如果你在句子中互换这些单词,句子仍然会有意义。两个单词的可替换性可以根据两个单词向量之间的夹角余弦来计算。这个值可以在 -1 到 1 之间取值,1 表示两个单词之间关系密切。可以对向量进行一些操作,以执行诸如查找类似词的任务。

Word2vec 主要用于单词预测。我们可能在每天使用的电子邮件等应用程序中看到自动补全和自动更正等功能。Word2vec 主要用于预测不完整文档中的下一个单词/单词,或者填充文档中缺失的单词。为了执行这些任务,需要训练一个机器学习模型。

现在我们可以看到自然语言如何在现实应用中进行向量化。

Photo by Jefferson Santos on Unsplash

在这里,我们将使用一个相对较小的数据集来训练一个垃圾邮件过滤模型。为了得到一个合适的模型,我们需要使用一个更大的数据集。这将需要很长时间来运行。

数据由几条文本消息组成,这些消息要么是垃圾消息,要么不是。可以从这里下载。

这是一个文本文件,每一行有两个字段,一个标签和一个逗号分隔的句子。标签给出垃圾消息的 spam 和真实消息的 ham。

我将使用 Python 来实现这个程序。程序需要各种库,如 numpy、pandas、nltk、regex、gensim 等等。如果你没有安装它们,可以使用 pip 进行安装。我将展示程序中导入的所有包。

from gensim.models import Word2Vecimport numpy as npfrom nltk.corpus import stopwordsimport nltkfrom nltk.corpus import stopwordsimport pandas as pdimport stringimport regex as refrom sklearn.feature_extraction.text import TfidfVectorizerfrom sklearn.ensemble import RandomForestClassifierfrom sklearn.metrics import precision_score,recall_scorefrom sklearn.model_selection import train_test_splitimport gensim

现在我们已经导入了所有的包,可以开始实现了。

第一步是清洗和准备数据集。

messages = pd.read_csv("output.csv", delimiter="\t")messages.columns = ["label", "text"]  def text_cleaner(text):    nxt = "".join([char for char in text if char not in string.punctuation])    nxt = re.split("\W+",nxt.lower())    nxt = [k for k in nxt if k not in stopwords.words('english')]    return nxt messages["clean_text"] = messages['text'].apply(lambda x:text_cleaner(x))print(messages.head())

我将数据集保存在一个名为output.csv的文件中。我使用了<pandas.read_csv()来读取文件。分隔符设置为“\t”,因为数据集中的字段使用制表符分隔。

我们给数据中的两列设置了标题,分别为labeltext

现在我们需要将文本转换为标记。在此之前,我们可以清理文本。首先,我们删除了句子中的所有标点符号。在Python中,可以在string.punctuation中找到所有常见的标点符号。

使用nxt = re.split(“\W+”,nxt.lower())使用正则表达式将句子拆分为一组单词。我还将单词转换为小写,因为我们不希望模型对大小写敏感。

停用词是那些对句子的主旨没有太多贡献的词。英语中有大约170个以上的停用词。可以使用nltk库的stopwords.words(‘english’)来访问这些词。我们可以从数据中删除这些词,以使我们的模型轻巧高效。

现在数据已经经过清理和标记化,并存储在一个名为clean_text的新列中。可以使用head()函数打印数据中的前5个条目。

现在我们有一组标记,我们需要在训练之前将其转换为向量。为此,让我们使用一种称为TF-IDF(词频逆文档频率)的属性。单词在文档中的TF-IDF显示了该单词对文档的重要性。它与单词在文档中的频率成正比,与样本空间中的文档数量成反比。可以使用以下方式计算:

在Python中,我们可以使用TfidfVectorizer类来创建向量。为了简化代码,我们不会创建一个新的列来进行清理和标记化。可以在TfidfVectorizer()中调用text_cleaner函数。

new_vector = TfidfVectorizer(analyzer=text_cleaner)x = new_vector.fit_transform(messages['text'])x_features = pd.DataFrame(x.toarray())

x现在是一个二维数组,每一行表示一个向量,其中包含样本空间中所有标记的TF-IDF值。如果单词不在句子中,则该标记的TF-IDF值将为零。由于大多数单词都是这种情况,我们得到了一个稀疏矩阵。现在将矩阵转换为pandas数据框进行训练。

在这里,我们使用sklearn提供的RandomForestClassifier来训练模型。

x_train, x_test, y_train, y_test = train_test_split(x_features,messages['label'],test_size=0.2)rf = RandomForestClassifier()rf_model = rf.fit(x_train,y_train)y_pred = rf_model.predict(x_test)precision = precision_score(y_test,y_pred,pos_label='spam')recall = recall_score(y_test,y_pred,pos_label='spam')print("precision = {} and recall = {}".format(round(precision,4),round(recall,4)))

数据被分割为训练集和测试集,并将训练集传递给RandomForestClassifier来创建模型。该模型使用测试数据进行测试,我们得到了精确度为1.0和召回率为0.8378的结果。(由于我对数据进行了一些调整,您可能会得到稍微不同的值)。

Nate Grant在Unsplash上的照片

而Word2vec则采用了略微不同的方法。它根据单词的位置来进行研究。这是通过分析单词附近的其他单词来实现的。在每个单词出现的位置周围创建一个特定大小的窗口。通过这种方式,学习了单词的用法上下文。让我们看看如何在之前的示例中使用相同的数据集进行处理。

数据进行了清洗和标记化,并存储在一个新的列中,就像我们之前做的那样。我们可以将该数据分割为训练数据和测试数据,并将它们传入word2vec模型中。gensim包中的Word2Vec类负责对标记进行向量化。

x_train, x_test, y_train, y_test = train_test_split(messages["clean_text"],messages["label"],test_size=0.2)w2v_model = gensim.models.Word2Vec(x_train,vector_size=100,window=5,min_count=2)w2v_model.save("mymodel.model")

训练好的模型可以保存到本地系统中,这样我们就不需要每次运行时都重新训练。

在这里,我们传入了一个最小计数值为2,这意味着只有在整个数据中至少出现2次的单词才会创建一个向量。因此,我们可以消除一些对问题没有任何影响的单词。

Word2vec模型具有许多内置功能。例如,如果您想在模型中找到与“run”最相似的单词,可以使用most_similar()函数。

mymodel = Word2Vec.load("mymodel.model")similar_words = mymodel.wv.most_similar("run")print(similar_words)

[('pls', 0.9978137612342834), ('yes', 0.9977635145187378), ('r', 0.9977442026138306), ('win', 0.9977269768714905), ('today', 0.9976850152015686), ('im', 0.9976809024810791), ('get', 0.9976732134819031), ('reply', 0.9976603984832764), ('new', 0.9976487159729004), ('one', 0.9976474046707153)]

我们得到的输出非常奇怪。这是因为我们在这次训练中使用了一个小的数据集。在gensim中有训练于大量维基百科文档的相似模型,它们给出更准确的输出。

将自然语言向量化在机器学习中具有非常广泛的应用。这种技术也可以应用于其他领域。情感分析、文本生成和机器DNA分类只是其中几个应用领域。而word2vec的成功在这些领域的发展中起到了关键作用。