为了20年后的梦想

1995年-1996年,写了一本 Visual Basic 3-4的书,想必当时过于年轻,自以为是的文字很幼稚,文字不够代码来凑,其实也不是很负责。也缺乏持续更新的能力和勇气,当时我的编程经验全部来源于自学,做过的项目有几个,但不多,也不复杂。最关键是,对于 Visual Basic 本身的认识还是比较肤浅的。

想起来那时的确是充满了热情,白天也是完全没有办法写作,每天上班前,下班后,周末,几乎一年,花费在上。虽然作品不满意,还算是完成了。

20年后,又开始这样的梦想,前些年,比较空的时候到时也有想过,却不太了解行情,原来,现在出版行业也早就市场化运作了,只是要出书并不是那么难。

和同事们选择了自己相对还比较擅长和有独到体会的 Python 和其用在机器学习方面作为主题。因为外面 Python 的书其实也很多了,实在不想写一本简单的入门级,无疑,这个定位在中等水平的目标,让我们一方面提高很多,一方面也是绞尽脑汁,受累。

而今年工作的忙碌,到了这个岁数的种种事情,都耗用了很多时间和精力。不知道多少个晚上和周末,在看资料、写 demo 程序、组织文字、review 其他同事写的书稿,或许这就是梦想,这就是有梦想的力量吧!

记录一下,也有一些颓废的时候,作为鼓励。

python flask 写 api 如何返回自定义错误

在 python 开发中,利用 flask 写 restful api 函数的时候,除了标准的400、500等这些返回码通过 abort() 返回以外,怎么另外返回自定义的错误代码和信息呢?

我们碰到的业务场景是对于api 输入参数的各类校验以及在业务逻辑执行的时候,都会返回统一的400代码,同时也会返回我们约定的描述详细错误的代码以及描述字符串,提供给调用方来处理,这样可以让其用户体验做得更好,同时详细错误代码和描述字符串也会自动打印在 log 日志中。

flask 的官方文档中告诉我们:

默认情况下,错误代码会显示一个黑白的错误页面。如果你要定制错误页面, 可以使用 errorhandler() 装饰器

在写 restful api 的时候,并没有页面可以返回,我们可以在 flask 提供的代码基础上稍加改造如下。

在你的初始化 flask app 的相关代码中加入下面两个函数:

@app.errorhandler(CustomFlaskErr)
def handle_flask_error(error):

    # response 的 json 内容为自定义错误代码和错误信息
    response = jsonify(error.to_dict())

    # response 返回 error 发生时定义的标准错误代码
    response.status_code = error.status_code

    return response
class CustomFlaskErr(Exception):

    # 默认的返回码
    status_code = 400

    # 自己定义了一个 return_code,作为更细颗粒度的错误代码
    def __init__(self, return_code=None, status_code=None, payload=None):
        Exception.__init__(self)
        self.return_code = return_code
        if status_code is not None:
            self.status_code = status_code
        self.payload = payload

    # 构造要返回的错误代码和错误信息的 dict
    def to_dict(self):
        rv = dict(self.payload or ())

        # 增加 dict key: return code
        rv['return_code'] = self.return_code

        # 增加 dict key: message, 具体内容由常量定义文件中通过 return_code 转化而来
        rv['message'] = J_MSG[self.return_code]

        # 日志打印
        logger.warning(J_MSG[self.return_code])

        return rv

CustomFlaskErr 是我们自己写的处理错误的类,然后通过 @app.errorhandler(CustomFlaskErr) 这个装饰器在 flask 中注册。

具体功能在注释里基本都写了,我们看一下怎么使用这个自定义错误处理器。

# 用户名输入为空
if user_name is None:
    raise CustomFlaskErr(USER_NAME_ILLEGAL, status_code=400)

当需要处理某个错误的时候,rasie 刚才的 CustomFlaskErr,传递另外定义好的自己的错误代码,以及标准的返回代码;

上面说的常量定义文件可以参考如下:

USER_ALREADY_EXISTS = 20001  # 用户已经存在
J_MSG = {USER_ALREADY_EXISTS: 'user already exists'}

通过这样的机制,就做到了在具体 restful api 的业务逻辑代码中简单的进行各类自定义错误的处理,所有的错误处理是集中的,细颗粒度的错误代码和消息也是集中维护,便于扩展。

flask 官方文档和一些网上的资料都说比较简单,实践中摸索了这样的实现方式供参考。

python 中使用装饰器来统一检查 flask 用户权限

