自然语言处理入门

自然语言处理NLP( natural language process)是这几年越来越火了,kaggle上的比赛有关NLP的也日渐多起来了.

NLP的应用场景很多,情感分析,邮件过滤,ai客服,机器翻译等等等等,就像这几年越来越火有成为BAT之后第四极的今日头条,为什么能够为每个人推送不同的感兴趣的内容,这里少不了机器学习的功能,当然也包括NLP.

想入门NLP,上网一搜,搜到的多是些具体算法的讲解,或者某些框架的使用,要么就是上来就一顿推荐看某某书某某论文或者讲义.从个人经验的角度来讲,这种方法其实不适合大多数人,因为在初期,学的东西枯燥无味又过于细节,又没有即时的反馈,学习热情很容易就消减了.

初期的时候对要学习的东西的整体概况,框架全貌,基本流程,有个基本了解,然后快速上手,再慢慢地去填充细节.这里强推数学之美,google一下蛮容易下载到的.即便你对机器学习都一无所知,这本书的大部分内容应该也能看懂.这本书会让你对机器学习,自然语言处理的一些基础原理有个大概的了解.

说回NLP,早期的时候发展的其实并不好.最早的时候分为两个派别,一派是语法语义分析派,一派是统计学派.

举个简单的例子,以分析"我爱北京天安门"为例

前者的思路是分析出"这是一个主谓宾结构,主语是‘我’,谓语是‘爱’,宾语是‘北京天安门’",我知道‘爱’是什么意思,知道‘北京天安门’是个地名.那么这句表达的意思也就知道了.

后者的思路是从大量的文本中找出相似的句子,比如我事先人工搜集了1000个文本,我们人工分析出“我爱xxx,我喜欢xxx,去北京天安门”等等类似的文本,人工标注这些文本,知道这种句子表达的是一种正面的情绪,表达喜欢某个人/地点/事物等. 那么我通过比较,就知道了“我爱北京天安门”表达的意思大概率也是我喜欢某个地方,这个地方叫天安门.

早期的时候语法分析派发展的比较好,但是很快就遇到了瓶颈,因为语法太TM复杂了,词的二义性也很多,根本分析不明白.统计学派发展的不好,很好理解,以这种思路来做NLP,势必要对语料库(也就是上面例子里的那1000个文本)的数量有要求,数量越多越好,早期的时候是没有这种条件的.随着计算机的发展,数据量的增长,统计学派越来越体现出其优势,这就是我们今天的NLP处理的思路:根据大量的已有的文本(语料库),基于统计学,基于概率,去推测待预测文本的最大可能的含义.

如果上面这个"我爱天安门"的例子让你困惑,不要怀疑自己,一定是我的例子举得还不够好,再一次建议去看看数学之美.可以看看第二章:从规则到统计.


 

书归正传:

NLP笼统地说:可以分为4个部分

  • 文本清洗       
  • 分词
  • word2vec
  • 上算法对文本做分析

拿到一个文本,首先要做清洗,比如你用爬虫爬一个电影评论,你爬下来的内容是html格式的,其中你真正要的可能就是评论的部分,那你可能会用到beatifulsoup这个库,用python写过爬虫的应该很熟悉了.

好,现在我们拿到干净的文本了,我们要把词分割出来,比如"我爱北京天安门",要分割出我,爱,北京,天安门这几个词.英文的分词好分一点,因为词和词之间有空格.这一步我们通常也是用现成的工具,英文就nltk,中文就结巴分词.都挺有名的.

好,现在我们已经拿到一堆一堆的词了,我们要把这些词转换成相应的向量,用向量表示出来.我们用一个例子来说明这一步做的是什么.

>>> from sklearn.feature_extraction.text import CountVectorizer
>>> corpus = [
...     'This is the first document.',
...     'This document is the second document.',
...     'And this is the third one.',
...     'Is this the first document?',
... ]
>>> vectorizer = CountVectorizer()
>>> X = vectorizer.fit_transform(corpus)
>>> print(vectorizer.get_feature_names())
['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this']
>>> print(X.toarray())  
[[0 1 1 1 0 0 1 0 1]
 [0 2 0 1 0 1 1 0 1]
 [1 0 0 1 1 0 1 1 1]
 [0 1 1 1 0 0 1 0 1]]

可以看到我们先统计出文本中有几种词,比如上面例子.corpus中一共涉及到  ['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this']这9种词,那么我们就把每一句话都转化为一个9个特征的样本,其中特征的值就是该特征出现的次数.比如第二句中document出现了两次,is一次,second一次.....,那么第二句的向量化表示就是[0 2 0 1 0 1 1 0 1]。这就是所谓的词频TF:Term Frequency.

