贝叶斯分类算法实例 --根据姓名推测男女

一.从贝叶斯公式开始

贝叶斯分类其实是利用用贝叶斯公式,算出每种情况下发生的概率,再取概率较大的一个分类作为结果。我们先来看看贝叶斯公式:

P(A|B) = P(B|A) P(A) / P(B)

其中P(A|B)是指在事件B发生的情况下事件A发生的概率。

在贝叶斯定理中,每个名词都有约定俗成的名称:

  • P(A|B)是已知B发生后A的条件概率,也由于得自B的取值而被称作A的后验概率。
  • P(A)是A的先验概率(或边缘概率)。之所以称为"先验"是因为它不考虑任何B方面的因素。
  • P(B|A)是已知A发生后B的条件概率,也由于得自A的取值而被称作B的后验概率。
  • P(B)是B的先验概率或边缘概率。

这里可以用一个例子来说明这个公式。

看一个简单的小例子来展示贝叶斯定理

病人的例子:
某个医院早上收了八个门诊病人,如下表。

症状 职业 疾病
打喷嚏 护士 感冒
打喷嚏 农夫 过敏
头痛 建筑工人 脑震荡
头痛 建筑工人 感冒
打喷嚏 建筑工人 过敏
打喷嚏 教师 感冒
头痛 教师 脑震荡
打喷嚏 教师 过敏

现在又来了第九个病人,是一个打喷嚏的建筑工人。请问他患上感冒的概率有多大?

根据贝叶斯定理:

P(A|B) = P(B|A) P(A) / P(B)

可得满足“打喷嚏”和“建筑工人”两个条件下,感冒的概率如下:

 P(感冒|打喷嚏x建筑工人)
= P(打喷嚏x建筑工人|感冒) x P(感冒) / P(打喷嚏x建筑工人)

假定"打喷嚏"和"建筑工人"这两个特征是独立的(即这两个条件没有相关性,比如不存在说他是建筑工人他打喷嚏的概率比较大或者比较小这种关系),因此,上面的等式就变成了。

 P(感冒|打喷嚏x建筑工人) 
 = P(打喷嚏|感冒) x P(建筑工人|感冒) x P(感冒) /  P(打喷嚏) x P(建筑工人)

通过统计可得:

 P(感冒|打喷嚏x建筑工人) 
 = (2/3) x (1/3) x (3/8) / (5/8) x (3/8) 
 = (16/45)

通过贝叶斯公式算出了满足条件下感冒的概率,那么现在贝叶斯分类器如何实现呢?

接上面的例子,从上面我们得出了 P(感冒|打喷嚏x建筑工人) 的值,那么我们可以再算出
P(不感冒|打喷嚏x建筑工人) 的值,计算结果如下:

 P(不感冒|打喷嚏x建筑工人) 

 = P(打喷嚏|不感冒) x P(建筑工人|不感冒) x P(不感冒)  /  P(打喷嚏) x P(建筑工人)
 = (3/5) x (2/5) x (5/8) / (5/8) x (3/8) 
 = (16/25)

OK,现在我们知道来一个打喷嚏的建筑工人,他感冒的几率是P(感冒|打喷嚏x建筑工人)= (16/45)。不感冒的几率是P(不感冒|打喷嚏x建筑工人)= (16/45)。

通过对概率的比较,我们就可以将打喷嚏的建筑工人分类到“不感冒”人群中(不感冒的概率比较大)。 这就是朴素贝叶斯分类器的最简单的应用了。当然你也看到了,贝叶斯分类器需要我们应用到统计所得的结果,这需要数据量比较大,大到能满足大数定理(大数定理这里就不多解释啦,自行百度即可),以及样本数据足够客观。

接下来我们看一个实际的例子,是我在 github 上看到的一个项目例子,根据姓名来对性别进行分类。看上去觉得很不可思议吧,其实也是用了上述说的贝叶斯分类的方法。

二.贝叶斯分类器根据姓名判别男女 -python

项目github地址:https://github.com/observerss/ngender