最近在一个项目中,需要判断 restful 接口函数传入的时候,是否之前已经登录状态是某个特定用户,以及该用户有没有指定的权限。检查下来如果没有的话,立刻返回错误,中断功能。

遮掩的场景虽然也可以通过标准的调用函数来操作,但都不如用装饰器来得简单。都知道装饰器好用不好写,废话不说,先来看看这个场景怎么实现,还是有一定的通用性的。

def validate_current_is_admin(f):
    @functools.wraps(f)
    def decorated_function(*args, **kws):
        # 需要在登录状态调用, 检查是否为有admin权限的用户登录,
        # 如果不是,返回错误码;
        if g.user.user_name != 'admin':
            raise CustomFlaskErr(USER_MUST_HAS_ADMIN_PRIVILEGE, status_code=401)

        # 验证权限是否为 admin, 不是的话,返回401错误
        if g.user.role_id != Permission.ADMIN:
            raise CustomFlaskErr(USER_MUST_HAS_ADMIN_PRIVILEGE, status_code=401)

        return f(*args, **kws)

    return decorated_function

这是一个标准的装饰器的写法,如果你要写一个简单的装饰器,整个框架可以参考。

装饰器调用举例:

@app.route('/api/create_user', methods=['POST'])
@auth.login_required
@validate_current_is_admin
def create_user():

    # 获得参数
    user_name = request.json.get('user_name')
    password = request.json.get('password')
......

 

核心代码的业务逻辑也不复杂,根据 flask 的 g 对象中预存的用户 user 进行检查处理,flask 的这些定义非常灵活,flask.g 怎么使用可以查看 flask 的文档。

这里的 user 以及相关的属性属于具体业务逻辑,就不展开解释了,可以望文生义。

因为不对 args 和 kws 这些参数进行解析和处理,所处理的是 flask 全局对象。最后将参数都原路打包返回即可,没有问题的话交给使用装饰器的代码继续处理。

这个例子比较简单,主要还是熟悉装饰器的基本用法。

python 之前因后果

如果你英语阅读还可以的话,推荐这个网站:The History of Python

2013年11月后就不再更新了,一共31篇 blog,讲的是 python 语言设计中的一些来龙去脉。我在搜索研究列表生成式的时候偶然看到了这个网站。

挺有趣的。

它更新的最后一篇文章是 The history of bool, True and False

或许你也像我一样被 python 的布尔值稍稍困惑过,我们可以看看当年这些天才的程序语言设计者到底是怎么想的。

python 单元测试中使用参数化测试技巧(parameterisation)

这篇文章介绍了在 python 的单元测试中如何使用参数化测试(parameterisation) 技巧来做到将测试数据和测试逻辑分离。Improve Python testing with parameterisation

的确,我们在应用程序中对于业务逻辑和数据的分离会做很好的考虑,但是在自动化测试,在单元测试中有时候会忽略这一点,我发现我也有这个问题,所以写出来的单元测试类似这样:

# test_prime.py
import unittest

from prime import is_prime


class TestIsPrime(unittest.TestCase):

    def test_x_negative(self):
        self.assertEqual(is_prime(-1), False)

    def test_x_zero(self):
        self.assertEqual(is_prime(0), False)

    def test_x_one(self):
        self.assertEqual(is_prime(1), False)

    def test_x_two(self):
        self.assertEqual(is_prime(2), True)

    def test_x_three(self):
        self.assertEqual(is_prime(3), True)

    def test_x_ten(self):
        self.assertEqual(is_prime(10), False)

    def test_x_fifty_three(self):
        self.assertEqual(is_prime(53), True)


if __name__ == "__main__":
    unittest.main()

而这篇文章中建议我们应该这样:

import unittest

from prime import is_prime


class TestIsPrime(unittest.TestCase):

    def test_is_prime(self):
        test_cases = [
            (-1, False),
            (0, False),
            (1, False),
            (2, True),
            (3, True),
            (10, True),
            (53, True),
        ]
        for x, output in test_cases:
            with self.subTest(name=str(x)):
                self.assertEqual(is_prime(x), output)


if __name__ == "__main__":
    unittest.main()

好处不言而喻。

python 3.x 的线程池模式实现多线程

之前发布在简书,我觉得简书还是一个做得非常好的写作平台,也有一定的互动,我现在比较纠结的就是在受众的广度、受众的亲疏、自己可以掌握的自由度、维护成本这些变量之间。

比如问题之一,简书虽然有很好的写作平台,但是我就是喜欢在 wordpress 里面自己折腾主题等等,怎么办。哎。

