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

一.从贝叶斯公式开始

贝叶斯分类实际上是利用用贝叶斯公式,算出每种状况下发生的几率,再取几率较大的一个分类做为结果。咱们先来看看贝叶斯公式:html

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

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

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

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

这里能够用一个例子来讲明这个公式。算法

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

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

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

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

根据贝叶斯定理:code

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

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

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/25)。

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

接下来咱们看一个实际的例子,是我在 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


推荐阅读:

python Kmeans算法解析 从分治算法到 MapReduce

相关文章
相关标签/搜索