赞
踩
基于Python 3.5。
因为我们假设所有特征独立,所以我们可以把P(Y=1|X1=1,X2=0)写成
P(Y=1|X1=1,X2=0)=P(Y=1)P(X1=1|Y=1)P(X2=0|Y=1)P(X1=1)P(X2=0)
推广到更普遍的情况下,假设数据有k个特征,
P(Y|X1,X2,⋯,Xn)=1ZP(Y)∏i=1nP(Xi|Y)
其中Z是缩放因子,使得概率和为1。
对于一个分类问题,如果我们只需要得到其标签,我们只需要求解
ypred=argmaxyP(Y=y)∏i=1nP(Xi|Y=y)
3. 实战练习
下面我们利用朴素贝叶斯对“机器读中文:根据名字判断性别”中的数据进行预测。首先下载,并读取数据。
# -*- coding: utf-8 -*-
import pandas as pd
from collections import defaultdict
import math
# 读取train.txt
train = pd.read_csv('train.txt')
test = pd.read_csv('test.txt')
submit = pd.read_csv('sample_submit.csv')
看看训练集中的数据长什么样
train.head(10)
id name gender
0 1 闳家 1
1 2 玉璎 0
2 3 于邺 1
3 4 越英 0
4 5 蕴萱 0
5 6 子颀 0
6 7 靖曦 0
7 8 鲁莱 1
8 9 永远 1
9 10 红孙 1
names_female = train[train['gender'] == 0]
names_male = train[train['gender'] == 1]
totals = {'f': len(names_female),
'm': len(names_male)}
分别计算在所有女生(男生)的名字当中,某个字出现的频率。这一步相当于是计算 P(Xi|女生)和P(Xi|男生)
frequency_list_f = defaultdict(int)
for name in names_female['name']:
for char in name:
frequency_list_f[char] += 1. / totals['f']
frequency_list_m = defaultdict(int)
for name in names_male['name']:
for char in name:
frequency_list_m[char] += 1. / totals['m']
print(frequency_list_f['娟'])
0.004144009000562539
print(frequency_list_m['钢'])
0.0006299685015749209
上面两个例子说明P(名字中含有娟|女生)=0.004144,P(名字中含有钢|男生)=0.0006299
考虑到预测集中可能会有汉字并没有出现在训练集中,所以我们需要对频率进行Laplace平滑(什么是Laplace平滑)。
def LaplaceSmooth(char, frequency_list, total, alpha=1.0):
count = frequency_list[char] * total
distinct_chars = len(frequency_list)
freq_smooth = (count + alpha ) / (total + distinct_chars * alpha)
return freq_smooth
P(Y)∏i=1nP(Xi|Y),
在性别预测中,每个样本中大量的特征都是0。比如说只有X2=1,其他都为0,那么
ypred=argmaxyP(Y=y)P(X2=1|Y=y)∏ni=1P(Xi=0|Y=y)P(X2=0|Y=y)
由于P(Xi)的数值通常较小,我们对整体取对数(防止浮点误差),可得
logP(Y=y)+∑i=1nlogP(Xi=0|Y=y)+logP(X2=1|Y=y)−logP(X2=0|Y=y)
如果一个人的名字中有两个字,假设X5=1,X10=1,其余为0,那么该名字的对数概率表达式为
logP(Y=y)+∑i=1nlogP(Xi=0|Y=y)
+logP(X5=1|Y=y)−logP(X5=0|Y=y)+logP(X10=1|Y=y)−logP(X10=0|Y=y)
对于一种性别,logP(Y=y)+∑ni=1logP(Xi=0|Y=y)只需要计算一次。为了方面,我们将其数值存放在bases当中
base_f = math.log(1 - train['gender'].mean())
base_f += sum([math.log(1 - frequency_list_f[char]) for char in frequency_list_f])
base_m = math.log(train['gender'].mean())
base_m += sum([math.log(1 - frequency_list_m[char]) for char in frequency_list_m])
bases = {'f': base_f, 'm': base_m}
对于logP(Xi=1|Y)−logP(Xi=0|Y)部分,我们利用如下函数计算
def GetLogProb(char, frequency_list, total):
freq_smooth = LaplaceSmooth(char, frequency_list, total)
return math.log(freq_smooth) - math.log(1 - freq_smooth)
最后我们只需要组合以上函数,实现
ypred=argmaxyP(Y=y)P(X2=1|Y=y)∏ni=1P(Xi=0|Y=y)P(X2=0|Y=y) def ComputeLogProb(name, bases, totals, frequency_list_m, frequency_list_f): logprob_m = bases['m'] logprob_f = bases['f'] for char in name: logprob_m += GetLogProb(char, frequency_list_m, totals['m']) logprob_f += GetLogProb(char, frequency_list_f, totals['f']) return {'male': logprob_m, 'female': logprob_f} def GetGender(LogProbs): return LogProbs['male'] > LogProbs['female'] result = [] for name in test['name']: LogProbs = ComputeLogProb(name, bases, totals, frequency_list_m, frequency_list_f) gender = GetGender(LogProbs) result.append(int(gender)) submit['gender'] = result submit.to_csv('my_NB_prediction.csv', index=False)
最后结果输出在’my_NB_prediction.csv’中。
我们可以看看预测结果如何。
test[‘pred’] = result
test.head(20)
id name pred
0 0 辰君 0
1 1 佳遥 0
2 2 淼剑 1
3 3 浩苳 1
4 4 俪妍 0
5 5 秉毅 1
6 6 妍艺 0
7 7 海防 1
8 8 壬尧 1
9 9 珞千 0
10 10 义元 1
11 11 才君 1
12 12 吉喆 1
13 13 少竣 1
14 14 创海 1
15 15 熙兰 0
16 16 家冬 1
17 17 方荧 1
18 18 介二 1
19 19 钰泷 1
完整代码如下:
# -*- coding: utf-8 -*- import pandas as pd from collections import defaultdict import math # 读取train.txt train = pd.read_csv('train.txt') test = pd.read_csv('test.txt') submit = pd.read_csv('sample_submit.csv') #把数据分为男女两部分 names_female = train[train['gender'] == 0] names_male = train[train['gender'] == 1] totals = {'f': len(names_female), 'm': len(names_male)} frequency_list_f = defaultdict(int) for name in names_female['name']: for char in name: frequency_list_f[char] += 1. / totals['f'] frequency_list_m = defaultdict(int) for name in names_male['name']: for char in name: frequency_list_m[char] += 1. / totals['m'] def LaplaceSmooth(char, frequency_list, total, alpha=1.0): count = frequency_list[char] * total distinct_chars = len(frequency_list) freq_smooth = (count + alpha ) / (total + distinct_chars * alpha) return freq_smooth def GetLogProb(char, frequency_list, total): freq_smooth = LaplaceSmooth(char, frequency_list, total) return math.log(freq_smooth) - math.log(1 - freq_smooth) def ComputeLogProb(name, bases, totals, frequency_list_m, frequency_list_f): logprob_m = bases['m'] logprob_f = bases['f'] for char in name: logprob_m += GetLogProb(char, frequency_list_m, totals['m']) logprob_f += GetLogProb(char, frequency_list_f, totals['f']) return {'male': logprob_m, 'female': logprob_f} def GetGender(LogProbs): return LogProbs['male'] > LogProbs['female'] base_f = math.log(1 - train['gender'].mean()) base_f += sum([math.log(1 - frequency_list_f[char]) for char in frequency_list_f]) base_m = math.log(train['gender'].mean()) base_m += sum([math.log(1 - frequency_list_m[char]) for char in frequency_list_m]) bases = {'f': base_f, 'm': base_m} result = [] for name in test['name']: LogProbs = ComputeLogProb(name, bases, totals, frequency_list_m, frequency_list_f) gender = GetGender(LogProbs) result.append(int(gender)) submit['gender'] = result submit.to_csv('my_NB_prediction12.csv', index=False)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。