先从简书这里搬一些自己的文章过来。


看了不少书和资料,自认为对于 python 中的线程、进程、协程等略知一二了。

想实现一个多线程池的模型,但是也不想用 queue 甚至是 celery 这些,查了很多资料,国内的原创的不多,并且基本都是停留在 python 2.7 的时代,而且国内的文章即便用 google 搜索,大部分文章也是互相转载。国外的资料比较好的还是在 stackoverflow,国内的简书上好文章不少。

搜了半天,在 python 的官方文档上赫然有着一个例子:

The concurrent.futures module provides a high-level interface for asynchronously executing callables.
The asynchronous execution can be performed with threads, using ThreadPoolExecutor, or separate processes, using ProcessPoolExecutor. Both implement the same interface, which is defined by the abstract Executor class.

用 concurrent.futures 即可,然后

ThreadPoolExecutor is an Executor subclass that uses a pool of threads to execute calls asynchronously.

找了好久差点想自己实现(担心自己写的很烂)的线程池就在这里,例子如下:

import urllib.request

URLS = ['http://www.foxnews.com/',
        'http://www.cnn.com/',
        'http://europe.wsj.com/',
        'http://www.bbc.co.uk/',
        'http://some-made-up-domain.com/']

# Retrieve a single page and report the URL and contents
def load_url(url, timeout):
    with urllib.request.urlopen(url, timeout=timeout) as conn:
        return conn.read()

# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
    # Start the load operations and mark each future with its URL
    future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            data = future.result()
        except Exception as exc:
            print('%r generated an exception: %s' % (url, exc))
        else:
            print('%r page is %d bytes' % (url, len(data)))

这个例子写得很清楚,可以直接运行,不过建议把那些网址换掉,因为 g*w 的关系。

没想到 python 的官方文档做的这么好,我准备从头到底先通读一遍。

从学习角度这个代码是够了,当然如果要用在真正的应用里面,还要考虑更多的事情哦!

学习 python 的可爱的孩子们

又是一个学期,时间真快,自己也不容易,这个学期14节课,风里来雨里去,来回就要1个多小时,坚持下来。今天终于是最后一节课,欢乐的考试时光。

还是希望现在这些条件越来越好的孩子们,可以好好学习电脑,学习编程,成为未来的栋梁之才!

小时候自己主要在中学和少科站,至今不能忘记当年格致中学的励幼娣、周柏生老师,少科站的曹文浩老师,谢谢他们的悉心指点,当年的我也有点像现在这些孩子,聪明、贪玩。很多道理都是后来才懂。

学习 python 这一年

大约2015年4月到5月开始,正式学习 python,发现之前大概在2009年左右也学过,可能当时没有坚持下去。

记得去年开始学 python 的时候,1个月左右,给同事写了一个基于 csv 处理的小程序,当时就被 python 的简洁优雅所倾倒。

然后边学边写东西,本来为公司 zion 框架写一个 dsl,当时水平还不行,所以写成了一个 sql 的包装工具 r2,用来在前端业务逻辑调用后台数据库的时候简化 sql 语句写法以及做到和数据库无关。

真正让我自己 python 水平感觉有点突破的是几个事情:

1 写真正生产上的应用。需要考虑的事情非常多,比如一个简单的 r2,就让我学到了 log、conf、import、class 等很多基本知识的应用,以及单元测试、性能测试。

2 教别人 python。这是让自己的基础知识巩固最好的办法之一。要把别人教会,且处理各类奇怪的运行错误,很有挑战。这样的结果,是对诸如列表、字符串、元组、字典、函数、循环等基本概念非常清楚。不管多复杂的程序,90%的代码其实还是基本的操作,在这90%的代码设计和编写的时候可以减少错误,节约时间,自然有用。

3 看资料。晚上有大量的英文和中文的 python 资料,绝大多数都写的很好,受益匪浅。

在我的推进下,公司也在个别项目上开始使用 python,通过 flask 来构建 restful 接口,机器学习也基于 keras 和 tensorflow 开始了实际的应用。

我相信,进步会是跳跃式的,而这还是仅仅发生在一年间,python 在胶水语言的应用,连接 js、php、java 和 moble 开发上面,以及 python 在人工智能、机器学习上这几年强劲的表现,都让人激动不已。

我的2016 Python B 班

从三月开始,江湖救急。

也一直好为人师。

终于找到了舞台。

昨天,这13个小孩,Python 初级班结束。

