pyhanlp 文本分类与情感分析

这一次我们需要利用HanLP进行文本分类与情感分析。同时这也是pyhanlp用户指南的倒数第二篇关于接口和Python实现的文章了,再之后就是导论,使用技巧汇总和几个实例落。真是可喜可贺啊。

文本分类

在HanLP中,文本分类与情感分析都是使用一个分类器,朴素贝叶斯分类器。或许这个分类器还算是比较一般,不过从最终结果来看效果还是很可以的。

因为底层采用词袋模式,所以当文本较大时可能会是内存开效果大,不过没关系,作者预先写了一个特征检测的方法。使用卡方检测,利用阈值来过滤特征,减少内存的开销。

原作者只给了文本分类的例子,这里我们对原来的例子稍加改造,使其更适用分类任务。

语料库

本文语料库特指文本分类语料库,对应IDataSet接口。而文本分类语料库包含两个概念:文档和类目。一个文档只属于一个类目,一个类目可能含有多个文档。比如搜狗文本分类语料库迷你版.zip,下载前请先阅读搜狗实验室数据使用许可协议。

数据格式

分类语料的根目录.目录必须满足如下结构:

根目录

├── 分类A

│  └── 1.txt

│  └── 2.txt

│  └── 3.txt

├── 分类B

│  └── 1.txt

│  └── ...

└── ...


文件不一定需要用数字命名,也不需要以txt作为后缀名,但一定需要是文本文件.

分词

目前,本系统中的分词器接口一共有两种实现: BigramTokenizer and HanLPTokenizer。

但文本分类是否一定需要分词?答案是否定的。 我们可以顺序选取文中相邻的两个字,作为一个“词”(术语叫bigram)。这两个字在数量很多的时候可以反映文章的主题(参考清华大学2016年的一篇论文《Zhipeng Guo, Yu Zhao, Yabin Zheng, Xiance Si, Zhiyuan Liu, Maosong Sun. THUCTC: An Efficient Chinese Text Classifier. 2016》)。这在代码中对应BigramTokenizer. 当然,也可以采用传统的分词器,如HanLPTokenizer。 另外,用户也可以通过实现ITokenizer来实现自己的分词器,并通过IDataSet#setTokenizer来使其生效

特征提取

特征提取指的是从所有词中,选取最有助于分类决策的词语。理想状态下所有词语都有助于分类决策,但现实情况是,如果将所有词语都纳入计算,则训练速度将非常慢,内存开销非常大且最终模型的体积非常大。

本系统采取的是卡方检测,通过卡方检测去掉卡方值低于一个阈值的特征,并且限定最终特征数不超过100万。

预测

classify方法直接返回最可能的类别的String形式,而predict方法返回所有类别的得分(是一个Map形式,键是类目,值是分数或概率),categorize方法返回所有类目的得分(是一个double数组,分类得分按照分类名称的字典序排列),label方法返回最可能类目的字典序。

线程安全性

类似于HanLP的设计,以效率至上,本系统内部实现没有使用任何线程锁,但任何预测接口都是线程安全的(被设计为不储存中间结果,将所有中间结果放入参数栈中)。

from pyhanlp import SafeJClass

import zipfile

import os

from pyhanlp.static import download, remove_file, HANLP_DATA_PATH

# 设置路径,否则会从配置文件中寻找

HANLP_DATA_PATH = "/home/fonttian/Data/CNLP"

"""

获取测试数据路径,位于$root/data/textClassification/sogou-mini,

根目录由配置文件指定,或者等于我们前面手动设置的HANLP_DATA_PATH。

"""

DATA_FILES_PATH = "textClassification/sogou-mini"

def test_data_path():

    data_path = os.path.join(HANLP_DATA_PATH, DATA_FILES_PATH)

    if not os.path.isdir(data_path):

        os.mkdir(data_path)

    return data_path

def ensure_data(data_name, data_url):

    root_path = test_data_path()

    dest_path = os.path.join(root_path, data_name)

    if os.path.exists(dest_path):

        return dest_path

    if data_url.endswith('.zip'):

        dest_path += '.zip'

    download(data_url, dest_path)

    if data_url.endswith('.zip'):

        with zipfile.ZipFile(dest_path, "r") as archive:

            archive.extractall(root_path)

        remove_file(dest_path)

        dest_path = dest_path[:-len('.zip')]

    return dest_path

NaiveBayesClassifier = SafeJClass('com.hankcs.hanlp.classification.classifiers.NaiveBayesClassifier')

IOUtil = SafeJClass('com.hankcs.hanlp.corpus.io.IOUtil')

sogou_corpus_path = ensure_data('搜狗文本分类语料库迷你版',

                                'http://hanlp.linrunsoft.com/release/corpus/sogou-text-classification-corpus-mini.zip')

def train_or_load_classifier(path):

    model_path = path + '.ser'

    if os.path.isfile(model_path):

        return NaiveBayesClassifier(IOUtil.readObjectFrom(model_path))

    classifier = NaiveBayesClassifier()

    classifier.train(sogou_corpus_path)

    model = classifier.getModel()

    IOUtil.saveObjectTo(model, model_path)

    return NaiveBayesClassifier(model)

