nltk 自己训练模型例子

简介: NLTK是Python的一个自然语言处理的模块,其中实现了朴素贝叶斯分类算法。以下,就使用上一篇文中提到的数据,来应用这个模块实现朴素贝叶斯分类。NLTK的实现更加泛化,所以在应用到我们的数据上时需要做一点的转化。 首先来看一下NLTK官方文档中给出的一个简单明了的例子,在了解这个例子之后,再设法将同样的模型应用到自己的数据集上。官方给出的例子是英文名中,在知道名字中最后

NLTK是Python的一个自然语言处理的模块,其中实现了朴素贝叶斯分类算法。以下,就使用上一篇文中提到的数据,来应用这个模块实现朴素贝叶斯分类。NLTK的实现更加泛化,所以在应用到我们的数据上时需要做一点的转化。


首先来看一下NLTK官方文档中给出的一个简单明了的例子,在了解这个例子之后,再设法将同样的模型应用到自己的数据集上。官方给出的例子是英文名中,在知道名字中最后一个字母后,判断这个名字对应的人是男是女。

[python]  view plain  copy
  1. #coding=utf-8  
  2. import random, nltk  
  3. from nltk.corpus import names  
  4.   
  5. def gender_features(word):  
  6.     '''''提取每个单词的最后一个字母作为特征'''  
  7.     return {'last_letter': word[-1]}  
  8. # 先为原始数据打好标签  
  9. labeled_names = ([(name, 'male'for name in names.words('male.txt')] + [(name, 'female'for name in names.words('female.txt')])  
  10. # 随机打乱打好标签的数据集的顺序,  
  11. random.shuffle(labeled_names)  
  12. # 从原始数据中提取特征(名字的最后一个字母, 参见gender_features的实现)  
  13. featuresets = [(gender_features(name), gender) for (name, gender) in labeled_names]  
  14. # 将特征集划分成训练集和测试集  
  15. train_set, test_set = featuresets[500:], featuresets[:500]  
  16. # 使用训练集训练模型(核心就是求出各种后验概率)  
  17. classifier = nltk.NaiveBayesClassifier.train(train_set)  
  18. # 通过测试集来估计分类器的准确性  
  19. print(nltk.classify.accuracy(classifier, test_set))  
  20. # 如果一个人的名字的最后一个字母是‘a’,那么这个人是男还是女  
  21. print(classifier.classify({'last_letter''a'}))  
  22. # 找出最能够区分分类的特征值  
  23. classifier.show_most_informative_features(5)  


以上程序的输出如下:
[plain]  view plain  copy
  1. 0.754  
  2. female  
  3. Most Informative Features  
  4.              last_letter = u'a'           female : male   =     35.6 : 1.0  
  5.              last_letter = u'k'             male : female =     30.7 : 1.0  
  6.              last_letter = u'f'             male : female =     16.6 : 1.0  
  7.              last_letter = u'p'             male : female =     12.5 : 1.0  
  8.              last_letter = u'm'             male : female =     11.1 : 1.0  
从结果中,我们可以看到,通过训练集训练出的模型,在应用到测试集上时,其准确率为75%;如果一个人的名字以字母‘a’结束,那么此分类器将其划分为女性;最后输出了最能区分男女的5个属性值的数据,比如,对于字母‘a’来说,它作为女性名的最后一个字母的可能性是男性的35倍。

可以看到NLTK的朴素贝叶斯实现之中,它的输入的训练集的输入是类似于以下的形式:

[

({'attr1':val1, 'attr2': val2, 'attr3': val3 ... 'attrn': valn}, label1),

({'attr1':val1, 'attr2': val2, 'attr3': val3 ... 'attrn': valn}, label2),

......

]

其中,每个特征对应一个标签,在以上的官方的例子中,特征就只有一个,last_letter;而特征的可能值是26个字母。对应到自己的数据,对应一个用户就不止有一个特征了,而是用户安装的APP名称列表,同时又由于每个用户安装的APP可能不同,所以不同的用户所对应的特征的长度也是可能不同的;而每个属性(APP名称)对应的值只有两个:安装或者没安装。


以下的代码中的注释以及输出说明了整个转化过程(使用了上篇文章中第三步中生成的数据):

[python]  view plain  copy
  1. #!/usr/local/bin/python2.7  
  2. # encoding: utf-8  
  3. from collections import defaultdict  
  4. import nltk  
  5.   
  6. def gender_features(appnamelist):  
  7.     features = defaultdict(bool)  
  8.     for appname in appnamelist:  
  9.         features[appname] = True  
  10.     return features  
  11.   
  12. if __name__ == '__main__':  
  13.     raw_data = defaultdict(lambda: defaultdict(list))  
  14.     with open('data/genderapplist.log') as f:  
  15.         for line in f:  
  16.             cells = line.strip().split('\t')  
  17.             if len(cells) == 3:  
  18.                 imei, gender, appname = cells  
  19.                 gender = 'male' if gender == '男性应用' else 'female'  
  20.                 raw_data[gender][imei].append(appname)  
  21.       
  22.     labeled_applist = [(appnamelist, 'male'for appnamelist in raw_data['male'].values()] + [(appnamelist, 'female'for appnamelist in raw_data['female'].values()]  
  23.     featuresets = [(gender_features(appnamelist), gender) for appnamelist, gender in labeled_applist]  
  24.     train_set, test_set = featuresets[500:], featuresets[:500]  
  25.     classifier = nltk.NaiveBayesClassifier.train(train_set)  
  26.       
  27.     # 在训练生成的分类器classifier中,有两个属性存储着贝叶斯分类器所需要的先验和后验概率:  
  28.     # _label_probdist 保存了标签的分布  
  29.     # _feature_probdist 保存了每个APPNAME对应的后验分布  
  30.     # 通过下面的代码我们可以看到它们的值  
  31.     print '以下是 _label_probdist的相关信息'  
  32.     print '1. 类型'   
  33.     print type(classifier._label_probdist)  
  34.     print '2. 标签的整体分布状况'  
  35.     classifier._label_probdist.freqdist().tabulate()  
  36.     print '3. 由第二步推出的标签的概率分布'  
  37.     print classifier._label_probdist.prob('female'), classifier._label_probdist.prob('male')  
  38.       
  39.     print '*' * 32  
  40.       
  41.     # _feature_probdist的值  
  42.     print '以下是 _feature_probdist的相关信息'  
  43.     print '1. 类型'  
  44.     print type(classifier._feature_probdist)  
  45.     print '2. 从1的输出中可以看到其类型为dict,我们看它的一个key和value即可'  
  46.     print classifier._feature_probdist.items()[6302]  
  47.     print '3. 从2中可以看到,其代表了,在标签为female的情况下,安装了支付宝钱包这个应用的概率分布'  
  48.     classifier._feature_probdist.items()[6302][1].freqdist().tabulate()  
  49.     print '4. 3的输出,我们非常熟悉,也就是在所有4910个female用户中,有77个安装了支付宝钱包,没有安装的有4833个'  
  50.     print '有了这个分布,我们就可以计算出P(True|female, 支付宝钱包),其意义就是,在female用户中,支付宝钱包这个属性为True的可能性为'  
  51.     print classifier._feature_probdist.items()[6302][1].prob(True)  
  52.     print '5. 然后你会发现4中输出的P(True|female, 支付宝钱包)并不正好等于77./4910,这是因为使用ELEProbDist'  
  53.     print '也就是“期望相似性概率估计”,这种方法避免了P(True|female, 支付宝钱包)=0情况的出现,从而避免模型失效'  
  54.     print '6. 通过在训练集上的训练,我们得到了以上的概率分布,然后就可以使用训练好的模型来分类了,我们看一下安装了蘑菇街和支付宝钱包的用户是男还是女'  
  55.     print classifier.classify({'蘑菇街':True'支付宝钱包'True})  
  56.     print '7. 让我们看一下安传过了蘑菇街和支付宝钱包的用户男女的可能性'  
  57.     print 'Prob(female)', classifier.prob_classify({'蘑菇街':True'支付宝钱包'True}).prob('female')  
  58.     print 'Prob(male)', classifier.prob_classify({'蘑菇街':True'支付宝钱包'True}).prob('male')  
  59.     print '8. 如果我们的输入中,有一个全新的应用“这个应用不存在”,这里的处理是不处理它'  
  60.     print 'Prob(female)', classifier.prob_classify({'蘑菇街':True'支付宝钱包'True'这个应用不存在':True}).prob('female')  
  61.     print 'Prob(male)', classifier.prob_classify({'蘑菇街':True'支付宝钱包'True'这个应用不存在':True}).prob('male')  

以上程序的输出为:

[plain]  view plain  copy
  1. 以下是 _label_probdist的相关信息  
  2. 1. 类型  
  3. <class 'nltk.probability.ELEProbDist'>  
  4. 2. 标签的整体分布状况  
  5. female male   
  6. 4910 4420   
  7. 3. 由第二步推出的标签的概率分布  
  8. 0.526256564141 0.473743435859  
  9. ********************************  
  10. 以下是 _feature_probdist的相关信息  
  11. 1. 类型  
  12. <type 'dict'>  
  13. 2. 从1的输出中可以看到其类型为dict,我们看它的一个key和value即可  
  14. (('female', '\xe6\x94\xaf\xe4\xbb\x98\xe5\xae\x9d\xe9\x92\xb1\xe5\x8c\x85'), <ELEProbDist based on 4910 samples>)  
  15. 3. 从2中可以看到,其代表了,在标签为female的情况下,安装了支付宝钱包这个应用的概率分布  
  16. None True   
  17. 4833   77   
  18. 4. 3的输出,我们非常熟悉,也就是在所有4910个female用户中,有77个安装了支付宝钱包,没有安装的有4833个  
  19. 有了这个分布,我们就可以计算出P(True|female, 支付宝钱包),其意义就是,在female用户中,支付宝钱包这个属性为True的可能性为  
  20. 0.0157809000204  
  21. 5. 然后你会发现4中输出的P(True|female, 支付宝钱包)并不正好等于77./4910,这是因为使用ELEProbDist  
  22. 也就是“期望相似性概率估计”,这种方法避免了P(True|female, 支付宝钱包)=0情况的出现,从而避免模型失效  
  23. 6. 通过在训练集上的训练,我们得到了以上的概率分布,然后就可以使用训练好的模型来分类了,我们看一下安装了蘑菇街和支付宝钱包的用户是男还是女  
  24. female  
  25. 7. 让我们看一下安传过了蘑菇街和支付宝钱包的用户男女的可能性  
  26. Prob(female) 0.994878529146  
  27. Prob(male) 0.00512147085357  
  28. 8. 如果我们的输入中,有一个全新的应用“这个应用不存在”,这里的处理是不处理它  
  29. Prob(female) 0.994878529146  
  30. Prob(male) 0.00512147085357  

这样通过使用NLTK,相比自己实现来说有了更简洁的代码,并且更容易维护,希望对有需要的同学有帮助。
目录
相关文章
|
人工智能 Linux Python
代码自动补全工具——Kite安装教程(以Pycharm为例)及Failed to install PyCharm at path.Plugin configuration directory的解决方案
代码自动补全工具——Kite安装教程(以Pycharm为例)及Failed to install PyCharm at path.Plugin configuration directory的解决方案
代码自动补全工具——Kite安装教程(以Pycharm为例)及Failed to install PyCharm at path.Plugin configuration directory的解决方案
|
测试技术 开发者 Python
对于Python中的异常要如何处理,raise关键字你真的了解吗?一篇文章带你从头了解
`raise`关键字在Python中用于显式引发异常,允许开发者在检测到错误条件时中断程序流程,并通过异常处理机制(如try-except块)接管控制。`raise`后可跟异常类型、异常对象及错误信息,适用于验证输入、处理错误、自定义异常、重新引发异常及测试等场景。例如,`raise ValueError(&quot;Invalid input&quot;)`用于验证输入数据,若不符合预期则引发异常,确保数据准确并提供清晰错误信息。此外,通过自定义异常类,可以针对特定错误情况提供更具体的信息,增强代码的健壮性和可维护性。
【IntelliJ IDEA】idea 收起注释、打开注释、隐藏注释的快捷键
【IntelliJ IDEA】idea 收起注释、打开注释、隐藏注释的快捷键
1412 0
|
数据处理 索引 Python
Pandas中resample方法:轻松处理时间序列数据
Pandas中resample方法:轻松处理时间序列数据
504 1
|
数据挖掘 数据处理 Python
​掌握Pandas中的rolling窗口,轻松处理时间序列数据
​掌握Pandas中的rolling窗口,轻松处理时间序列数据
1088 2
|
Python
在Python中实现斐波那契数列(Fibonacci sequence)的4中方法
在Python中实现斐波那契数列(Fibonacci sequence)的4中方法
3496 0
|
开发者 Python
在Python中,异常处理通过`try`、`except`、`else`和`finally`关键字进行
【6月更文挑战第26天】在Python中,异常处理通过`try`、`except`、`else`和`finally`关键字进行。基本结构包括尝试执行可能抛出异常的代码,然后指定`except`来捕获特定或任何类型的异常。`else`块在`try`无异常时执行,`finally`块确保无论是否发生异常都会执行,例如用于清理。可以使用`raise`重新抛出异常,而自定义异常则允许创建特定的错误类。这种机制增强了代码的健壮性。
574 7
|
canal 关系型数据库 MySQL
"揭秘阿里数据同步黑科技Canal:从原理到实战,手把手教你玩转MySQL数据秒级同步,让你的数据处理能力瞬间飙升,成为技术界的新晋网红!"
【8月更文挑战第18天】Canal是一款由阿里巴巴开源的高性能数据同步系统,它通过解析MySQL的增量日志(Binlog),提供低延迟、可靠的数据订阅和消费功能。Canal模拟MySQL Slave与Master间的交互协议来接收并解析Binary Log,支持数据的增量同步。配置简单直观,包括Server和Instance两层配置。在实战中,Canal可用于数据库镜像、实时备份等多种场景,通过集成Canal Client可实现数据的消费和处理,如更新缓存或写入消息队列。
1897 0
|
安全 Linux 测试技术
惊世骇俗!国产 OpenEuler 向 CentOS 发起挑战:这场替代之战结局如何?
【8月更文挑战第13天】曾为服务器首选的 CentOS 因策略变动促使业界寻求新替代。国产 OpenEuler 操作系统应运而生,它是一款开源 Linux 发行版,具备出色的性能与安全性,并提供及时的安全更新。OpenEuler 采用类似 CentOS 的包管理工具,便于用户过渡。例如,可在 OpenEuler 上轻松安装与配置 Web 服务器。尽管其生态系统仍在发展中,但对于注重安全及国产技术的用户而言,OpenEuler 已展现出替代 CentOS 的强大潜力。不过,在具体应用时仍需综合考量业务需求。
641 4
|
Python
Python教程:一文了解如何使用Lambda 表达式和 filter函数实现过滤器
在 Python 中,Lambda 表达式是一种匿名函数,也就是没有名称的函数。它允许您快速定义简单的单行函数,通常用于函数式编程中的一些场景,例如在高阶函数中作为参数传递。
932 2

热门文章

最新文章