使用pandas,7行代码实现朴素贝叶斯

作者:hhh5460

大抵分成两类

一、离散的、标签化的数据

原文没有使用pandas,我使用pandas重新实现了朴素贝叶斯算法,看起来非常简洁、清爽。

import pandas as pd

'''
导入数据集
{a1 = 0, a2 = 0, C = 0} {a1 = 0, a2 = 0, C = 1}
{a1 = 0, a2 = 0, C = 0} {a1 = 0, a2 = 0, C = 1}
{a1 = 0, a2 = 0, C = 0} {a1 = 0, a2 = 0, C = 1}
{a1 = 1, a2 = 0, C = 0} {a1 = 0, a2 = 0, C = 1}
{a1 = 1, a2 = 0, C = 0} {a1 = 0, a2 = 0, C = 1}
{a1 = 1, a2 = 0, C = 0} {a1 = 1, a2 = 0, C = 1}
{a1 = 1, a2 = 1, C = 0} {a1 = 1, a2 = 0, C = 1}
{a1 = 1, a2 = 1, C = 0} {a1 = 1, a2 = 1, C = 1}
{a1 = 1, a2 = 1, C = 0} {a1 = 1, a2 = 1, C = 1}
{a1 = 1, a2 = 1, C = 0} {a1 = 1, a2 = 1, C = 1}
'''
#导入数据集
data = [[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[1, 0, 0],
[1, 0, 0],
[1, 0, 0],
[1, 1, 0],
[1, 1, 0],
[1, 1, 0],
[1, 1, 0],
[0, 0, 1],
[0, 0, 1],
[0, 0, 1],
[0, 0, 1],
[0, 0, 1],
[1, 0, 1],
[1, 0, 1],
[1, 1, 1],
[1, 1, 1],
[1, 1, 1]]

df = pd.DataFrame(data, columns=['a1', 'a2', 'c'])

'''
#计算类别的先验概率
#P(C = 0) = 0.5
#P(C = 1) = 0.5
'''

#计算类别的先验概率
pc = df['c'].value_counts()/df['c'].size

'''
计算每个特征属性条件概率:
P(a1 = 0 | C = 0) = 0.3
P(a1 = 1 | C = 0) = 0.7
P(a2 = 0 | C = 0) = 0.4
P(a2 = 1 | C = 0) = 0.6
P(a1 = 0 | C = 1) = 0.5
P(a1 = 1 | C = 1) = 0.5
P(a2 = 0 | C = 1) = 0.7
P(a2 = 1 | C = 1) = 0.3
'''
# 计算每个特征属性条件概率:
pa1 = pd.crosstab(df['c'], df['a1'], margins=True).apply(lambda x:x/x[-1], axis=1)
pa2 = pd.crosstab(df['c'], df['a2'], margins=True).apply(lambda x:x/x[-1], axis=1)

'''
测试样本:
x = { a1 = 1, a2 = 1}
p(x | C = 0) = p(a1 = 1 | C = 0) * p( a2 = 1 | C = 0) = 0.3 * 0.6 = 0.18
p(x | C = 1) = p(a1 = 1 | C = 1) * p (a2 = 1 | C = 1) = 0.5 * 0.3 = 0.15
'''
# 给出测试样本:
x = pd.Series([1,1], index=['a1', 'a2'])
px = pa1.ix[:,x[0]].mul(pa2.ix[:,x[1]])[:-1]
'''
计算P(C | x):
P(C = 0) * p(x | C = 1) = 0.5 * 0.18 = 0.09
P(C = 1) * p(x | C = 1) = 0.5 * 0.15 = 0.075
所以认为测试样本属于类型C1
'''
# 计算P(C | x)
res = pc.mul(px).argmax()
print(res)

同样的方法,7行代码解决这里的问题:

import pandas as pd

data = [['打喷嚏','护士','感冒'],
        ['打喷嚏','农夫','过敏'],
        ['头痛','建筑工人','脑震荡'],
        ['头痛','建筑工人','感冒'],
        ['打喷嚏','教师','感冒'],
        ['头痛','教师','脑震荡']]

df = pd.DataFrame(data, columns=['症状','职业','疾病'])

#计算类别的先验概率
pr = df['疾病'].value_counts()/df['疾病'].size

# 计算每个特征属性条件概率:
pzz = pd.crosstab(df['疾病'], df['症状'], margins=True).apply(lambda x:x/x[-1], axis=1)
pzy = pd.crosstab(df['疾病'], df['职业'], margins=True).apply(lambda x:x/x[-1], axis=1)

# 给出测试样本:
x = pd.Series(['打喷嚏','建筑工人'], index=['症状','职业'])
px = pzz.ix[:,x[0]].mul(pzy.ix[:,x[1]])[:-1]

# 计算P(C | x)
res = pr.mul(px).argmax()
print(res)

二、连续的、非标签化的数据

1.连续变量,样本足够大。使用区间,标签化

这里的第二个例子:
**

# 检测SNS社区中不真实账号

# 运维人员人工检测过的1万个账号作为训练样本

# 原始数据格式:
# ['日志数量','好友数量','注册天数','是否使用真实头像','账号类别']

'''可惜,没有真实数据!!!!'''
data = [
    [3,0,120,1,1],
    [3,0,120,1,1],
    [3,0,120,1,1],
    [3,0,120,1,1],
    [3,0,120,1,1],
    [3,0,120,1,1],
    [3,0,120,1,1],
    #...
    [3,0,120,1,1]]

df = pd.DataFrame(data, columns=['日志数量','好友数量','注册天数','是否使用真实头像','账号类别'])

# 计算训练样本中每个类别的频率(当做 类别的先验概率)
'''
P(C=0) = 8900/10000 = 0.89
P(C=1) = 1100/10000 = 0.11
'''
pr = df['账号类别'].value_counts()/df['账号类别'].size

#================================================================
#----------------------------------------------------------------

# 构建两个特征
# ['日志数量/注册天数','好友数量/注册天数']

df['日志数量/注册天数'] = df['日志数量'].div(df['注册天数'])
df['好友数量/注册天数'] = df['好友数量'].div(df['注册天数'])

# 把'日志数量/注册天数'分解成[0, 0.05]、(0.05, 0.2)、[0.2, +∞)三个区间
# 把'好友数量/注册天数'分解成[0, 0.1]、(0.1, 0.8)、[0.8, +∞)三个区间

# 打标签函数(根据 x 值所在的区间)
def depart(x, low, high):
    if x <= low:
        return 0
    elif x >= high:
        return 2
    else:
        return 1

# 打标签
df['特征1'] = df['日志数量/注册天数'].apply(depart, args=(0.05, 0.2))
df['特征2'] = df['好友数量/注册天数'].apply(depart, args=(0.1, 0.8))
df['特征3'] = df['是否使用真实头像']

#----------------------------------------------------------------
#================================================================

# 计算每个特征属性条件概率:
ptz1 = pd.crosstab(df['账号类别'], df['特征1'], margins=True).apply(lambda x:x/x[-1], axis=1)
ptz2 = pd.crosstab(df['账号类别'], df['特征2'], margins=True).apply(lambda x:x/x[-1], axis=1)
ptz3 = pd.crosstab(df['账号类别'], df['特征3'], margins=True).apply(lambda x:x/x[-1], axis=1)

# 给出测试样本:
x_ = pd.Series([0.1, 0.2, 0], index=['日志数量/注册天数', '好友数量/注册天数', '是否使用真实头像'])

#================================================================
#----------------------------------------------------------------
# 打标签
x = pd.Series([depart(x_[0], 0.05, 0.2), depart(x_[1], 0.1, 0.8), x_[2]], index=['特征1','特征2','特征3'])
#----------------------------------------------------------------
#================================================================
px = ptz1.ix[:,x[0]].mul(ptz2.ix[:,x[1]]).mul(ptz3.ix[:,x[2]])[:-1]

# 计算P(C | x)
res = pr.mul(px).argmax()
print(res)

2.连续变量,样本太小,无法划分区间。

假设符合正态分布,先求出按类的均值,方差,再代入密度函数
这里的第三个例子:
**

import pandas as pd

# 关于处理连续变量的另一种方法

# 下面是一组人类身体特征的统计资料
data = [['男', 6, 180, 12],
        ['男', 5.92, 190, 11],
        ['男', 5.58, 170, 12],
        ['男', 5.92, 165, 10],
        ['女', 5, 100, 6],
        ['女', 5.5, 150, 8],
        ['女', 5.42, 130, 7],
        ['女', 5.75, 150, 9]]

df = pd.DataFrame(data, columns=['性别','身高(英尺)','体重(磅)','脚掌(英寸)'])

# 已知某人身高6英尺、体重130磅,脚掌8英寸,请问该人是男是女?
x = pd.Series([6,130,8], index=['身高(英尺)','体重(磅)','脚掌(英寸)'])

# 这里的困难在于,
# 1.连续变量
# 2.样本太少(无法分成区间)

# 解决:
# 假设男性和女性的身高、体重、脚掌都是正态分布,
# 通过样本计算出均值和方差,也就是得到正态分布的密度函数。
# 有了密度函数,就可以把值代入,算出某一点的密度函数的值。

mean_male = df[df['性别']=='男'].mean()
var_male = df[df['性别']=='男'].var()

mean_formale = df[df['性别']=='女'].mean()
var_formale = df[df['性别']=='女'].var()

df2 = pd.concat((x, mean_male, var_male, mean_formale, var_formale), axis=1, keys=['x', 'mean_male', 'var_male', 'mean_formale', 'var_formale'])

# 正态分布密度函数:
# f(x|male) = exp(-(x-mean)**2/(2*var))/sqrt(2*pi*var)
from math import pi
def f(x, mean, var):
    return exp(-(x-mean)**2/(2*var))/sqrt(2*pi*var) # 密度函数

# 求对应的密度函数值
df2['px_male'] = df2['x', 'mean_male', 'var_male'].apply(lambda x:f(x[0],x[1],x[2])) ###################报错!容后再改!!
df2['px_formale'] = df2['x', 'mean_formale', 'var_formale'].apply(lambda x:f(x[0],x[1],x[2]))

# 类别的先验概率
pr = df['性别'].value_counts()/df['性别'].size

# 预测结果
res = pd.Series([df2['p_male'].cumprod()[-1]*pr['男'], df2['p_formale'].cumprod()[-1]]*pr['女'], index=['男','女']).argmax()
print(res)

时间: 2024-11-05 14:41:07

使用pandas,7行代码实现朴素贝叶斯的相关文章

详解基于朴素贝叶斯的情感分析及 Python 实现

相对于「 基于词典的分析 」,「 基于机器学习 」的就不需要大量标注的词典,但是需要大量标记的数据,比如: 还是下面这句话,如果它的标签是: 服务质量 - 中 (共有三个级别,好.中.差) ╮(╯-╰)╭,其是机器学习,通过大量已经标签的数据训练出一个模型, 然后你在输入一条评论,来判断标签级别 宁馨的点评 国庆活动,用62开头的信用卡可以6.2元买一个印有银联卡标记的冰淇淋, 有香草,巧克力和抹茶三种口味可选,我选的是香草口味,味道很浓郁. 另外任意消费都可以10元买两个马卡龙,个头虽不是很大

抽象的艺术 - 朴素贝叶斯

Situation 2016年,A市对30000+市民进行了年收入统计,收入>=50K的人数7000+,<=50K的人数20000+. 为了提高税收,需要分析两种收入群体的特征,分析员抽取了"职业.年龄.性别.出生地.教育程度"等属性,更进一步分析哪些职业收入高,哪个年龄段收入高等等,为来年税收做预测. 问题来了:2017年2月,A市人口增加了20000+,对这个群体年收入做预测. 朴素贝叶斯 分类算法有很多种,今天讲朴素贝叶斯的原理和Java实现. 朴素贝叶斯分类的正式定

朴素贝叶斯从放弃到入门

理论基础 联合概率 联合概率表示两个事件共同发生的概率.A与B的联合概率表示为$P(AB)$,$P(A,B)$或者$P(A \bigcap B)$. 联合概率可以推广到任意又穷多个事件出现的情况,设($A_1,A_2,\cdots,A_n$)为任意n个事件($n\ge2$),事件$A_1,A_2,\cdots,A_n$共同发生的概率记为$P(A_1A_2 \dots A_n)$,$P(A_1,A_2,\dots,A_n)$或者$P(A_1 \bigcap A_2 \bigcap \dots \b

机器学习算法实践:朴素贝叶斯 (Naive Bayes)

前言 上一篇<机器学习算法实践:决策树 (Decision Tree)>总结了决策树的实现,本文中我将一步步实现一个朴素贝叶斯分类器,并采用SMS垃圾短信语料库中的数据进行模型训练,对垃圾短信进行过滤,在最后对分类的错误率进行了计算. 正文 与决策树分类和k近邻分类算法不同,贝叶斯分类主要借助概率论的知识来通过比较提供的数据属于每个类型的条件概率, 将他们分别计算出来然后预测具有最大条件概率的那个类别是最后的类别.当然样本越多我们统计的不同类型的特征值分布就越准确,使用此分布进行预测则会更加准

朴素贝叶斯算法的python实现方法_python

本文实例讲述了朴素贝叶斯算法的python实现方法.分享给大家供大家参考.具体实现方法如下: 朴素贝叶斯算法优缺点 优点:在数据较少的情况下依然有效,可以处理多类别问题 缺点:对输入数据的准备方式敏感 适用数据类型:标称型数据 算法思想: 比如我们想判断一个邮件是不是垃圾邮件,那么我们知道的是这个邮件中的词的分布,那么我们还要知道:垃圾邮件中某些词的出现是多少,就可以利用贝叶斯定理得到. 朴素贝叶斯分类器中的一个假设是:每个特征同等重要 函数loadDataSet() 创建数据集,这里的数据集是

朴素贝叶斯分类器

  所谓分类,就是根据事物的特征(Feature)对其归类(Class)    特征的数据特点有两种可能: 1. 离散/标签 2. 连续/浮点数(大样本/小样本)   下面我们分别来看 一.离散/标签 这是一个病人分类的例子 某个医院早上收了六个门诊病人,如下表. 症状 职业 疾病 打喷嚏 护士 感冒 打喷嚏 农夫 过敏 头痛 建筑工人 脑震荡 头痛 建筑工人 感冒 打喷嚏 教师 感冒 头痛 教师 脑震荡 现在又来了第七个病人,是一个打喷嚏的建筑工人.请问他患上感冒的概率有多大?   根据贝叶斯

朴素贝叶斯-学习笔记

朴素贝叶斯 标签(空格分隔): 机器学习 朴素贝叶斯算法适合给文档分类. 词向量 先对文档分词,所有文档中所有不同的词构成词汇表.每个文档根据词汇表能形成一个词向量,1表示对应维度的词条出现在文档中,0表示词条未出现. 这种想法推广开来,发现向量是新时代的数字. 比如一个可能发生的事件集合,可以表示为一个向量,每个维度对应一个事件发生的概率. 问题描述 任给一个文档,怎样确定其分类? 每个文档对应一个词向量$\vec w$,需要确定$p(c_i|\vec w)$的最大值,即:已知这个文档的条件下

基于朴素贝叶斯的定位算法

1 定位背景介绍       一说到定位大家都会想到gps,然而gps定位有首次定位缓慢(具体可以参考之前的博文<LBS定位技术>).室内不能使用.耗电等缺陷,这些缺陷大大限制了gps的使用.在大多数移动互联网应用例如google地图.百度地图等,往往基于wifi.基站来进行定位.        一般APP在请求定位的时候会上报探测到的wifi信号.基站信号.以wifi为例,手机会探测到周围各个wifi(mac地址)对应的信号强度(RSSI),即收集到信号向量(<WF1, RSSI1&g

机器学习基础(三)朴素贝叶斯

贝叶斯决策一直很有争议,今年是贝叶斯250周年,历经沉浮,今天它的应用又开始逐渐活跃,有兴趣的可 以看看斯坦福Brad Efron大师对其的反思,两篇文章:"Bayes'Theorem in the 21st Century"和 "A250-YEAR ARGUMENT:BELIEF, BEHAVIOR, AND THE BOOTSTRAP".俺就不参合这事了,下面来看看朴素贝叶 斯分类器. 有时我们想知道给定一个样本时,它属于每个类别的概率是多少,即P(Ci|X),