先说一下主要思路,我们日常从一个人的名字中,基本上能大致判断这个名字的主人是男是女。比如李大志,这个名字一听就很男性。为什么呢?因为字和字男性名字用得比较多。虽然机器一眼看不出来,但它可以通过统计信息来判断。如果有足够多的数据,我们就可以统计出字和字用作男性名字的比例,计算概率信息。然后就可以用这些概率,运用上述的贝叶斯公式来进行计算,判定性别。

代码其实不难,各个字的统计数据已经计算好,在项目中给出。我们只需要读取文件数据,存储到 python 的字典中,计算出概率,然后预测的时候进行计算即可。我们先看核心代码,稍后会有例子说明。

里面核心代码文件为:

这里主要讲一下核心代码的内容:https://github.com/observerss/ngender/blob/master/ngender/ngender.py

class Guesser(object):

    //初始化函数,调用下面的_load_model()函数
    def __init__(self):
        self._load_model()

    //初始化一些参数
    def _load_model(self):
        self.male_total = 0
        self.female_total = 0
        self.freq = {}

        //这里加载charfreq.csv文件,这个文件存放的是一些汉字是男女的统计信息
        with open(os.path.join(os.path.dirname(__file__),
                               'charfreq.csv'),
                  'rb') as f:
            # skip first line
            next(f)
            //将文件中的信息存储,累加,以便稍后计算概率
            for line in f:
                line = line.decode('utf-8')
                char, male, female = line.split(',')
                char = py2compat(char)
                //计算男性总数
                self.male_total += int(male)
                //计算女性总数
                self.female_total += int(female)
                //一个汉字对应的那女数量
                self.freq[char] = (int(female), int(male))

        self.total = self.male_total + self.female_total

        //一个汉字是男女概率
        for char in self.freq:
            female, male = self.freq[char]
            self.freq[char] = (1. * female / self.female_total,
                               1. * male / self.male_total)

    def guess(self, name):
        name = py2compat(name)
         //去掉姓氏
        firstname = name[1:]
        //过滤掉不在这个unicode编码范围内的字符
        for char in firstname:
            assert u'\u4e00' <= char <= u'\u9fa0', u'姓名必须为中文'

        //贝叶斯分类器,分别计算出男的概率和女的概率
        pf = self.prob_for_gender(firstname, 0)
        pm = self.prob_for_gender(firstname, 1)

        //若名字为男的概率较大,则分类为男,反之则为女
        if pm  pf:
            return ('male', 1. * pm / (pm + pf))
        elif pm < pf:
            return ('female', 1. * pf / (pm + pf))
        else:
            return ('unknown', 0)

    //贝叶斯公式的应用
    def prob_for_gender(self, firstname, gender=0):
        p = 1. * self.female_total / self.total \
            if gender == 0 \
            else 1. * self.male_total / self.total

        for char in firstname:
            p *= self.freq.get(char, (0, 0))[gender]

        return p


guesser = Guesser()

上述代码还是比较简单的,首先在初始化的时候会调用 _load_model() 函数,这个函数完成的是一些概率计算工作,比如先将每个字对应是男是女的概率计算好存储在字典中。

然后在计算的时候,先过滤掉姓氏。然后分别计算出这个名字是男是女的概率,比如计算 P(男|李大志)和P(女|李大志),,对比哪个概率大一些,然后进行男女分类。

这里放上一个例子:判断

P(gender=男|name=本山) 
= P(name=本山|gender=男) * P(gender=男) / P(name=本山)
= P(name has 本|gender=男) * P(name has 山|gender=男) * P(gender=男) / P(name=本山)
  • 公式原理为贝叶斯公式,下面对公式中中各个项进行解答,首先明确我们已经统计得到P(gender=男),P(gender=女)的概率。

怎么算 P(name has 本|gender=男)?

  • “本”在男性名字中出现的次数 / 男性字出现的总次数

怎么算 P(gender=男)?

  • 男性名出现的次数 / 总次数

怎么算 P(name=本山)?

这个概率对男女来说都是一样的,所以没必要算出来,即我们只需要比较P(name=本山|gender=男) * P(gender=男)和P(name=本山|gender=女) * P(gender=女)两部分谁比较大即可做出判断。

以上就是贝叶斯分类器介绍的全部内容啦。

参考文章:
http://www.ruanyifeng.com/blog/2013/12/naive_bayes_classifier.html

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

推荐阅读更多精彩内容