谢谢豆妈,谢谢静枫,谢谢所有的家长,谢谢聪明的孩子们。

很多时候感觉回到了自己小时候,在少科站、少年宫、格致老大楼的机房。

IMG_7951

IMG_7952

或许,这样耗费很多业余时间,来回路上,准备讲义和题目,制作考试用的 rpg 游戏,有的人会觉得我很傻,很多时候我也认为自己不是一个一流的程序员,但是当这些孩子们编程入门了,或许明天的 facebook、google 的创造者就在他们中间,想想这也是很开心的。

使用 python 基于朴素贝叶斯进行文本分类学习笔记之五:增加停用词

还记得之前我们搭建的朴素贝叶斯的分类模型,在正面负面各9个样本的情况下,正确率如下。

{'01': 1, '10': 5, '00': 7, '11': 3}
(0.875, 0.375)

 

我开始引入停用词,从测试来看,主要是在训练的时候效果比较明显,因为中文样本中标点符号和很多常用词占比还是比较大的,引入停用词机制前后,差不多是三分之一的量。

下面是读入停用词的函数代码。

 def read_stopwords(self):

        self.stopwords_list = []

        # 获得停用词文件的本地文件
        filename = get_long_filename_with_sub_dir_module('bayes', 'stopwords.txt')[1]

        with open(filename, 'r') as f:
            for line in f:
                self.stopwords_list.append(line.rstrip())

        print(self.stopwords_list)

 

目前我是将朴素贝叶斯的这个分类,作为 fish_base 包的一部分功能。对于停用词来说属于功能部分,而之前的训练文档其实不是功能部分,是由真实代码或者 demo 代码传递给分类器的。因此训练文档和测试文档属于 demo 代码,而停用词属于分类器代码。

(国内网上很多的贝叶斯代码的解释者可能都是学习数据分析、统计分析的职业人士,但是代码的写法和扩展性,略显简单,我可能习惯了尽量做得完善一些,副作用是会比较复杂一点,需要更多 python 和编程的基础)

整个类的代码最后给出。这里解释一下

get_long_filename_with_sub_dir_module

这个函数是为了获得模块运行时候的路径,否则一般的获取路径办法获得是执行文件的路径,这就是之前说的如果只是一个 demo,不会有这个问题,统统在一个路径下面,但是如果考虑做成包,做成 module,封装逻辑的话,就会复杂一点,另外还要考虑各个操作系统可能的差异。

这个函数属于 fish_base 的 commmon 部分,目前 fish_base 公开的版本1.0.7 中还不支持,在 github 上的1.0.8 支持该函数。

停用词来自于之前说到过的 snownlp 包,感谢作者。停用词数量大约1400个左右,以后考虑支持用户自定义停用词。

在训练过程引入停用词之后,再用昨天的测试样本测试一下,得到了如下的结果。

{'00': 8, '10': 4, '01': 0, '11': 4}
(1.0, 0.5)

 

正面被分类成正面准确率100%,负面被分类成负面也从37.5% 提升到 50%,略有进步。

按照公司数据分析团队的建议,后者百分比还不够高是因为训练样本太少的缘故。

如此少的训练样本,得到了这样的结果,不得不说朴素贝叶斯的确很厉害,一点也不 naive。

之后我们还会继续改进的地方是:
1 将判断错误的样本增加到训练样本中,来重新训练
2 分词,增加用户自定义词汇
3 测试材料,增加停用词处理(目前测试下来,对提升正确率没有作用),这也和目前举例中的测试文本比较短有关,并且这个也和性能有关,训练过程中引入停用词判断对性能的损失是无所谓的,反正是在训练过程中,但是实际使用分类还是要越快越好
4 我们会将整个分类器通过 Falsk 包装成 web 接口,加入 job 概念,这样调用程序只需要传入训练文本和测试文本,之后就可以生成特定的分类器概率矩阵,然后供调用程序在真实场景下使用,作为调用程序的项目组不需要知道后面这些细节
5 所有的数据存储可以本地实例化,sqlite 或者 mysql 之类的支持
6 支持三元和四元的分类

从用 python 来实现朴素贝叶斯分类器来对中文文本进行倾向性分析来说,暂时告一段落了。所有代码都是这几天里面改写和增加的,防止错误的部分几乎没有,也没有进行完整的单元测试。

下面是当前版本完整的朴素贝叶斯分类器的类的代码,直接使用需要有 python 基础,也可以之后使用 fish_base 包来调用。

最新版本源代码在这里: github.com/chinapnr/fish_base

pypi 的安装包会稍微滞后一些。

