自然语言处理入门
自然语言处理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的准确率.
总结一下:
- 你需要一个学习环境. 建议直接安装anaconda。已经帮你装好了大部分你可能用到的机器学习包.
- python python语法需要有基本了解.不会的话就搜一搜吧,网上教程大把.对于有编程基础的朋友,入门很容易.
- pandas/numpy用法要有个基本了解.可以跟着https://www.kaggle.com/learn/overview学习.
- sklearn 在刚开始的时候可以先不用太注重各种算法背后的原理.先学着用起来.等能入门了以后,再不断深化自己对各种算法的理解,这样才能更好地选择合适的算法,合适的参数.
- 去kaggle找些比赛动起手来,实战起来.
以上就是机器学习快速入门的学习路径,结合本文说的内容,也就算是nlp的快速入门的内容了,希望能帮到大家.