先回顾下数据挖掘和计算机视觉任务。数据挖掘中给定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。还有很重要的一点,这种表示方法无法表达单词与单词之间的相似程度,如beautifulpretty可以表达相似的意思但是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,即将词向量的长度进行缩减。

下面是奇异值分解的步骤。

分布式表示

离散表示虽然能够进行词语或者文本的向量表示,进而用模型进行情感分析或是文本分类之类的任务,但其不能表示词语间的相似程度或者词语间的类比关系。比如前面提到的beautifulpretty,它们表达相近的意思,所以我们希望它们在整个文本的表示空间内挨得很近。一般认为词向量/文本向量之间的夹角越小,两个词相似度越高。

离散表示如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模型的原理示意:

截自word2vec论文

连续词袋模型在NNLM基础上有以下几点创新:

  1. 取消了隐藏层,减少了计算量
  2. 采用上下文划窗而不只是前文划窗,即用上下文的词来预测当前词
  3. 投影层不再使用各向量拼接的方式,而是简单的求和平均

其目标函数为:

可以看到,上面提到的取消隐藏层,投影层求和平均都可以一定程度上减少计算量,但输出层的数量在那里,比如语料库有500W个词那么隐藏层就要对500W个神经元进行全连接计算,这依然需要庞大的计算量。word2vec算法又在这里进行了训练优化。

https://www.analyticsvidhya.com/blog/2017/06/word-embeddings-count-word2veec/

层级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之和最小。

https://www.analyticsvidhya.com/blog/2017/06/word-embeddings-count-word2veec/

fasttext

fasttext的模型与CBOW类似,实际上,fasttext的确是由CBOW演变而来的。CBOW预测上下文的中间词,fasttext预测文本标签。与word2vec算法的衍生物相同,稠密词向量也是在训练神经网络的过程中得到的。

截自fasttext论文

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 Python​www.analyticsvidhya.comAn Intuitive Understanding of Word Embeddings: From Count Vectors to Word2Vec​www.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中的文本表示方法相关推荐

  1. 7-4 统计一行文本的单词个数 (15 分)

    7-4 统计一行文本的单词个数 (15 分) 本题目要求编写程序统计一行字符中单词的个数.所谓"单词"是指连续不含空格的字符串,各单词之间用空格分隔,空格数可以是多个. 输入格式: ...

  2. pta——大笨钟的心情,稳赢,统计一行文本的单词个数(c语言)

    程序设计实训8月15日小组编程 7-4 稳赢 大家应该都会玩"锤子剪刀布"的游戏:两人同时给出手势,胜负规则如图所示: 现要求你编写一个稳赢不输的程序,根据对方的出招,给出对应的赢 ...

  3. 统计一行文本的单词个数(引用@浅哥 大佬)

    一. 1.这道题很有意思,需要让我们统计单词个数,一共有三种理解方式,先来理解上面这种 (1)首先,我们分析题目可以近似理解成统计空格的数量,那么我们怎么统计呢 ?如果理解成统计前面的空格数,那么会出 ...

  4. PTA c语言 统计一行文本的单词个数

    本题目要求编写程序统计一行字符中单词的个数.所谓"单词"是指连续不含空格的字符串,各单词之间用空格分隔,空格数可以是多个. 输入格式: 输入给出一行字符. 输出格式: 在一行中输出 ...

  5. 用java统计英文文本的单词个数_统计文本英文单词总个数,并列出每个单词的个数...

    package test; /* * Task :统计文本英文单词总个数,并列出每个单词的个数 * * Date:2014.02.26 * *Author:璀若星辰 * */ import java. ...

  6. delphi 停电文本数据丢失_NLP中的文本分析和特征工程

    语言检测,文本清理,长度测量,情绪分析,命名实体识别,n字频率,词向量,主题建模 前言 在本文中,我将使用NLP和Python解释如何分析文本数据并为机器学习模型提取特征. NLP(自然语言处理)是人 ...

  7. 表单如何添加大的文本框_在 Flutter 中进行文本框的创建和设定

    文本框作为一个接收用户输入的组件,被广泛应用于表单构建.即时通讯.搜索等场景中. Flutter 提供了两个开箱即用的文本框组件:TextField 和 TextFormField. 1. 文本框 T ...

  8. python 文本框_重置Python中的文本框

    几个星期前,我在制作重置按钮时要求一些帮助,我是python的新手,还有一个Noob,主要是我在c& c#也是SQL反正我正在为游戏制作一个重置按钮,我无法让它工作.这是代码.问题似乎是它在发 ...

  9. html文本阴影水平垂直,CSS中使用文本阴影与元素阴影效果

    文本阴影介绍 在CSS中使用text-shadow属性设置文本阴影,该属性一共有4个属性值如:水平阴影.垂直阴影.(清晰度或模糊距离).阴影颜色. text-shadow属性值说明,在文本阴影实践中: ...

最新文章

  1. docker-compose的安装与简单使用
  2. 数据分析 同比是消除季节影响与去年同段时间比,环比是连续两个时间段比
  3. Tomcat9 无法启动组件[Connector[AJP/1.3-8009]]
  4. centos7 安装python3
  5. 《Linux命令行与shell脚本编程大全 第3版》Linux命令行---4
  6. 弹出键盘,UIView 上移
  7. Photoshop CS6将多张图片合成GIF动态图或视频,并将其保存导出
  8. SAP 设置或取消仓库不参与MRP运算(转)
  9. float最大_Hard 级:二叉树中的最大路径和
  10. Common plugins
  11. WebService 常用免费调用接口 与 JWS(Java Web Service) 调用第三方 webService 天气服务
  12. 电脑快速截屏(缺少PrtScr键)
  13. 各省份的车牌简称 备案地区的简称
  14. matlab 图例自定义,matlab实现自定义曲线图以及图例
  15. operator开发流程
  16. 职业操盘手的止损法则
  17. mysql 通过load data local infile导入txt文件数据
  18. 步进电机工作原理与编程
  19. 【Shader】实验06——后处理实现色散效果
  20. 第三章 页表管理(Page Table Management)

热门文章

  1. python断言assert实例_Python 拓展之断言(assert)
  2. java远程执行jmi,java调用matlab 时出现java.lang.NullPointerException错误
  3. gamma校正_Log与Gamma校正视频
  4. linux c 文件映射,linuxc-共享内存
  5. java中singleton_Singleton是什么,在Java中如何实现
  6. GitHub 添加开源协议
  7. 基于JAVA+SpringMVC+Mybatis+MYSQL的停车场管理系统
  8. 基于JAVA+SpringBoot+Mybatis+MYSQL的社区物业管理系统
  9. jeecgboot 前端环境搭建_如何从零开始搭建前端监控平台?
  10. Mysql字段修饰符(约束)