def predict(classifier, text):

    print("《%16s》\t属于分类\t【%s】" % (text, classifier.classify(text)))

    # 如需获取离散型随机变量的分布,请使用predict接口

    # print("《%16s》\t属于分类\t【%s】" % (text, classifier.predict(text)))

if __name__ == '__main__':

    classifier = train_or_load_classifier(sogou_corpus_path)

    predict(classifier, "C罗压梅西内马尔蝉联金球奖 2017=C罗年")

    predict(classifier, "英国造航母耗时8年仍未服役 被中国速度远远甩在身后")

    predict(classifier, "研究生考录模式亟待进一步专业化")

    predict(classifier, "如果真想用食物解压,建议可以食用燕麦")

    predict(classifier, "通用及其部分竞争对手目前正在考虑解决库存问题")



    print("\n 我们这里再用训练好的模型连测试一下新的随便从网上找来的几个新闻标题 \n")

    predict(classifier, "今年考研压力进一步增大,或许考研正在变成第二次高考")

    predict(classifier, "张继科被刘国梁连珠炮喊醒:醒醒!奥运会开始了。")

    predict(classifier, "福特终于开窍了!新车1.5T怼出184马力,不足11万,思域自愧不如")


《C罗压梅西内马尔蝉联金球奖 2017=C罗年》 属于分类 【体育】

《英国造航母耗时8年仍未服役 被中国速度远远甩在身后》 属于分类 【军事】

《 研究生考录模式亟待进一步专业化》 属于分类 【教育】

《如果真想用食物解压,建议可以食用燕麦》 属于分类 【健康】

《通用及其部分竞争对手目前正在考虑解决库存问题》 属于分类 【汽车】

我们这里再用训练好的模型连测试一下新的随便从网上找来的几个新闻标题

《今年考研压力进一步增大,或许考研正在变成第二次高考》 属于分类 【教育】

《张继科被刘国梁连珠炮喊醒:醒醒!奥运会开始了。》 属于分类 【体育】

《福特终于开窍了!新车1.5T怼出184马力,不足11万,思域自愧不如》 属于分类 【汽车】


从我们最后自己增加的几个新闻标题来看,分类器的效果相当的好。这多亏了word2vec。

情感分析

我们对于情感分析的实现与之前的文本分类具有高度的相似性,同时刚刚也提到了,实际上他们就是用的一个分类器。而在python的实现中,他们则几乎一模一样。

也正是因为如此,所以只要我们拥有同样格式的语料,那么我们可以使用这个分类器做任何我们需要的文本分类

语料来源

可以利用文本分类在情感极性语料上训练的模型做浅层情感分析。目前公开的情感分析语料库有:中文情感挖掘语料-ChnSentiCorp,语料发布者为谭松波。

"""

获取测试数据路径,位于$root/data/textClassification/sogou-mini,

根目录由配置文件指定,或者等于我们前面手动设置的HANLP_DATA_PATH。

ChnSentiCorp评论酒店情感分析

"""

DATA_FILES_PATH = "sentimentAnalysis/ChnSentiCorp"

if __name__ == '__main__':


    ChnSentiCorp_path = ensure_data('酒店评论情感分析', \

        'http://hanlp.linrunsoft.com/release/corpus/ChnSentiCorp.zip')

    # 此处感谢网友给出的下载链接

    # 本文示例中,如果需要使用本地资料,请通过上面的DATA_FILES_PATH变量控制

    classifier = train_or_load_classifier(ChnSentiCorp_path)

    predict(classifier, '距离川沙公路较近,但是公交指示不对,如果是"蔡陆线"的话,会非常麻烦.建议用别的路线.房间较为简单.')

    predict(classifier, "商务大床房,房间很大,床有2M宽,整体感觉经济实惠不错!")

    predict(classifier, "标准间太差 房间还不如3星的 而且设施非常陈旧.建议酒店把老的标准间从新改善.")

    predict(classifier, "服务态度极其差,前台接待好象没有受过培训,连基本的礼貌都不懂,竟然同时接待几个客人")



    print("\n 我们这里再用训练好的模型连测试一下我自己编的‘新的’的文本 \n")

    predict(classifier, "服务态度很好,认真的接待了我们,态度可以的!")

    predict(classifier, "有点不太卫生,感觉不怎么样。")


《距离川沙公路较近,但是公交指示不对,如果是"蔡陆线"的话,会非常麻烦.建议用别的路线.房间较为简单.》 属于分类 【正面】

《商务大床房,房间很大,床有2M宽,整体感觉经济实惠不错!》 属于分类 【正面】

《标准间太差 房间还不如3星的 而且设施非常陈旧.建议酒店把老的标准间从新改善.》 属于分类 【负面】

《服务态度极其差,前台接待好象没有受过培训,连基本的礼貌都不懂,竟然同时接待几个客人》 属于分类 【负面】

我们这里再用训练好的模型连测试一下我自己编的‘新的’的文本

《服务态度很好,认真的接待了我们,态度可以的!》 属于分类 【正面】

《  有点不太卫生,感觉不怎么样。》 属于分类 【负面】




文章来源于Font Tian的博客

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容