构建文本分类程序:NLP 教程
已发表: 2022-03-11深度学习是一种技术,已成为机器学习工作流程的重要组成部分。 利用并行计算能力和支持工具的改进,曾经不切实际的复杂和深度神经网络现在变得可行。
Tensorflow、Torch 和 Deeplearning4j 等功能强大且易于访问的库的出现,也为大型科技公司的学术界和研究部门以外的用户打开了开发大门。 为了证明其日益普及,华为和苹果等公司现在在其最新设备中包含专用的深度学习优化处理器,以支持深度学习应用程序。
深度学习已经在许多领域证明了它的力量。 最值得注意的是,谷歌的 AlphaGo 能够在围棋游戏中击败人类玩家,该游戏的复杂性令人难以置信,曾经被认为是计算机与人类玩家竞争的几乎不可逾越的障碍。 索尼的 Flow Machines 项目开发了一种神经网络,可以按照过去著名音乐家的风格创作音乐。 FaceID 是 Apple 开发的一项安全功能,它使用深度学习来识别用户的面部并跟踪用户面部随时间的变化。
在本文中,我们将深度学习应用到我最喜欢的两个主题:自然语言处理和葡萄酒。 我们将建立一个模型来理解专家的自然语言葡萄酒评论,并推断他们正在评论的葡萄酒的种类。
NLP 的深度学习
深度学习已广泛用于自然语言处理(NLP),因为它非常适合学习句子的复杂底层结构和各种单词的语义接近度。 例如,当前的情感分析技术使用深度学习来捕捉难以建模的语言概念,例如否定和混合情感。
与其他 NLP 算法相比,深度学习有几个优势:
- 灵活的模型:深度学习模型比其他 ML 模型灵活得多。 我们可以轻松地尝试不同的结构,根据需要添加和删除层。 深度学习模型还允许构建具有灵活输出的模型。 灵活性是开发非常适合理解复杂语言结构的模型的关键。 它对于开发 NLP 应用程序(例如翻译、聊天机器人和文本转语音应用程序)也至关重要。
- 需要更少的领域知识:虽然开发一个好的深度学习模型当然需要一些领域知识和直觉,但深度学习算法能够自行学习特征层次结构意味着开发人员不需要对开发深度学习 NLP 算法的问题空间。 对于像自然语言这样复杂的问题空间,这是一个非常受欢迎的优势。
- 更轻松的持续学习:随着新数据的到来,深度学习算法很容易训练。一些机器学习算法需要通过模型发送整个数据集以进行更新,这对于实时的大型数据集来说是一个问题。
今天的问题
今天,我们将构建一个深度学习算法,根据评论文本来确定被评论的葡萄酒的品种。 我们将在 https://www.kaggle.com/zynicide/wine-reviews 使用由 Kaggle 用户zackthoutt提供的葡萄酒杂志数据集。
从概念上讲,问题是,我们可以像…
香气包括热带水果、扫帚、硫磺和干香草。 口感并不过分表现力,提供未成熟的苹果、柑橘和干鼠尾草以及清爽的酸度。
......并认识到它是关于白色混合物的? 一些葡萄酒爱好者可能会识别出白葡萄酒的明显迹象,例如苹果、柑橘和明显的酸度,但我们可以训练我们的神经网络来识别这些信号吗? 此外,我们能否训练我们的神经网络来识别白色混合评论和灰比诺评论之间的细微差别?
类似的算法
我们今天处理的问题本质上是一个 NLP 分类问题。 有几种 NLP 分类算法已应用于 NLP 中的各种问题。 例如,朴素贝叶斯已用于各种垃圾邮件检测算法,支持向量机 (SVM) 已用于对医疗机构的进度说明等文本进行分类。 实现这些算法的简单版本作为我们深度学习模型的基线会很有趣。
朴素贝叶斯
用于 NLP 的朴素贝叶斯的一种流行实现涉及使用 TF-IDF 预处理文本,然后在预处理的输出上运行多项朴素贝叶斯。 这允许算法在文档中最突出的单词上运行。 我们可以如下实现朴素贝叶斯:
import numpy as np from sklearn.naive_bayes import MultinomialNB from sklearn.feature_extraction.text import CountVectorizer import pandas as pd from collections import Counter from sklearn.model_selection import train_test_split from sklearn.feature_extraction.text import TfidfTransformer df = pd.read_csv('data/wine_data.csv') counter = Counter(df['variety'].tolist()) top_10_varieties = {i[0]: idx for idx, i in enumerate(counter.most_common(10))} df = df[df['variety'].map(lambda x: x in top_10_varieties)] description_list = df['description'].tolist() varietal_list = [top_10_varieties[i] for i in df['variety'].tolist()] varietal_list = np.array(varietal_list) count_vect = CountVectorizer() x_train_counts = count_vect.fit_transform(description_list) tfidf_transformer = TfidfTransformer() x_train_tfidf = tfidf_transformer.fit_transform(x_train_counts) train_x, test_x, train_y, test_y = train_test_split(x_train_tfidf, varietal_list, test_size=0.3) clf = MultinomialNB().fit(train_x, train_y) y_score = clf.predict(test_x) n_right = 0 for i in range(len(y_score)): if y_score[i] == test_y[i]: n_right += 1 print("Accuracy: %.2f%%" % ((n_right/float(len(test_y)) * 100)))
运行上面的代码,你应该会看到类似下面的内容: 73.56%
考虑到我们正在查看 10 个类,这是一个相当不错的结果。
我们也可以使用支持向量机,看看它会怎么做。 要查看它的执行情况,只需将分类器定义替换为
clf = SVC(kernel='linear').fit(train_x, train_y)
运行它,您应该会看到以下输出:
准确度: 80.66%
也不会太破旧。
让我们看看我们是否可以建立一个可以超越或至少匹配这些结果的深度学习模型。 如果我们能做到这一点,这将是一个很好的迹象,表明我们的深度学习模型至少可以有效地复制由领域专业知识提供的流行机器学习模型的结果。
构建模型
今天,我们将使用 Keras 和 Tensorflow 来构建我们的模型。 Keras 是一个 Python 库,与 Tensorflow API 的相对低级接口相比,它使构建深度学习模型变得非常容易。 除了密集层之外,我们还将使用嵌入层和卷积层来学习单词的底层语义信息和数据中潜在的结构模式。

