当前位置: 首页 > news >正文

利用朴素贝叶斯对名字进行性别预测

基于Python 3.5。

  1. 条件概率与贝叶斯定理
    对于事件A和B,当B发生的情况下,A发生的条件概率为
    P(A|B)=P(AB)P(B).
    如果把P(AB)表示为P(B|A)P(A),那么
    P(A|B)=P(B|A)P(A)P(B).
  2. 朴素贝叶斯
    朴素贝叶斯是一个基于贝叶斯定理的分类算法,其基本假设是所有特征是相互独立的。 举个例子来说,有一个二元分类问题,每个样本只有两个二元特征X1和X2。若已知一个样本(X1=1,X2=0),我们要预测它的标签为1的概率,就是等价于去计算
    P(Y=1|X1=1,X2=0)
    根据贝叶斯定理,我们可得
    P(Y=1|X1=1,X2=0)=P(Y=1)P(X1=1,X2=0|Y=1)P(X1=1,X2=0)
    其中P(Y=1)被称为先验(prior),P(X1=1,X2=0|Y=1)被称为似然(likelyhood),P(X1=1,X2=0)被成为证据(evidence)。

因为我们假设所有特征独立,所以我们可以把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用来存放训练集中女生、男生的总数

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)

相关文章:

  • 机器学习神器:GBDT,XGBOOST
  • hyperledge简要命令
  • chaincde shim包的方法名称及其相应功能
  • Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.
  • docker重要细节
  • docker运行tomcat
  • docker启动nginx
  • docker中的命令
  • Hyperledger Fabric介绍
  • 下载hyperledger-fabric源码
  • 谷歌浏览器安装
  • docker 安装mysql8
  • 区块链相关网站
  • dokcer通过 Dockerfile 构建部署tomcat图文详解
  • SOLID原则
  • “Material Design”设计规范在 ComponentOne For WinForm 的全新尝试!
  • 4月23日世界读书日 网络营销论坛推荐《正在爆发的营销革命》
  • 78. Subsets
  • java中的hashCode
  • Next.js之基础概念(二)
  • quasar-framework cnodejs社区
  • ReactNative开发常用的三方模块
  • Zsh 开发指南(第十四篇 文件读写)
  • 高度不固定时垂直居中
  • 给第三方使用接口的 URL 签名实现
  • ------- 计算机网络基础
  • 聊聊hikari连接池的leakDetectionThreshold
  • 买一台 iPhone X,还是创建一家未来的独角兽?
  • 强力优化Rancher k8s中国区的使用体验
  • 扫描识别控件Dynamic Web TWAIN v12.2发布,改进SSL证书
  • 使用 QuickBI 搭建酷炫可视化分析
  • 用element的upload组件实现多图片上传和压缩
  • 职业生涯 一个六年开发经验的女程序员的心声。
  • 《天龙八部3D》Unity技术方案揭秘
  • 不要一棍子打翻所有黑盒模型,其实可以让它们发挥作用 ...
  • ​LeetCode解法汇总2696. 删除子串后的字符串最小长度
  • ​linux启动进程的方式
  • # Pytorch 中可以直接调用的Loss Functions总结:
  • #{}和${}的区别?
  • #Linux(帮助手册)
  • (02)vite环境变量配置
  • (6)设计一个TimeMap
  • (第9篇)大数据的的超级应用——数据挖掘-推荐系统
  • (三)elasticsearch 源码之启动流程分析
  • (十六)Flask之蓝图
  • (转) Android中ViewStub组件使用
  • (转)Linux NTP配置详解 (Network Time Protocol)
  • (转)ObjectiveC 深浅拷贝学习
  • *++p:p先自+,然后*p,最终为3 ++*p:先*p,即arr[0]=1,然后再++,最终为2 *p++:值为arr[0],即1,该语句执行完毕后,p指向arr[1]
  • .NET 8.0 发布到 IIS
  • .Net 垃圾回收机制原理(二)
  • .netcore如何运行环境安装到Linux服务器
  • .Net面试题4
  • @Conditional注解详解
  • [ NOI 2001 ] 食物链