from numpy import *
import jieba

from fish_base import get_long_filename_with_sub_dir_module


class ClassNaiveBayes:

    # 训练 list, 默认内容, 原书中的内容
    train_doc_list = [['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
                      ['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
                      ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
                      ['stop', 'posting', 'stupid', 'worthless', 'garbage'],
                      ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
                      ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
    # 倾向性向量, 0:正面 1:负面
    train_doc_sent_vec = [0, 1, 0, 1, 0, 1]

    # 单词列表集合
    word_list = []

    # 正面和负面概率, 先验概率
    p0_v = 0
    p1_v = 0
    p_ab = 0

    stopwords_list = []

    # 2016.5.18
    # 读入停用词
    def read_stopwords(self):

        self.stopwords_list = []

        # 获得停用词文件的本地文件
        filename = get_long_filename_with_sub_dir_module('bayes', 'stopwords.txt')[1]

        with open(filename, 'r') as f:
            for line in f:
                self.stopwords_list.append(line.rstrip())

        print(self.stopwords_list)

    # 2016.5.19
    def word_optimize(self, l):
        # 停用词过滤
        temp_word_list = [x for x in l if x not in self.stopwords_list]
        return temp_word_list

    # 2016.5.16 5.19
    # 创建单词集合
    # 输入 data_list: 数据列表内容, 两维list
    # 输出 单维list
    def create_word_list(self, data_list):
        # create empty set
        word_set = set([])
        for document in data_list:
            # union of the two sets
            word_set = word_set | set(document)
        word_list = list(word_set)
        # 词汇处理
        word_list = self.word_optimize(word_list)
        # print('word list count:', len(word_list))
        return word_list

    # 2016.5.16
    # 将单词 list 转换为向量
    # 输入 word_list: 单词列表 new_word_list: 需要向量化的单词列表
    # 输出 vec: 生成的向量数组
    @staticmethod
    def words_to_vec(word_list, new_word_list):
        vec = [0] * len(word_list)
        for word in new_word_list:
            if word in word_list:
                vec[word_list.index(word)] += 1
            else:
                pass
                # print("the word: %s is not in my Vocabulary!" % word)
        return vec

    # 2016.5.16
    # 进行 naive bayes 训练
    # 输入 train_matrix: 训练举证 train_category: 正反向量列表
    # 输出 p0_v, p1_v:正面反面概率, p_ab:先验概率
    @staticmethod
    def train_nb0(train_matrix, train_category):

        num_train_docs = len(train_matrix)
        num_words = len(train_matrix[0])
        p_ab = sum(train_category) / float(num_train_docs)

        # 创建给定长度的填满1的数组
        p0_num = ones(num_words)
        p1_num = ones(num_words)

        p0_d = 2.0
        p1_d = 2.0
        for i in range(num_train_docs):
            if train_category[i] == 1:
                p1_num += train_matrix[i]
                p1_d += sum(train_matrix[i])
            else:
                p0_num += train_matrix[i]
                p0_d += sum(train_matrix[i])

        p1_v = log(p1_num / p1_d)
        p0_v = log(p0_num / p0_d)
        return p0_v, p1_v, p_ab

    # 2016.5.16
    # 分类
    # 输入 向量, 正面反面概率,事件概率
    # 输出 正面或者反面
    @staticmethod
    def classify_nb(vec, p0_vec, p1_vec, p_class1):
        # element-wise mult
        p0 = sum(vec * p0_vec) + log(1.0 - p_class1)
        p1 = sum(vec * p1_vec) + log(p_class1)
        print('p0:', p0, 'p1:', p1)
        if p1 > p0:
            return 1
        else:
            return 0

    # 2016.5.16
    # 训练, 生成需要的向量参数等
    def train(self):
        # 生成单词列表集合
        self.word_list = self.create_word_list(self.train_doc_list)

        # 训练矩阵初始化
        train_matrix = []

        # 根据训练文档进行循环
        for post_in_doc in self.train_doc_list:
            # 构建训练矩阵, 将单词列表转化为向量
            train_matrix.append(self.words_to_vec(self.word_list, post_in_doc))

        # 根据训练矩阵和情感分析向量进行训练,得到
        self.p0_v, self.p1_v, self.p_ab = self.train_nb0(array(train_matrix), array(self.train_doc_sent_vec))

    # 2016.5.16
    # 根据输入内容测试 Naive Bayes 模型
    # 输入 test_word_list: 需要测试的单词 list
    # 输出 0 or 1, 表示正面或者反面
    def run_nb(self, word_list):

        # 对输入的内容转化为向量
        this_post_vec = array(self.words_to_vec(self.word_list, word_list))

        # 返回分类的值
        return self.classify_nb(this_post_vec, self.p0_v, self.p1_v, self.p_ab)

    # 2016.5.18
    @staticmethod
    def init_cut_word():
        jieba.initialize()

    # 2016.5.18
    # 打开训练文档, 将内容增加到内部变量
    def open_train_doc_ch(self, filename, class_mark):

        train_txt0 = []
        with open(filename, 'r') as f:
            for line in f:
                train_txt0.append(line.rstrip())

        for item in train_txt0:
            s = list(jieba.cut(item))
            self.train_doc_list.append(s)
            self.train_doc_sent_vec.append(class_mark)

    # 2016.5.18
    # 根据测试样本来测试分类的准确率
    # 输出 人工正确/机器判断正确 人工错误/机器判断错误 的两个百分比
    def test_nb(self, filename):

        test_doc_list = []
        pre_class_list = []

        # 设定测试结果 dict
        test_result_dict = {'11': 0, '10': 0, '00': 0, '01': 0}

        # 打开测试文本
        with open(filename, 'r') as f:
            for line in f:
                # 获得人工设定的类别
                pre_class_list.append(line[0:1])
                # 获得需要测试的文本
                test_doc_list.append(line[2:].rstrip())

        # 测试文本的长度
        test_doc_count = len(test_doc_list)

        for i, item in enumerate(test_doc_list):

            s = list(jieba.cut(item))

            # 对输入单词进行优化处理
            s = self.word_optimize(s)

            # 获得程序分类结果
            computer_class = self.run_nb(s)
            # 获得人工设定的分类结果
            pre_class = pre_class_list[i]

            # 结果记录到测试结果 dict 中
            index = '**'

            if pre_class == '1':
                index = str(10 + computer_class)
            if pre_class == '0':
                index = '0' + str(computer_class)

            test_result_dict[index] += 1

            print(s, pre_class, computer_class)

        print(test_result_dict)

        # 返回结果, 假设测试文本中正面和负面各占一半
        return test_result_dict['00'] / (test_doc_count / 2), test_result_dict['11'] / (test_doc_count / 2)

 

下面是测试用的程序。

from fish_base import bayes
import jieba

nb = bayes.ClassNaiveBayes()

nb.train()

test_list = ['love', 'my', 'dalmation']
print(test_list, 'classified as: ', nb.run_nb(test_list))

test_list = ['stupid', 'garbage']
print(test_list, 'classified as: ', nb.run_nb(test_list))

nb.train_doc_list = []
nb.train_doc_sent_vec = []

# for Chinese

# 初始化分词
nb.init_cut_word()

# 读入停用词
nb.read_stopwords()

nb.open_train_doc_ch('train_bayes/good.txt', 0)
nb.open_train_doc_ch('train_bayes/bad.txt', 1)

nb.train()
print(nb.p0_v, nb.p1_v, nb.p_ab)

print(nb.test_nb('train_bayes/test.txt'))

# 指定测试
print()
test_s = '这个手机很好,我很喜欢'
print(test_s)
test_list = list(jieba.cut(test_s))
p = nb.run_nb(test_list)
if p == 0:
    print('classified as good ')
else:
    print('classified as bad ')

# while 1:
#     test_s = input('input comment:')
#     test_list = list(jieba.cut(test_s))
#     print(test_list)
#     p = nb.run_nb(test_list)
#     if p == 0:
#         print('classified as good ')
#     else:
#         print('classified as bad ')
#
#     print()

# 2016.5.18
# {'01': 1, '10': 5, '00': 7, '11': 3}
# (0.875, 0.375)
#
#
# 2016.5.18 增加去除停用词,一般意义
# {'11': 4, '00': 8, '10': 4, '01': 0}
# (1.0, 0.5)

 

(感谢这几天项目开发团队和数据分析开发团队同事支持和耐心讲解。)

使用 python 基于朴素贝叶斯进行文本分类学习笔记之一:开始
使用 python 基于朴素贝叶斯进行文本分类学习笔记之二:将原书程序修改并转换为类
使用 python 基于朴素贝叶斯进行文本分类学习笔记之三:中文内容的倾向性判断初步
使用 python 基于朴素贝叶斯进行文本分类学习笔记之四:增加测试文本和计算正确率
使用 python 基于朴素贝叶斯进行文本分类学习笔记之五:增加停用词