Kaggle word2vec NLP 教程 第二部分:词向量
原文:Bag of Words Meets Bags of Popcorn
译者:飞龙
自豪地采用谷歌翻译
第二部分:词向量
代码
第二部分的教程代码在这里。
分布式词向量简介
本教程的这一部分将重点介绍使用 Word2Vec 算法创建分布式单词向量。 (深度学习的概述,以及其他一些教程的链接,请参阅“什么是深度学习?”页面)。
第 2 部分和第 3 部分比第 1 部分假设你更熟悉Python。我们在双核 Macbook Pro 上开发了以下代码,但是,我们还没有在 Windows 上成功运行代码。如果你是 Windows 用户并且使其正常运行,请在论坛中留言如何进行操作!更多详细信息,请参阅“配置系统”页面。
Word2vec,由 Google 于 2013 年发表,是一种神经网络实现,可以学习单词的分布式表示。在此之前已经提出了用于学习单词表示的其他深度或循环神经网络架构,但是这些的主要问题是训练模型所需时长间。 Word2vec 相对于其他模型学习得快。
Word2Vec 不需要标签来创建有意义的表示。这很有用,因为现实世界中的大多数数据都是未标记的。如果给网络足够的训练数据(数百亿个单词),它会产生特征极好的单词向量。具有相似含义的词出现在簇中,并且簇具有间隔,使得可以使用向量数学来再现诸如类比的一些词关系。着名的例子是,通过训练好的单词向量,“国王 - 男人 + 女人 = 女王”。
查看 Google 的代码,文章和附带的论文。 此演示也很有帮助。 原始代码是 C 写的,但它已被移植到其他语言,包括 Python。 我们鼓励你使用原始 C 工具,但如果你是初学程序员(我们必须手动编辑头文件来编译),请注意它不是用户友好的。
最近斯坦福大学的工作也将深度学习应用于情感分析;他们的代码以 Java 提供。 但是,他们的方法依赖于句子解析,不能直接应用于任意长度的段落。
分布式词向量强大,可用于许多应用,尤其是单词预测和转换。 在这里,我们将尝试将它们应用于情感分析。
在 Python 中使用 word2vec
在 Python 中,我们将使用gensim
包中的 word2vec 的优秀实现。 如果你还没有安装gensim
,则需要安装它。 这里有一个包含 Python Word2Vec 实现的优秀教程。
虽然 Word2Vec 不像许多深度学习算法那样需要图形处理单元(GPU),但它是计算密集型的。 Google 的版本和 Python 版本都依赖于多线程(在你的计算机上并行运行多个进程以节省时间)。 为了在合理的时间内训练你的模型,你需要安装 cython(这里是指南)。 Word2Vec 可在没有安装 cython 的情况下运行,但运行它需要几天而不是几分钟。
为训练模型做准备
现在到了细节! 首先,我们使用pandas
读取数据,就像我们在第 1 部分中所做的那样。与第 1 部分不同,我们现在使用unlabeledTrain.tsv
,其中包含 50,000 个额外的评论,没有标签。 当我们在第 1 部分中构建词袋模型时,额外的未标记的训练评论没有用。 但是,由于 Word2Vec 可以从未标记的数据中学习,现在可以使用这些额外的 50,000 条评论。
import pandas as pd # 从文件读取数据 train = pd.read_csv( "labeledTrainData.tsv", header=0, delimiter="\t", quoting=3 ) test = pd.read_csv( "testData.tsv", header=0, delimiter="\t", quoting=3 ) unlabeled_train = pd.read_csv( "unlabeledTrainData.tsv", header=0, delimiter="\t", quoting=3 ) # 验证已读取的评论数量(总共 100,000 个) print "Read %d labeled train reviews, %d labeled test reviews, " \ "and %d unlabeled reviews\n" % (train["review"].size, test["review"].size, unlabeled_train["review"].size )
我们为清理数据而编写的函数也与第 1 部分类似,尽管现在存在一些差异。 首先,为了训练 Word2Vec,最好不要删除停止词,因为算法依赖于句子的更广泛的上下文,以便产生高质量的词向量。 因此,我们将在下面的函数中,将停止词删除变成可选的。 最好不要删除数字,但我们将其留作读者的练习。
# Import various modules for string cleaning from bs4 import BeautifulSoup import re from nltk.corpus import stopwords def review_to_wordlist( review, remove_stopwords=False ): # 将文档转换为单词序列的函数,可选地删除停止词。 返回单词列表。 # # 1. 移除 HTML review_text = BeautifulSoup(review).get_text() # # 2. 移除非字母 review_text = re.sub("[^a-zA-Z]"," ", review_text) # # 3. 将单词转换为小写并将其拆分 words = review_text.lower().split() # # 4. 可选地删除停止词(默认为 false) if remove_stopwords: stops = set(stopwords.words("english")) words = [w for w in words if not w in stops] # # 5. 返回单词列表 return(words)
接下来,我们需要一种特定的输入格式。 Word2Vec 需要单个句子,每个句子都是一列单词。 换句话说,输入格式是列表的列表。
如何将一个段落分成句子并不简单。 自然语言中有各种各样的问题。 英语句子可能以“?”,“!”,“"”或“.”等结尾,并且间距和大写也不是可靠的标志。因此,我们将使用 NLTK 的punkt
分词器进行句子分割。为了使用它,你需要安装 NLTK 并使用nltk.download()
下载punkt
的相关训练文件。
# 为句子拆分下载 punkt 分词器 import nltk.data nltk.download() # 加载 punkt 分词器 tokenizer = nltk.data.load('tokenizers/punkt/english.pickle') # 定义一个函数将评论拆分为已解析的句子 def review_to_sentences( review, tokenizer, remove_stopwords=False ): # 将评论拆分为已解析句子的函数。 # 返回句子列表,其中每个句子都是单词列表 # 1. 使用 NLTK 分词器将段落拆分为句子 raw_sentences = tokenizer.tokenize(review.strip()) # # 2. 遍历每个句子 sentences = [] for raw_sentence in raw_sentences: # 如果句子为空,则跳过 if len(raw_sentence) > 0: # 否则,调用 review_to_wordlist 来获取单词列表 sentences.append( review_to_wordlist( raw_sentence, \ remove_stopwords )) # 返回句子列表(每个句子都是单词列表, # 因此返回列表的列表) return sentences
现在我们可以应用此函数,来准备 Word2Vec 的输入数据(这将需要几分钟):
sentences = [] # 初始化空的句子列表 print "Parsing sentences from training set" for review in train["review"]: sentences += review_to_sentences(review, tokenizer) print "Parsing sentences from unlabeled set" for review in unlabeled_train["review"]: sentences += review_to_sentences(review, tokenizer)
你可能会从BeautifulSoup
那里得到一些关于句子中 URL 的警告。 这些都不用担心(尽管你可能需要考虑在清理文本时删除 URL)。
我们可以看一下输出,看看它与第 1 部分的不同之处:
>>> # 检查我们总共有多少句子 - 应该是 850,000+ 左右 ... print len(sentences) 857234 >>> print sentences[0] [u'with', u'all', u'this', u'stuff', u'going', u'down', u'at', u'the', u'moment', u'with', u'mj', u'i', u've', u'started', u'listening', u'to', u'his', u'music', u'watching', u'the', u'odd', u'documentary', u'here', u'and', u'there', u'watched', u'the', u'wiz', u'and', u'watched', u'moonwalker', u'again'] >>> print sentences[1] [u'maybe', u'i', u'just', u'want', u'to', u'get', u'a', u'certain', u'insight', u'into', u'this', u'guy', u'who', u'i', u'thought', u'was', u'really', u'cool', u'in', u'the', u'eighties', u'just', u'to', u'maybe', u'make', u'up', u'my', u'mind', u'whether', u'he', u'is', u'guilty', u'or', u'innocent']
需要注意的一个小细节是 Python 列表中+=
和append
之间的区别。 在许多应用中,这两者是可以互换的,但在这里它们不是。 如果要将列表列表附加到另一个列表列表,append
仅仅附加外层列表; 你需要使用+=
才能连接所有内层列表。
译者注:原文中这里的解释有误,已修改。
训练并保存你的模型
使用精心解析的句子列表,我们已准备好训练模型。 有许多参数选项会影响运行时间和生成的最终模型的质量。 以下算法的详细信息,请参阅 word2vec API 文档以及 Google 文档。
- 架构:架构选项是 skip-gram(默认)或 CBOW。 我们发现 skip-gram 非常慢,但产生了更好的结果。
- 训练算法:分层 softmax(默认)或负采样。 对我们来说,默认效果很好。
- 对频繁词汇进行下采样:Google 文档建议值介于
.00001
和.001
之间。 对我们来说,接近0.001的值似乎可以提高最终模型的准确性。 - 单词向量维度:更多特征会产生更长的运行时间,并且通常(但并非总是)会产生更好的模型。 合理的值可能介于几十到几百;我们用了 300。
- 上下文/窗口大小:训练算法应考虑多少个上下文单词? 10 似乎适用于分层 softmax(越多越好,达到一定程度)。
- 工作线程:要运行的并行进程数。 这是特定于计算机的,但 4 到 6 之间应该适用于大多数系统。
- 最小词数:这有助于将词汇量的大小限制为有意义的单词。 在所有文档中,至少没有出现这个次数的任何单词都将被忽略。 合理的值可以在 10 到 100 之间。在这种情况下,由于每个电影出现 30 次,我们将最小字数设置为 40,来避免过分重视单个电影标题。 这导致了整体词汇量大约为 15,000 个单词。 较高的值也有助于限制运行时间。
选择参数并不容易,但是一旦我们选择了参数,创建 Word2Vec 模型就很简单:
# 导入内置日志记录模块并配置它,以便 Word2Vec 创建良好的输出消息 import logging logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s',\ level=logging.INFO) # 设置各种参数的值 num_features = 300 # 词向量维度 min_word_count = 40 # 最小单词数 num_workers = 4 # 并行运行的线程数 context = 10 # 上下文窗口大小 downsampling = 1e-3 # 为频繁词设置下采样 # 初始化并训练模型(这需要一些时间) from gensim.models import word2vec print "Training model..." model = word2vec.Word2Vec(sentences, workers=num_workers, \ size=num_features, min_count = min_word_count, \ window = context, sample = downsampling) # 如果你不打算再进一步训练模型, # 则调用 init_sims 将使模型更具内存效率。 model.init_sims(replace=True) # 创建有意义的模型名称并保存模型以供以后使用会很有帮助。 # 你可以稍后使用 Word2Vec.load() 加载它 model_name = "300features_40minwords_10context" model.save(model_name)
在双核 Macbook Pro 上,使用 4 个工作线程来运行,花费不到 15 分钟。 但是,它会因你的计算机而异。 幸运的是,日志记录功能可以打印带有信息的消息。
如果你使用的是 Mac 或 Linux 系统,则可以使用终端内(而不是来自 Python 内部)的top
命令,来查看你的系统是否在模型训练时成功并行化。 键入:
> top -o cpu
在模型训练时进入终端窗口。 对于 4 个 worker,列表中的第一个进程应该是 Python,它应该显示 300-400% 的 CPU 使用率。
如果你的 CPU 使用率较低,则可能是你的计算机上的 cython 无法正常运行。
探索模型结果
恭喜你到目前为止成功通过了一切! 让我们来看看我们在 75,000 个训练评论中创建的模型。
doesnt_match
函数将尝试推断集合中哪个单词与其他单词最不相似:
>>> model.doesnt_match("man woman child kitchen".split()) 'kitchen'
我们的模型能够区分意义上的差异! 它知道男人,女人和孩子彼此更相似,而不是厨房。 更多的探索表明,该模型对意义上更微妙的差异敏感,例如国家和城市之间的差异:
>>> model.doesnt_match("france england germany berlin".split()) 'berlin'
…虽然我们使用的训练集相对较小,但肯定不完美:
>>> model.doesnt_match("paris berlin london austria".split()) 'paris'
我们还可以使用most_similar
函数来深入了解模型的单词簇:
>>> model.most_similar("man") [(u'woman', 0.6056041121482849), (u'guy', 0.4935004413127899), (u'boy', 0.48933547735214233), (u'men', 0.4632953703403473), (u'person', 0.45742249488830566), (u'lady', 0.4487500488758087), (u'himself', 0.4288588762283325), (u'girl', 0.4166809320449829), (u'his', 0.3853422999382019), (u'he', 0.38293731212615967)] >>> model.most_similar("queen") [(u'princess', 0.519856333732605), (u'latifah', 0.47644317150115967), (u'prince', 0.45914226770401), (u'king', 0.4466976821422577), (u'elizabeth', 0.4134873151779175), (u'antoinette', 0.41033703088760376), (u'marie', 0.4061327874660492), (u'stepmother', 0.4040161967277527), (u'belle', 0.38827288150787354), (u'lovely', 0.38668593764305115)]
鉴于我们特定的训练集,“Latifah”与“女王”的相似性最高,也就不足为奇了。
或者,与情感分析更相关:
>>> model.most_similar("awful") [(u'terrible', 0.6812670230865479), (u'horrible', 0.62867271900177), (u'dreadful', 0.5879652500152588), (u'laughable', 0.5469599962234497), (u'horrendous', 0.5167273283004761), (u'atrocious', 0.5115568041801453), (u'ridiculous', 0.5104714632034302), (u'abysmal', 0.5015234351158142), (u'pathetic', 0.4880446791648865), (u'embarrassing', 0.48272213339805603)]
因此,似乎我们有相当好的语义意义模型 - 至少和词袋一样好。 但是,我们如何才能将这些花哨的分布式单词向量用于监督学习呢? 下一节将对此进行一次尝试。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
JVM致命错误日志(hs_err_pid.log)分析
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xmt1139057136/article/details/82880179 致命错误出现的时候,JVM 生成了 hs_err_pid<pid>.log 这样的文件,其中往往包含了虚拟机崩溃原因的重要信息。因为经常遇到,在这篇文章里,我挑选了一个,并且逐段分析它包含的内容(文件可以在文章最后下载)。默认情况下文件是创建在工作目录下的(如果没权限创建的话 JVM 会尝试把文件写到/tmp 这样的临时目录下面去),当然,文件格式和路径也可以通过参数指定,比如: 1 java -XX:ErrorFile=/var/log/java/java_error%p.log 这个文件将包括: 触发致命错误的操作异常或者信号; 版本和配置信息; 触发致命异常的线程详细信息和线程栈; 当前运行的线程列表和它们的状态; 堆的总括信息; 加载的本地库; 命令行参数; 环境变量; 操作系统 CPU 的详细信息。 首先,看到的是对问题的概要介绍: 1 # SIGSEGV (0xb) at pc=0x035...
- 下一篇
Eclipse 4.9 正式发布,支持 Java 11!
来看看 Eclipse 4.9 带来了哪些新特性! 1、外观 新增类似大纲视图的”Minimap” 间主题/暗黑主题,启用方法: Window > Show View > Other,然后在 Show View 对话框中选择General > Minimap 或在Quick Access 搜索框输入“minimap” 改进暗黑主题中的“面包屑导航 (Breadcrumb)” Java 编辑器中的“面包屑导航”在暗黑主题中现在使用了黑色背景,而在日间主题中也使用了扁平化的风格。其实觉得还是别扭,没有 IDEA 中的漂亮,推荐大家阅读Intellij Idea非常6的10个姿势。 2、功能 Project Explorer 可在项目层次结构上显示有问题的标记 使用 Project Explorer 的Projects Presentation > Hierarchical模式时,子项目中的错误标记现在会报告给父节点,包括其他项目中的父项目和文件夹。通过该功能我们可以轻松检测错误,并在项目层次结构折叠时从 Project Explorer 中浏览错误。 创建抽象方法的...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Red5直播服务器,属于Java语言的直播服务器
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS8编译安装MySQL8.0.19
- CentOS6,CentOS7官方镜像安装Oracle11G
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- CentOS7设置SWAP分区,小内存服务器的救世主