数据清洗
首先,我们必须以我们的神经网络可以轻松处理和理解的方式重组数据。 我们可以通过用唯一标识数字替换单词来做到这一点。 结合嵌入向量,我们能够以灵活且语义敏感的方式表示单词。
在实践中,我们希望对这种预处理更聪明一点。 将重点放在常用词上,同时过滤掉最常用的词(例如,the、this、a)是有意义的。
我们可以使用 Defaultdict 和 NLTK 来实现这个功能。 将以下代码写入单独的 Python 模块。 我把它放在lib/get_top_x_words.py
中。
from nltk import word_tokenize from collections import defaultdict def count_top_x_words(corpus, top_x, skip_top_n): count = defaultdict(lambda: 0) for c in corpus: for w in word_tokenize(c): count[w] += 1 count_tuples = sorted([(w, c) for w, c in count.items()], key=lambda x: x[1], reverse=True) return [i[0] for i in count_tuples[skip_top_n: skip_top_n + top_x]] def replace_top_x_words_with_vectors(corpus, top_x): topx_dict = {top_x[i]: i for i in range(len(top_x))} return [ [topx_dict[w] for w in word_tokenize(s) if w in topx_dict] for s in corpus ], topx_dict def filter_to_top_x(corpus, n_top, skip_n_top=0): top_x = count_top_x_words(corpus, n_top, skip_n_top) return replace_top_x_words_with_vectors(corpus, top_x)
现在我们准备好构建模型了。 我们想要一个嵌入层、一个卷积层和一个密集层来利用所有对我们的应用程序有帮助的深度学习特征。 使用 Keras,我们可以非常简单地构建模型:
from keras.models import Sequential from keras.layers import Dense, Conv1D, Flatten from keras.layers.embeddings import Embedding from keras.preprocessing import sequence from keras.utils import to_categorical import pandas as pd from collections import Counter from sklearn.model_selection import train_test_split from lib.get_top_xwords import filter_to_top_x df = pd.read_csv('data/wine_data.csv') counter = Counter(df['variety'].tolist()) top_10_varieties = {i[0]: idx for idx, i in enumerate(counter.most_common(10))} df = df[df['variety'].map(lambda x: x in top_10_varieties)] description_list = df['description'].tolist() mapped_list, word_list = filter_to_top_x(description_list, 2500, 10) varietal_list_o = [top_10_varieties[i] for i in df['variety'].tolist()] varietal_list = to_categorical(varietal_list_o) max_review_length = 150 mapped_list = sequence.pad_sequences(mapped_list, maxlen=max_review_length) train_x, test_x, train_y, test_y = train_test_split(mapped_list, varietal_list, test_size=0.3) max_review_length = 150 embedding_vector_length = 64 model = Sequential() model.add(Embedding(2500, embedding_vector_length, input_length=max_review_length)) model.add(Conv1D(50, 5)) model.add(Flatten()) model.add(Dense(100, activation='relu')) model.add(Dense(max(varietal_list_o) + 1, activation='softmax')) model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) model.fit(train_x, train_y, epochs=3, batch_size=64) y_score = model.predict(test_x) y_score = [[1 if i == max(sc) else 0 for i in sc] for sc in y_score] n_right = 0 for i in range(len(y_score)): if all(y_score[i][j] == test_y[i][j] for j in range(len(y_score[i]))): n_right += 1 print("Accuracy: %.2f%%" % ((n_right/float(len(test_y)) * 100)))
运行代码,您应该会看到以下输出。
准确度: 77.20%
回想一下,朴素贝叶斯和 SVC 的准确率分别为 73.56% 和 80.66%。 因此,我们的神经网络非常适合一些更常见的文本分类方法。
结论
今天,我们介绍了构建分类深度学习模型来分析葡萄酒评论。
我们发现我们能够构建一个能够与其他一些机器学习算法竞争并优于其他一些机器学习算法的模型。 我们希望您受到启发,使用这些信息来构建分析更复杂数据集并生成更复杂输出的应用程序!
注意:你可以在 GitHub 上找到我用于本文的代码。
进一步阅读 Toptal 工程博客:
- 更深层次的含义:Python 中的主题建模
- 如何构建电子邮件情绪分析机器人:NLP 教程