NLP 中的文本分类
文本分类是机器学习在自然语言处理中的最常用也是最基础的应用,机器学习相关内容可以直接看我的有关scikit-learn相关教程,本节直接涉及nltk中的机器学习相关内容
转载自网站www.shareditor.com以及原始链接地址
先来一段前戏
机器学习的过程是训练模型和使用模型的过程,训练就是基于已知数据做统计学习,使用就是用统计学习好的模型来计算未知的数据。
机器学习分为有监督学习和无监督学习,文本分类也分为有监督的分类和无监督的分类。有监督就是训练的样本数据有了确定的判断,基于这些已有的判断来断定新的数据,无监督就是训练的样本数据没有什么判断,完全自发的生成结论。
无论监督学习还是无监督学习,都是通过某种算法来实现,而这种算法可以有多重选择,贝叶斯就是其中一种。在多种算法中如何选择最适合的,这才是机器学习最难的事情,也是最高境界。
nltk中的贝叶斯分类器
贝叶斯是概率论的鼻祖,贝叶斯定理是关于随机事件的条件概率的一则定理,贝叶斯公式是:
P(B|A)=P(A|B)P(B)/P(A);即,已知P(A|B),P(A)和P(B)可以计算出P(B|A)。
贝叶斯分类器就是基于贝叶斯概率理论设计的分类器算法,nltk库中已经实现,具体用法如下:
# coding:utf-8import sys
reload(sys)
sys.setdefaultencoding( "utf-8" )
import nltkmy_train_set = [({'feature1':u'a'},'1'),({'feature1':u'a'},'2'),({'feature1':u'a'},'3'),({'feature1':u'a'},'3'),({'feature1':u'b'},'2'),({'feature1':u'b'},'2'),({'feature1':u'b'},'2'),({'feature1':u'b'},'2'),({'feature1':u'b'},'2'),({'feature1':u'b'},'2'),]
classifier = nltk.NaiveBayesClassifier.train(my_train_set)
print classifier.classify({'feature1':u'a'})
print classifier.classify({'feature1':u'b'})
执行后判断特征a和特征b的分类分别是3和2
因为训练集中特征是a的分类是3的最多,所以会归类为3
当然实际中训练样本的数量要多的多,特征要多的多
请尊重原创,转载请注明来源网站www.shareditor.com以及原始链接地址
文档分类
不管是什么分类,最重要的是要知道哪些特征是最能反映这个分类的特点,也就是特征选取。文档分类使用的特征就是最能代表这个分类的词。
因为对文档分类要经过训练和预测两个过程,而特征的提取是这两个过程都需要的,所以,习惯上我们会把特征提取单独抽象出来作为一个公共方法,比如:
from nltk.corpus import movie_reviews
all_words = nltk.FreqDist(w.lower() for w in movie_reviews.words())
word_features = all_words.keys()[:2000]
def document_features(document): for word in word_features: features['contains(%s)' % word] = (word in document_words) return features
这是一个简单的特征提取过程,前两行找到movie_reviews语料库中出现词频最高的2000个词作为特征,下面定义的函数就是特征提取函数,每个特征都是形如contains(***)的key,value就是True或False,表示这个词是否在文档中出现
那么我们训练的过程就是:
featuresets = [(document_features(d), c) for (d,c) in documents]
classifier = nltk.NaiveBayesClassifier.train(featuresets)
要预测一个新的文档时:
classifier.classify(document_features(d))
通过
classifier.show_most_informative_features(5)
可以找到最优信息量的特征,这对我们选取特征是非常有帮助的
其他文本分类
文本分类除了文档分类外还有许多其他类型的分类,比如:
词性标注:属于一种文本分类,一般是基于上下文语境的文本分类
句子分割:属于标点符号的分类任务,它的特征一般选取为单独句子标识符的合并链表、数据特征(下一个词是否大写、前一个词是什么、前一个词长度……)
识别对话行为类型:对话行为类型是指问候、问题、回答、断言、说明等
识别文字蕴含:即一个句子是否能得出另外一个句子的结论,这可以认为是真假标签的分类任务。这是一个有挑战的事情
从一句话里提取出十句话的信息,扩充训练样本
按照之前理解的内容,对一句话做处理,最多是切成一个一个的词,再标注上词性,仅此而已,然而事实并非如此,一句话还可以做更多的文章,如下:
什么?还能结构化?
任何语言的每一句话之所以称为“话”,是因为它有一定的句子结构,除了一个个独立的词之外,他们之间还存在着某种关系。如果任何一句话可以由任何词构成,可长可短,那么这是一个非结构化的信息,计算机是很难理解并做计算的,但是如果能够以某种方式把句子转化成结构化的形式,计算机就可以理解了。而如果建立结构化的知识之间的关系图,则所谓的知识图谱 。
实事上,人脑在理解一句话的时候也暗暗地在做着由非结构化到结构化的工作。
比如说:“我下午要和小明在公司讨论一个技术问题”。这是一片非结构化的词语拼成的一句话,但是这里面有很多隐含信息:
1)小明是一个实体
2)参与者有两个:我和小明
3)地点设定是:公司
4)要做的事情是:讨论
5)讨论的内容是:问题
6)这个问题是一个技术问题
7)公司是一个地点
8)讨论是一种行为
9)我和小明有某种关系
10)下午是一个时间
上面这些信息有一些是专门针对这个句子的,有一些是常理性的,对于针对句子的信息有利于理解这句话,对于常理性的信息可以积累下来用来以后理解其他句子。
那么怎么才能把非结构化的句子转成结构化的信息呢?要做的工作除了断句、分词、词性标注之外,还要做的一个关键事情就是分块。
分块
分块就是根据句子中的词和词性,按照某种规则组合在一起形成一个个分块,每个分块代表一个实体。常见的实体包括:组织、人员、地点、日期、时间等
以上面的例子为例,首先我们做名词短语分块(NP-chunking),比如:技术问题。名词短语分块通过词性标记和一些规则就可以识别出来,也可以通过机器学习的方法识别
除了名词短语分块还有很多其他分块:介词短语(PP,比如:以我……)、动词短语(VP,比如:打人)、句子(S,我是人)
分块如何标记和存储呢?
可以采用IOB标记,I(inside,内部)、O(outside,外部)、B(begin, 开始),一个块的开始标记为B,块内的标识符序列标注为I,所有其他标识符标注为O
也可以用树结构来存储分块,用树结构可以解决IOB无法标注的另一类分块,那就是多级分块。多级分块就是一句话可以有多重分块方法,比如:我以我的最高权利惩罚你。这里面“最高权利”、“我的最高权利”、“以我的最高权利”是不同类型分块形成一种多级分块,这是无法通过IOB标记的,但是用树结构可以。这也叫做级联分块。具体树结构举个例子:
(S(NP 小明) (VP(V 追赶) (NP(Det 一只) (N 兔子))))
这是不是让你想到了语法树?
关系抽取
通过上面的分块可以很容易识别出实体,那么关系抽取实际就是找出实体和实体之间的关系,这是自然语言处理一个质的跨越,实体识别让机器认知了一种事物,关系识别让机器掌握了一个真相。
关系抽取的第一个方法就是找到(X, a, Y)这种三元组,其中X和Y都是实体,a是表达关系的字符串,这完全可以通过正则来识别,因为不同语言有这不同的语法规则,所以方法都是不同的,比如中文里的“爱”可以作为这里的a,但是“和”、“因为”等就不能作为这里的a
编程实现
下面介绍部分有关分块的代码,因为中文标注好分块的语料没有找到,所以只能沿用英文语料来说明,但是原理是一样的
conll2000语料中已经有标注好的分块信息,如下:
>>> from nltk.corpus import conll2000
>>> print conll2000.chunked_sents('train.txt')[99]
(S(PP Over/IN)(NP a/DT cup/NN)(PP of/IN)(NP coffee/NN),/,(NP Mr./NNP Stone/NNP)(VP told/VBD)(NP his/PRP$ story/NN)./.)
我们可以基于这些标注数据做训练,由于这种存储结构比较特殊,所以就不单独基于这种结构实现parser了,只说下跟前面讲的机器学习一样,只要基于这部分数据做训练,然后再用来标注新的语料就行了
这里介绍一下 sklearn 库中的的一个文本分类 demo
以下为笔者自己编辑:
# -*- coding:utf-8 -*-import numpy as np
from sklearn.naive_bayes import MultinomialNB, BernoulliNB
from sklearn.datasets import fetch_20newsgroups
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import RidgeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
from sklearn import metrics
from time import time
from pprint import pprint
import matplotlib.pyplot as plt
import matplotlib as mpldef test_clf(clf):print u'分类器:', clfalpha_can = np.logspace(-3, 2, 10)model = GridSearchCV(clf, param_grid={'alpha': alpha_can}, cv=5)m = alpha_can.sizeif hasattr(clf, 'alpha'):model.set_params(param_grid={'alpha': alpha_can})m = alpha_can.sizeif hasattr(clf, 'n_neighbors'):neighbors_can = np.arange(1, 15)model.set_params(param_grid={'n_neighbors': neighbors_can})m = neighbors_can.sizeif hasattr(clf, 'C'):C_can = np.logspace(1, 3, 3)gamma_can = np.logspace(-3, 0, 3)model.set_params(param_grid={'C':C_can, 'gamma':gamma_can})m = C_can.size * gamma_can.sizeif hasattr(clf, 'max_depth'):max_depth_can = np.arange(4, 10)model.set_params(param_grid={'max_depth': max_depth_can})m = max_depth_can.sizet_start = time()model.fit(x_train, y_train)t_end = time()t_train = (t_end - t_start) / (5*m)print u'5折交叉验证的训练时间为:%.3f秒/(5*%d)=%.3f秒' % ((t_end - t_start), m, t_train)print u'最优超参数为:', model.best_params_t_start = time()y_hat = model.predict(x_test)t_end = time()t_test = t_end - t_startprint u'测试时间:%.3f秒' % t_testacc = metrics.accuracy_score(y_test, y_hat)print u'测试集准确率:%.2f%%' % (100 * acc)name = str(clf).split('(')[0]index = name.find('Classifier')if index != -1:name = name[:index] # 去掉末尾的Classifierif name == 'SVC':name = 'SVM'return t_train, t_test, 1-acc, nameif __name__ == "__main__":print u'开始下载/加载数据...'t_start = time()# remove = ('headers', 'footers', 'quotes')remove = ()categories = 'alt.atheism', 'talk.religion.misc', 'comp.graphics', 'sci.space'# categories = None # 若分类所有类别,请注意内存是否够用data_train = fetch_20newsgroups(subset='train', categories=categories, shuffle=True, random_state=0, remove=remove)data_test = fetch_20newsgroups(subset='test', categories=categories, shuffle=True, random_state=0, remove=remove)t_end = time()print u'下载/加载数据完成,耗时%.3f秒' % (t_end - t_start)print u'数据类型:', type(data_train)print u'训练集包含的文本数目:', len(data_train.data)print u'测试集包含的文本数目:', len(data_test.data)print u'训练集和测试集使用的%d个类别的名称:' % len(categories)categories = data_train.target_namespprint(categories)y_train = data_train.targety_test = data_test.targetprint u' -- 前10个文本 -- 'for i in np.arange(10):print u'文本%d(属于类别 - %s):' % (i+1, categories[y_train[i]])print data_train.data[i]print '\n\n'vectorizer = TfidfVectorizer(input='content', stop_words='english', max_df=0.5, sublinear_tf=True)x_train = vectorizer.fit_transform(data_train.data) # x_train是稀疏的,scipy.sparse.csr.csr_matrixx_test = vectorizer.transform(data_test.data)print u'训练集样本个数:%d,特征个数:%d' % x_train.shapeprint u'停止词:\n',pprint(vectorizer.get_stop_words())feature_names = np.asarray(vectorizer.get_feature_names())print u'\n\n===================\n分类器的比较:\n'clfs = (MultinomialNB(), # 0.87(0.017), 0.002, 90.39%BernoulliNB(), # 1.592(0.032), 0.010, 88.54%KNeighborsClassifier(), # 19.737(0.282), 0.208, 86.03%RidgeClassifier(), # 25.6(0.512), 0.003, 89.73%RandomForestClassifier(n_estimators=200), # 59.319(1.977), 0.248, 77.01%SVC() # 236.59(5.258), 1.574, 90.10%)result = []for clf in clfs:a = test_clf(clf)result.append(a)print '\n'result = np.array(result)time_train, time_test, err, names = result.Ttime_train = time_train.astype(np.float)time_test = time_test.astype(np.float)err = err.astype(np.float)x = np.arange(len(time_train))mpl.rcParams['font.sans-serif'] = [u'simHei']mpl.rcParams['axes.unicode_minus'] = Falseplt.figure(figsize=(10, 7), facecolor='w')ax = plt.axes()b1 = ax.bar(x, err, width=0.25, color='#77E0A0')ax_t = ax.twinx()b2 = ax_t.bar(x+0.25, time_train, width=0.25, color='#FFA0A0')b3 = ax_t.bar(x+0.5, time_test, width=0.25, color='#FF8080')plt.xticks(x+0.5, names)plt.legend([b1[0], b2[0], b3[0]], (u'错误率', u'训练时间', u'测试时间'), loc='upper left', shadow=True)plt.title(u'新闻组文本数据不同分类器间的比较', fontsize=18)plt.xlabel(u'分类器名称')plt.grid(True)plt.tight_layout(2)plt.show()
NLP 中的文本分类相关推荐
- 手把手教你在Python中实现文本分类(附代码、数据集)
作者: Shivam Bansal 翻译:申利彬 校对:丁楠雅 本文约2300字,建议阅读8分钟. 本文将详细介绍文本分类问题并用Python实现这个过程. 引言 文本分类是商业问题中常见的自然语言处 ...
- 在TensorFlow中实现文本分类的卷积神经网络
在TensorFlow中实现文本分类的卷积神经网络 Github提供了完整的代码: https://github.com/dennybritz/cnn-text-classification-tf 在 ...
- Python中实现文本分类(附代码、数据集)
本文将详细介绍文本分类问题并用Python实现这个过程. 引言 文本分类是商业问题中常见的自然语言处理任务,目标是自动将文本文件分到一个或多个已定义好的类别中.文本分类的一些例子如下: 分析社交媒体中 ...
- 零基础入门NLP - 天池新闻文本分类Task3笔记
零基础入门NLP - 天池新闻文本分类 以下以Datawhale与天池举办的新闻文本分类这个NLP赛题做的NLP入门Task2笔记 赛题链接:https://tianchi.aliyun.com/co ...
- python文本分类_手把手教你在Python中实现文本分类.pdf
手把手教你在Python 中实现文本分类(附代码.数 据集) 引言 文本分类是商业问题中常见的自然语言处理任务,目标是自动将文本文件分到一个 或多个已定义好的类别中.文本分类的一些例子如下: • 分析 ...
- 在TensorFlow中实现文本分类的CNN
在TensorFlow中实现文本分类的CNN 在TensorFlow中实现文本分类的CNN 数据和预处理 模型 实现 1 输入占位符 2 向量层 3 卷积层和池化层 4 Dropout 层 5 得分和 ...
- LDA 用于将文档中的文本分类为特定主题
数据集: LDA 用于将文档中的文本分类为特定主题. 它构建每个文档模型的主题和每个主题模型的单词,建模为 Dirichlet 分布. 每个文档被建模为主题的多项分布,每个主题被建模为单词的多项分布. ...
- 【NLP】中文文本分类数据增强方法:EDA 与代码实现
数据增强可以算作是做深度学习算法的一个小trick.该介绍主要出自论文:EDA: Easy Data Augmentation Techniques for Boosting Performance ...
- NLP中面向文本表示的模型梳理
引言 语言表示是将自然语言表示为计算机或者模型能够处理的数据特征,是解决例如情感分析.命名实体识别.机器翻译.文本生成等这些高级任务的基础.本文作为NLP基础知识的入门,梳理了相关文本表征的模型与方法 ...
最新文章
- python 显示图片然后延时,python – ROS图像用户滞后
- 清晰讲解SQL语句中的外连接,通用于Mysql和Oracle,全是干货哦
- vector中的圆括号和花括号
- C语言之文件读写探究(六):fscanf、fprintf(格式化读写文件)
- java基础应用_Java基础(应用篇)
- Thrift辅助类,用于简化Thrift编程
- 任正非:华为鸿蒙将比安卓快 60%;小米回应主题侵权;VS Code 1.36发布​ | 极客头条...
- 【AdaBoost算法】积分图代码实现
- python 异常处理高级形式例子_Python 异常处理的实例详解
- dev-cpp linux,QT4+Devcpp开发环境搭建(参照网上资料整理)
- 初次尝试使用VisualSFM记录
- Mac修改redis密码
- Legend of Mir(传奇)官方源码学习3、服务端程序初始化过程
- ActiveMQ--CVE-2015-5254
- fcpx快速添加字幕 | final cut pro导入fcpxml字幕文件与视频时间对不上?我用代码搞定了
- 2018年考研真题计算机专业,2018年计算机考研真题及参考答案.pdf
- java姓名隐藏中间一个_如何正确的隐藏java语言中的名字
- ocv特性_锂离子电池的三大特性分析
- activemq保证消息顺序原理
- SpringBoot 代码结构
热门文章
- js函数引用、函数调用与回调函数
- ACM用N个正方体来建造金字塔问可以建造多少层
- 将英文的week 转换为中文的 简单的方法
- linux centos7重启路由命令行,centos7 永久添加静态路由
- 后缀用什么打开_茅台酒瓶口的珠子有什么用,取出来能多倒一杯酒?打开方法教给你...
- python卸载_删除系统 Python 引发的惨案
- ajax 赋值 获取,ajax得到的数据赋值给js中的全局变量
- 小程序开发代码_快速学会微信小程序开发,无需懂代码!
- LAMP环境下配置虚拟主机和域名的跳转
- JMS学习九 ActiveMQ的消息持久化到Mysql数据库