全文共3640字,预计学习时长7分钟
这篇文章是写给有数据科学技术知识背景的读者看的。本文将探索如何使用快速句子嵌入来使著名的亚马逊评论数据集可视化。本文所涉及的技术工具有fse、FIt-SNE和Tableau。
上图显示了这条管道的结果。在文末,有一个指向交互式Tableau映射的链接,可以浏览所有100,000个产品。
数据
如果你经常用NLP,就很可能听说过斯坦福亚马逊评论数据集(http://jmcauley.ucsd.edu/data/amazon/)。第二大类是“电子”类,共有7824482篇评论。
为了获得每个产品的嵌入,需要评审数据和元数据。两者都是通过唯一的ASIN亚马逊标识连接的。先来看看元数据:
为了得到可视化数据(即把每个产品表示为可映射的向量),只能利用每个产品的评论。因此,我们处理的是多对一嵌入。在筛选出少于10个评论的ASIN后,最终得到了97249个ASIN和6875530条评论。
我们不对文本数据进行任何预处理。 为什么呢? 因为……
从评论到产品嵌入
为了获得每个评论的嵌入,首先需要某种预处理嵌入。评论很可能包含许多未知的词语。幸运的是,fse在FastText开箱即用模型中起到了作用。我们首先加载公开可用的FastText 模型(https://fasttext.cc/docs/en/english-vectors.html):
from gensim.models.keyedvectors import FastTextKeyedVectors
ft =
FastTextKeyedVectors.load("../models/ft_crawl_300d_2m.model")
接着,从fse实例化SIF模型。
from fse.models import SIF
model = SIF(ft, components=10, lang_freq="en")
组件数量等于10,这会在STS基准再现性部分中阐述。
lang_freq参数。一些预先训练的嵌入不包含语料库中的词频信息。fse支持为多种语言的预训练模型收集归纳词频(可能需要一段时间,不过具体取决于词汇量的大小),这对SIF和uSIF模型来说必不可少。
所有fse模型都是要求输入元组列表。元组的第一个条目是标记列表(句子),第二个条目是句子索引。后者决定了句子被嵌入矩阵中的目标行。我们稍后将在一行(多对一)上写多个句子(评论)。
s = (["Hello", "world"], 0)
fse提供多个输入类,都具有不同的功能。这里提供了有6个输入类选择:
• IndexedList(索引列表):用于已预拆分的句子。
• CIndexedList:用于有自定义索引的已预拆分句子。
• SplitIndexedList: 用于未拆分的句子,会把字符串分开。
• SplitCIndexedList:用于有自定义索引的未拆分句子。
• CSplitIndexedList:用于未拆分的句子,会把字符串分开。可以提供自定义拆分功能。
• CSplitCIndexedList:用于提供自定义索引和自定义拆分功能的句子。
• IndexedLineDocument: 用于从磁盘流式传输句子。是可索引的,以便于搜索相似的句子。
上述输入类是按速度排序的。也就是说,IndexedList是最快的,而CSplitCIndexedList是最慢的变量(调用越多=越慢)。为什么要那么多类?因为我们希望减少每个__getitem__方法的代码行,以免影响到计算速度。
审核数据使用的是SplitCIndexedList,因为不想预拆分数据(预拆分的700万评论占用了大量内存)。在内部,该输入类主要指向评论,并且只有在调用__getitem__时才会执行预处理。
从fse导入SplitCIndexedList
review = ["I really like this product.", "Its nice and comfy."]
s = SplitCIndexedList(review, custom_index = [0, 0])
print(s[0])
print(s[1])
>>> (['I', 'really', 'like', 'this', 'product.'], 0)
>>> (['Its', 'nice', 'and', 'comfy.'], 0)
敲黑板,这两个句子都指向索引0。因此,它们都将被添加到索引为0的嵌入中。要将每个ASIN映射到一个索引,只需要一些更便于操作的函数。
从 fse导入SplitCIndexedList
ASIN_TO_IDX = {asin : index for index, asin in enumerate(meta.index)}
indexed_reviews = SplitCIndexedList(data.reviewText.values, custom_index = [ASIN_TO_IDX[asin] for asin in data.asin])
现在一切就位,只需运行
model.train(indexed_reviews)
该模型是在一个16核32GB内存的云实例基础上训练的。整个过程大约需要15分钟,每秒约8500个评论。平均每个评论包含86个词语,一共有593774622个单词。我们会把大约700万条的评论压缩成100000*300的矩阵。这时候再调用更多的功能也没什么用,因为预处理(分裂)已经达到瓶颈。
如果数据已经被预分割,那么在普通的MacBook Pro上操作时可以达到每秒500000个句子。
想了解更多,请参看教程笔记本:https://github.com/oborchers/Fast_Sentence_Embeddings/blob/master/notebooks/Tutorial.ipynb
嵌入与可视化
训练句子嵌入后,可以通过每个嵌入的索引或完整的嵌入矩阵来访问每个单独的嵌入。语法要尽可能地接近gensims语法,以便于使用。
model.sv[0] # Access embedding with index 0
model.sv.vectors # Access embedding matrix
相应的句子向量(sv)类提供了相当多的函数来处理获取的句子嵌入。例如,可以参考相似性、距离、最相似、逐字相似、逐句相似或逐字相似向量的功能。
如果用标准的sklearn t-SNE来可视化这么多数据可能需要非常长的时间。因此,可以尝试一种更优化的方法:FIt-SNE。这种优化的t-SNE可视化操作是利用傅立叶变换来加速t-SNE的计算。没事可以翻翻论文[4]。魔法般地使用了机器的所有16个内核。
import sys; sys.path.append('../FIt-SNE')
from fast_tsne import fast_tsne
mapping = fast_tsne(model.sv.vectors, perplexity=50, seed=42)
在计算了映射之后,就有效完成了最困难的部分。将元数据中的一些信息添加到每个点,最终可以将所有内容导出到Tableau。
Tableau映射
要访问相应的图形,请访问“my public tableau”页面:
https://public.tableau.com/views/ProductMap_15674406439260/TSNEPrice?:embed=y&:display_count=yes&:origin=viz_share_link
可以将鼠标悬停在每个点上,以获取产品价格、名称、品牌等信息。
从嵌入的角度来看,每个集群中包含了相当多的信息。
此外,进入数据,手动标记一些集群,以确定集群的形成在某种程度上是否有效。这种映射捕获了评论中包含的大量信息。
记住:我们所做的就是平均每个评论中的单词数,并总结所有评论。令人震惊的是基于平均值的嵌入是可行的。
结论
句子嵌入是NLP流水线的重要组成部分。本文介绍了如何使用快速句子嵌入、FIt-SNE以及Tableau来可视化众所周知的亚马逊评论数据集。
希望你能从使用fse中找到乐趣。欢迎大家随时提出其他的模型或功能。
相应的FSE软件包可以在pip / Github上运行,给数据科学家提供了一种快速计算句子嵌入的方法。
提示:本文需要常规的Python (>3.6)包,尤其是Numpy、Scipy、Cython和Gensim。
推荐阅读专题
留言 点赞 关注
我们一起分享AI学习与发展的干货
欢迎关注全平台AI垂类自媒体 “读芯术”
(添加小编微信:dxsxbb,加入读者圈,一起讨论最新鲜的人工智能科技哦~)