但是,问题来了!

考虑这样一个句子:"我想你,我喜欢你,我爱你,我要向你求婚!",分完词以后,得到我/你/爱/喜欢/想/求婚.  ‘我’,‘你’出现了很多次,但你能说这句话的重点在‘我’‘你’吗?这句的重点明显在‘爱’‘求婚’.  

知识点来了:TF-IDF是Term Frequency -  Inverse Document Frequency的缩写,即“词频-逆文本频率”

概括来讲, IDF用来反映词的重要性.IDF反应了一个词在所有文本中出现的频率,如果一个词在很多的文本中出现,那么它的IDF值应该低。比如上面例子里,‘我’‘你’重复了太多遍,你可以理解为表白的人废话有点多.所以‘我’,‘你’的IDF就低,‘求婚’的IDF更高.

下面给出IDF和TF-IDF的计算公式: 

$$IDF(x) = log\frac{N+1}{N(x)+1} + 1$$

$$TF-IDF(x) = TF(x) * IDF(x)$$

其中,N代表语料库中文本的总数,而N(x)代表语料库中包含词xx的文本总数。TF(x)指词xx在当前文本中的词频.

 

 stackoverflow上关于sklean中具体计算tf-idf的过程的回答详情请戳这里.   sklearn的官方文档戳这里  以上两个link有兴趣可以看看.

好,到了这一步,文本数据就已经被我们转换为M*N的矩阵了.代表M个文本. 下面就该上什么算法就上什么算法吧.


 

说了这么多,来实战看看吧.完整代码戳这里.

关于kaggle上这个比赛的描述及数据下载具体见这里. 这边我简单介绍一下,labeledTrainData.tsv里记录了各种电影评论,已经标明了是正面的评价还是负面的,testData.tsv里记录了各种评论,我们需要根据这些评论去判断这是一个正面的还是负面的评价.

1.文本清洗,分词

import re
from bs4 import BeautifulSoup 
def review_to_wordlist(review):
    '''
    Meant for converting each of the IMDB reviews into a list of words.
    '''
    # First remove the HTML.
    review_text = BeautifulSoup(review).get_text()
    
    # Use regular expressions to only include words.
    review_text = re.sub("[^a-zA-Z]"," ", review_text)
    
    # Convert words to lower case and split them into separate words.
    words = review_text.lower().split()
   
    # Return a list of words
    return(words)

traindata = []
for i in range(0,len(train['review'])):
    traindata.append(" ".join(review_to_wordlist(train['review'][i])))
testdata = []
for i in range(0,len(test['review'])):
    testdata.append(" ".join(review_to_wordlist(test['review'][i])))

2.词的向量化word2vec

这里,我们没有使用大名鼎鼎的google的word2vec库,我们就用sklearn中的TfidfVectorizer

from sklearn.feature_extraction.text import TfidfVectorizer
tfv = TfidfVectorizer(stop_words = 'english')

X_all = traindata + testdata 

tfv.fit(X_all)
X_all = tfv.transform(X_all)

这里涉及到一个stopwords的概念,即有些词我们认为对我们理解语义是无关紧要的,比如英文里的the,to 中文里的的地得...这种词我们就叫做stopwords,在做向量化的时候我们不管这些词.

3.采用逻辑回归 做模型训练

from sklearn.linear_model import LogisticRegression
log_reg = LogisticRegression()
log_reg.fit(X_train,y_train)

  predict_result = log_reg.predict(X_test)
  result_df = pd.DataFrame(data={"id":test["id"], "sentiment":predict_result})
  result_df.to_csv("log_reg.csv",index=False)

最终我们取得了0.88的准确率.

 


 

总结一下:

  1. 你需要一个学习环境.  建议直接安装anaconda。已经帮你装好了大部分你可能用到的机器学习包.
  2. python   python语法需要有基本了解.不会的话就搜一搜吧,网上教程大把.对于有编程基础的朋友,入门很容易.
  3. pandas/numpy用法要有个基本了解.可以跟着https://www.kaggle.com/learn/overview学习.
  4. sklearn  在刚开始的时候可以先不用太注重各种算法背后的原理.先学着用起来.等能入门了以后,再不断深化自己对各种算法的理解,这样才能更好地选择合适的算法,合适的参数.
  5. 去kaggle找些比赛动起手来,实战起来.

以上就是机器学习快速入门的学习路径,结合本文说的内容,也就算是nlp的快速入门的内容了,希望能帮到大家.

 

posted @ 2018-12-24 16:46  core!  阅读(2123)  评论(1编辑  收藏  举报