统计一行文本的单词个数_NLP中的文本表示方法
先回顾下数据挖掘和计算机视觉任务。数据挖掘中给定n个样本,每个样本有m个特征,这样组成了n×m的样本矩阵,然后丢给计算机中建好的模型进行回归或分类任务。计算机视觉中我们把图片的像素看作特征,每张图片看作hight×width×3的特征图,一个三维的矩阵来进入计算机进行计算。
在NLP任务中同样需要如此,我们要把文字表示成计算机能够运算的数字或向量。下面对文本表示方法进行梳理,一般称为词嵌入(Word Embedding)方法。词嵌入这个说法其实很形象,我们的做法就是把文本中的词嵌入到文本空间中,用一个向量来表示它。
离散表示
One-hot
One-hot表示很容易理解。在一个语料库中,给每个字/词编码一个索引,根据索引进行one-hot表示。
John likes to watch movies. Mary likes too.
John also likes to watch football games.
如果只需要表示出上面两句话中的单词,可以只对其中出现过的单词进行索引编码:
{"John": 1, "likes": 2, "to": 3, "watch": 4, "movies": 5, "also":6, "football": 7,
"games": 8, "Mary": 9, "too": 10}
其中的每个单词都可以用one-hot方法表示:
John: [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
likes: [0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
...
当语料库非常大时,需要建立一个很大的字典对所有单词进行索引编码。比如100W个单词,每个单词就需要表示成100W维的向量,而且这个向量是很稀疏的,只有一个地方为1其他全为0。还有很重要的一点,这种表示方法无法表达单词与单词之间的相似程度,如beautiful
和pretty
可以表达相似的意思但是ont-hot法无法将之表示出来。
Bag of Words
词袋表示,也称为计数向量表示(Count Vectors)。文档的向量表示可以直接用单词的向量进行求和得到。
John likes to watch movies. Mary likes too. -->> [1, 2, 1, 1, 1, 0, 0, 0, 1, 1]
John also likes to watch football games. -->> [1, 1, 1, 1, 0, 1, 1, 1, 0, 0]
横向来看我们把每条文本表示成了一个向量,纵向来看,不同文档中单词的个数又可以构成某个单词的词向量。如上文中的"John"
纵向表示成[1,1]
。
其具体实现可以采用sklearn
中的CountVectorizer
。
count_vect = CountVectorizer(analyzer='word')
count_vect.fit(trainDF['text']) #假定已经读进来了DataFrame,'text'列为文本列,
#每行为一条文本。此句代码基于所有语料库生成单词的词典。
xtrain_count = count_vect.transform(train_x)
Bi-gram和N-gram
与词袋模型原理类似,Bi-gram将相邻两个单词编上索引,N-gram将相邻N个单词编上索引。
为 Bi-gram建立索引:
{"John likes”: 1,
"likes to”: 2,
"to watch”: 3,
"watch movies”: 4,
"Mary likes”: 5,
"likes too”: 6,
"John also”: 7,
"also likes”: 8,
"watch football": 9,
"football games": 10}
这样,原来的两句话就可以表示为:
John likes to watch movies. Mary likes too. -->> [1, 1, 1, 1, 1, 1, 0, 0, 0, 0]
John also likes to watch football games. -->> [0, 1, 1, 0, 0, 0, 1, 1, 1, 1]
这种做法的优点是考虑了词的顺序,但是缺点也很明显,就是造成了词向量的急剧膨胀。
TF-IDF
上面的词袋模型和Bi-gram、N-gram模型是基于计数得到的,而TF-IDF则是基于频率统计得到的。TF-IDF的分数代表了词语在当前文档和整个语料库中的相对重要性。TF-IDF 分数由两部分组成:第一部分是词语频率(Term Frequency),第二部分是逆文档频率(Inverse Document Frequency)。其中计算语料库中文档总数除以含有该词语的文档数量,然后再取对数就是逆文档频率。
TF(t)= 该词语在当前文档出现的次数 / 当前文档中词语的总数
IDF(t)= log_e(文档总数 / 出现该词语的文档总数)
根据公式可以看出,TF 判断的是该字/词语是否是当前文档的重要词语,但是如果只用词语出现频率来判断其是否重要可能会出现一个问题,就是有些通用词可能也会出现很多次,如:a、the、at、in
等。当然我们对文本进行预处理的时候一般会去掉这些所谓的stopwords
,即停用词,但仍然会有很多通用词无法避免地出现在很多文档,而其实它们不是那么重要。
逆文档频率(IDF)用于判断是否在很多文档中都出现了此词语,即很多文档或所有文档中都出现的就是通用词。出现该词语的文档越多,IDF越小,其作用是抑制通用词的重要性。
将上述求出的 TF 和 IDF 相乘记得到词语在当前文档和整个语料库中的相对重要性。TF-IDF与一个词在当前文档中的出现次数成正比,与该词在整个语料库中的出现次数成反比
TF-IDF算法的优点是简单快速,结果比较符合实际情况。缺点是,单纯以"词频"衡量一个词的重要性,不够全面,有时重要的词可能出现次数并不多。而且,这种算法无法体现词的位置信息,出现位置靠前的词与出现位置靠后的词,都被视为重要性相同,这是不正确的。
可以使用sklearn
中的TfidfVectorizer
生成TF-IDF特征。
# word level tf-idf
tfidf_vect = TfidfVectorizer(analyzer='word', token_pattern=r'w{1,}', max_features=5000)
tfidf_vect.fit(trainDF['text'])
xtrain_tfidf = tfidf_vect.transform(train_x)
# ngram level tf-idf
tfidf_vect_ngram = TfidfVectorizer(analyzer='word', token_pattern=r'w{1,}', ngram_range=(2,3), max_features=5000)
tfidf_vect_ngram.fit(trainDF['text'])
xtrain_tfidf = tfidf_vect.transform(train_x)
共现矩阵 (Cocurrence matrix)
首先解释下“共现”,即共同出现,如一句话中共同出现,或一篇文章中共同出现。这里给共同出现的距离一个规范——窗口,如果窗口宽度是2,那就是在当前词的前后各2个词的范围内共同出现。可以想象,其实是一个总长为5的窗口依次扫过所有文本,同时出现在其中的词就说它们共现。
John likes to watch movies.
John likes to play basketball.
上面两句话设窗口宽度为1,则共现矩阵如下:
可以看到,当前词与自身不存在共现,共现矩阵实际上是对角矩阵。
实际应用中,我们用共现矩阵的一行(列)作为某个词的词向量,其向量维度还是会随着字典大小呈线性增长,而且存储共生矩阵可能需要消耗巨大的内存。一般配合PCA或SVD将其进行降维,如将原来 m×n 的矩阵降为 m×r的矩阵,其中 r<n,即将词向量的长度进行缩减。
下面是奇异值分解的步骤。
分布式表示
离散表示虽然能够进行词语或者文本的向量表示,进而用模型进行情感分析或是文本分类之类的任务,但其不能表示词语间的相似程度或者词语间的类比关系。比如前面提到的beautiful
和pretty
,它们表达相近的意思,所以我们希望它们在整个文本的表示空间内挨得很近。一般认为词向量/文本向量之间的夹角越小,两个词相似度越高。
离散表示如one-hot表示法无法表示上面的关系,引入分布式表示方法,其主要思想是用周围的词表示该词。
NNLM(Neural Network Language model)
2003年提出了A Neural Probabilistic Language Model,其用前n-1个词预测第n个词的概率,并用神经网络搭建模型。
目标函数:
使用非对称的前向窗口,长度为n-1,滑动窗口遍历整个语料库求和,使得目标概率最大化,其计算量正比于语料库大小。同时,预测所有词的概率总和应为1。
下面是NNLM的网络结构:
样本的一组输入是第n个词的前n-1个词的one-hot表示,目标是预测第n个词,输出层的大小是语料库中所有词的数量,然后sotfmax回归,使用反向传播不断修正神经网络的权重来最大化第n个词的概率。当神经网络学得到权重能够很好地预测第n个词的时候,输入层到映射层,即 这层,其中的权重Matrix C 被称为投影矩阵,输入层各个词的ont-hot表示法只在其对应的索引位置为1,其他全为0,在与Matrix C 矩阵相乘时相当于在对应列取出列向量投影到映射层。
此时的向量就是原词的分布式表示,其是稠密向量而非原来one-hot的稀疏向量了。
在后面的隐藏层将这n-1个稠密的词向量进行拼接,如果每个词向量的维度为D,则隐藏层的神经元个数为 (n-1)×D,然后接一个所有待预测词数量的全连接层,最后用softmax进行预测。
可以看到,在隐藏层和分类层中间的计算量应该是很大的,word2vec算法从这个角度出发对模型进行了简化。word2vec不是单一的算法,而是两种算法的结合:连续词袋模型(CBOW)和跳字模型(Skip-gram)。
CBOW
先来看下论文中给出的CBOW和Skip-gram模型的原理示意:
连续词袋模型在NNLM基础上有以下几点创新:
- 取消了隐藏层,减少了计算量
- 采用上下文划窗而不只是前文划窗,即用上下文的词来预测当前词
- 投影层不再使用各向量拼接的方式,而是简单的求和平均
其目标函数为:
可以看到,上面提到的取消隐藏层,投影层求和平均都可以一定程度上减少计算量,但输出层的数量在那里,比如语料库有500W个词那么隐藏层就要对500W个神经元进行全连接计算,这依然需要庞大的计算量。word2vec算法又在这里进行了训练优化。
层级softmax
先来了解下霍夫曼树。霍夫曼树是一棵特殊的二叉树,了解霍夫曼树之前先给出几个定义:
- 路径长度:在二叉树路径上的分支数目,其等于路径上结点数-1
- 结点的权:给树的每个结点赋予一个非负的值
- 结点的带权路径长度:根结点到该结点之间的路径长度与该节点权的乘积
- 树的带权路径长度:所有叶子节点的带权路径长度之和
霍夫曼树的定义为:在权为
最优二叉树或霍夫曼树。
可以看出,结点的权越小,其离树的根结点越远。
word2vec算法利用霍夫曼树,将平铺型softmax压缩成层级softmax,不再使用全连接。具体做法是根据文本的词频统计,将词频赋给结点的权。
在霍夫曼树中,叶子结点是待预测的所有词,在每个子结点处,用sigmoid激活后得到往左走的概率p,往右走的概率为1-p。最终训练的目标是最大化叶子结点处预测词的概率。
层级softmax的实现有点复杂,暂时先搞清楚大致原理~
负例采样 Negative Sampling
负例采样的想法比较简单,假如有m个待预测的词,每次预测一个正样本词,其他的m-1个词均为负样本。一方面正负样本数差别太大,另一方面负样本中可能有很多不常用或者的词预测时概率基本为0,我们不想在计算它们的概率上面消耗资源。
比如现在待预测词有100W个,正常情况下我们分类的全连接层需要100W个神经元,我们可以根据词语的出现频率进行负例采样,一个正样本加上采样出的比如说999个负样本,组成1000个新的分类全连接层。
采样尽量保持了跟原样本一样的分布,具体做法是将[0,1]区间均分108份,然后根据词出现在语料库中的次数赋予每个词不同的份额。
然后在[0,1]区间掷骰子,落在哪个区间内就采样哪个样本。实际上,最终效果证明上式中取counter(w)的3/4次方效果最好,所以在应用中也是这么做的。
Skip-gram
skip-gram模型与CBOW模型相反,它是用当前词来预测上下文的词。也是用当前词的one-hot向量经过投影矩阵得到其稠密表示,然后预测其周围词的one-hot向量,即网络的输出有多个,但是投影层到分类层的权重。具体实现时,(暂时想法)搭好一个输出的网络之后,如果要预测周围的4个词,可以将y的one-hot表示分别作为输出,进行四次网络的正向传播,然后使其loss之和最小。
fasttext
fasttext的模型与CBOW类似,实际上,fasttext的确是由CBOW演变而来的。CBOW预测上下文的中间词,fasttext预测文本标签。与word2vec算法的衍生物相同,稠密词向量也是在训练神经网络的过程中得到的。
fasttext的输入是一段词的序列,即一篇文章或一句话,输出是这段词序列属于某个类别的概率,所以fasttext是用来做文本分类任务的(暂时了解来看是这样~~)。
fasttext中采用层级softmax做分类,这与CBOW相同。fasttext算法中还考虑了词的顺序问题,即采用N-gram,与之前介绍离散表示时的做法相同。如:今天天气非常不错,Bi-gram的表示就是:今天、天天、天气、气非、非常、常不、不错。
fasttext做文本分类对文本的存储方式有要求:
__label__1, It is a nice day.
__label__2, I am fine,thank you.
__label__3, I like play football.
其中的__label__为实际类别的前缀,也可以自己定义。
fasttext有python实现:https://github.com/salestock/fastText.py
classifier = fasttext.supervised(input_file, output, label_prefix='__label__')
result = classifier.test(test_file)
print(result.precision,result.recall)
其中,input_file
是已经按上面的格式要求做好的训练集txt,output
后缀为.model
,是我们保存的二进制文件,label_prefix
可以自定义我们的类别前缀。当然还有其他参数,这里不一一介绍了。
以上内容包含自己的部分理解,现阶段的学习深度不够可能还没有理解到位,暂时先把所学进行整理,欢迎指正。
参考:
A Comprehensive Guide to Understand and Implement Text Classification in Pythonwww.analyticsvidhya.comAn Intuitive Understanding of Word Embeddings: From Count Vectors to Word2Vecwww.analyticsvidhya.comTF-IDF与余弦相似性的应用(一):自动提取关键词 - 阮一峰的网络日志www.ruanyifeng.com
数据结构和算法--Huffman树和Huffman编码 - null的专栏 - CSDN博客blog.csdn.net
yuyuqi:word2vec(cbow+skip-gram+hierarchical softmax+Negative sampling)模型深度解析zhuanlan.zhihu.com
FastText:快速的文本分类器 - 不忘初心~ - CSDN博客blog.csdn.net
————————————————————————————————
喜欢我的文章,或者希望了解更多机器学习、人工智能等相关知识、动态的小伙伴可以关注公众号,并进交流群。这里有一群志同道合的小伙伴可以一起交流学习、转行、打比赛等诸多经验。
统计一行文本的单词个数_NLP中的文本表示方法相关推荐
- 7-4 统计一行文本的单词个数 (15 分)
7-4 统计一行文本的单词个数 (15 分) 本题目要求编写程序统计一行字符中单词的个数.所谓"单词"是指连续不含空格的字符串,各单词之间用空格分隔,空格数可以是多个. 输入格式: ...
- pta——大笨钟的心情,稳赢,统计一行文本的单词个数(c语言)
程序设计实训8月15日小组编程 7-4 稳赢 大家应该都会玩"锤子剪刀布"的游戏:两人同时给出手势,胜负规则如图所示: 现要求你编写一个稳赢不输的程序,根据对方的出招,给出对应的赢 ...
- 统计一行文本的单词个数(引用@浅哥 大佬)
一. 1.这道题很有意思,需要让我们统计单词个数,一共有三种理解方式,先来理解上面这种 (1)首先,我们分析题目可以近似理解成统计空格的数量,那么我们怎么统计呢 ?如果理解成统计前面的空格数,那么会出 ...
- PTA c语言 统计一行文本的单词个数
本题目要求编写程序统计一行字符中单词的个数.所谓"单词"是指连续不含空格的字符串,各单词之间用空格分隔,空格数可以是多个. 输入格式: 输入给出一行字符. 输出格式: 在一行中输出 ...
- 用java统计英文文本的单词个数_统计文本英文单词总个数,并列出每个单词的个数...
package test; /* * Task :统计文本英文单词总个数,并列出每个单词的个数 * * Date:2014.02.26 * *Author:璀若星辰 * */ import java. ...
- delphi 停电文本数据丢失_NLP中的文本分析和特征工程
语言检测,文本清理,长度测量,情绪分析,命名实体识别,n字频率,词向量,主题建模 前言 在本文中,我将使用NLP和Python解释如何分析文本数据并为机器学习模型提取特征. NLP(自然语言处理)是人 ...
- 表单如何添加大的文本框_在 Flutter 中进行文本框的创建和设定
文本框作为一个接收用户输入的组件,被广泛应用于表单构建.即时通讯.搜索等场景中. Flutter 提供了两个开箱即用的文本框组件:TextField 和 TextFormField. 1. 文本框 T ...
- python 文本框_重置Python中的文本框
几个星期前,我在制作重置按钮时要求一些帮助,我是python的新手,还有一个Noob,主要是我在c& c#也是SQL反正我正在为游戏制作一个重置按钮,我无法让它工作.这是代码.问题似乎是它在发 ...
- html文本阴影水平垂直,CSS中使用文本阴影与元素阴影效果
文本阴影介绍 在CSS中使用text-shadow属性设置文本阴影,该属性一共有4个属性值如:水平阴影.垂直阴影.(清晰度或模糊距离).阴影颜色. text-shadow属性值说明,在文本阴影实践中: ...
最新文章
- docker-compose的安装与简单使用
- 数据分析 同比是消除季节影响与去年同段时间比,环比是连续两个时间段比
- Tomcat9 无法启动组件[Connector[AJP/1.3-8009]]
- centos7 安装python3
- 《Linux命令行与shell脚本编程大全 第3版》Linux命令行---4
- 弹出键盘,UIView 上移
- Photoshop CS6将多张图片合成GIF动态图或视频,并将其保存导出
- SAP 设置或取消仓库不参与MRP运算(转)
- float最大_Hard 级:二叉树中的最大路径和
- Common plugins
- WebService 常用免费调用接口 与 JWS(Java Web Service) 调用第三方 webService 天气服务
- 电脑快速截屏(缺少PrtScr键)
- 各省份的车牌简称 备案地区的简称
- matlab 图例自定义,matlab实现自定义曲线图以及图例
- operator开发流程
- 职业操盘手的止损法则
- mysql 通过load data local infile导入txt文件数据
- 步进电机工作原理与编程
- 【Shader】实验06——后处理实现色散效果
- 第三章 页表管理(Page Table Management)
热门文章
- python断言assert实例_Python 拓展之断言(assert)
- java远程执行jmi,java调用matlab 时出现java.lang.NullPointerException错误
- gamma校正_Log与Gamma校正视频
- linux c 文件映射,linuxc-共享内存
- java中singleton_Singleton是什么,在Java中如何实现
- GitHub 添加开源协议
- 基于JAVA+SpringMVC+Mybatis+MYSQL的停车场管理系统
- 基于JAVA+SpringBoot+Mybatis+MYSQL的社区物业管理系统
- jeecgboot 前端环境搭建_如何从零开始搭建前端监控平台?
- Mysql字段修饰符(约束)