【模式识别】贝叶斯分类器的C++实现

分类问题

在介绍贝叶斯分类器之前我们首先需要知道分类问题是什么。

给你一个训练数据集,数据集中有一些样本,每个样本有一个或若干特征x
𝑥
(这里x
𝑥
的是向量),每个样本都属于一个类别wi
𝑤
𝑖
,现在让你通过这个训练集得到一个分类器,这个分类器具有这样的功能:

给定一个新的样本(也就是给定一个特征x
𝑥
),你的分类器能判断它属于哪个类别

其实我们可以把分类器看成是一个函数f(x)
𝑓
(
𝑥
)
,函数的返回值就是对应特征所属的类别,所有的分类器的目的都是去寻找一个比较好的函数能更好的描述特征与类别之间的关系。

贝叶斯定理:
P(wi|x)=P(x|wi)P(wi)∑kj=1P(x|wj)P(wj)
𝑃
(
𝑤
𝑖
|
𝑥
)
=
𝑃
(
𝑥
|
𝑤
𝑖
)
𝑃
(
𝑤
𝑖
)

𝑗
=
1
𝑘
𝑃
(
𝑥
|
𝑤
𝑗
)
𝑃
(
𝑤
𝑗
)


P(wi)
𝑃
(
𝑤
𝑖
)
是,表示在不知道样本特征的情况下,某个样本属于wi
𝑤
𝑖
类的概率。

P(x|wi)
𝑃
(
𝑥
|
𝑤
𝑖
)
是类条件概率密度,可以看成是在某一类别的情况下特征的分布(概率密度函数)

P(wi|x)
𝑃
(
𝑤
𝑖
|
𝑥
)
是后验概率,就是在知道样本的特征的情况下该样本属于某一个特征的概率。

贝叶斯分类器的设计思路

一句话概括贝叶斯分类器:

在知道先验概率和类条件概率密度的情况下算后验概率,后验概率最大的类别作为最终类别

我们的问题是”给定特征判断这个特征所对应的类别”,一个容易想到的思路是算出这个特征属于每个类别的概率,然后取最大的那个类别作为最终的分类。其中”属于某个类别的概率”可以表示成条件概率的形式P(wi|x)
𝑃
(
𝑤
𝑖
|
𝑥
)
,也就是贝叶斯定理中的后验概率,接下来就是去求得P(x|wi)
𝑃
(
𝑥
|
𝑤
𝑖
)
和P(wi)
𝑃
(
𝑤
𝑖
)
就行了.

例子

将人的身高(height)和体重(weight)作为分类特征,分为两组类别,男性(male)和女性(female),现在给你一组男性的身高和体重的数据和女性的身高体重数据作为训练数据集训练出一个贝叶斯分类器。

男性的数据保存在MALE.TXT,包含若干行数据,每行两个数x1 x2分别表示身高和体重

女性的数据类似

假设二者相关,在正态分布假设下估计概率密度函数

由于假设了两个特征满足正态分布,所以我们可以通过μ1、μ2、θ1、θ2、ρ
𝜇
1

𝜇
2

𝜃
1

𝜃
2

𝜌
五个参数确定某个类别的样本分布,也就是类条件概率密度P(x|wi)
𝑃
(
𝑥
|
𝑤
𝑖
)
代码实现

#include<iostream>
#include<fstream>
#include<cmath>
#include<cstdio>
using namespace std;
const int MAXN=1000;
const double pi=3.1415926;
ifstream cin1("FEMALE.TXT");
ifstream cin2("MALE.TXT");
ifstream cin3("test2.txt");
ofstream cout1("result.txt");
struct HUMAN
{
    double height;
    double weight;
};
HUMAN female[MAXN];
HUMAN male[MAXN];
int female_num;
int male_num;

double P_female;
double P_male;
struct NORMAL
{
  double mu1;
  double mu2;
  double delta1;
  double delta2;
  double rho;
};
NORMAL female_normal;
NORMAL male_normal;
/*
读入文件数据
*/
void In()
{
    male_num=0;
    female_num=0;
    while(cin1>>female[female_num+1].height>>female[female_num+1].weight)
    {
        female_num++;
    }
    while(cin2>>male[male_num+1].height>>male[male_num+1].weight)
    {
        male_num++;
    }
}
void Init()
{
      P_female=0.5;
      P_male=0.5;
}
/*
读入样本数量个样本,并求出该样本的二维正态分布
*/
void Normalization(struct HUMAN *human,int human_num,struct NORMAL &human_normal)
{
    double mu1,mu2,delta1,delta2,rho;
    mu1=0;mu2=0;delta1=0;delta2=0,rho=0;
    for(int i=1;i<=human_num;i++)
    {
          mu1+=human[i].height;
          mu2+=human[i].weight;
    }
    mu1/=human_num;
    mu2/=human_num;

    for(int i=1;i<=human_num;i++)
    {
          delta1+=(human[i].height-mu1)*(human[i].height-mu1);
          delta2+=(human[i].weight-mu2)*(human[i].weight-mu2);
    }
    delta1/=human_num;
    delta2/=human_num;
    delta1=sqrt(delta1);
    delta2=sqrt(delta2);
    for(int i=1;i<=human_num;i++)
    {
          rho+=human[i].height*human[i].weight;
    }
    rho/=human_num;
    rho-=mu1*mu2;
    rho/=(delta1*delta2);
    human_normal.mu1=mu1;
    human_normal.mu2=mu2;
    human_normal.delta1=delta1;
    human_normal.delta2=delta2;
    human_normal.rho=rho;
    cout<<mu1<<" "<<delta1<<" "<<mu2<<" "<<delta2<<" "<<rho<<endl;
}
/*
在分布为normal的条件下特征为(x1,x2)的条件概率
*/

double P(struct NORMAL &normal,double x1,double x2)
{
    double ans;
    double mu1=normal.mu1;
    double mu2=normal.mu2;
    double delta1=normal.delta1;
    double delta2=normal.delta2;
    double rho=normal.rho;
     rho=0;
    ans=(1/(2*pi*delta1*delta2*        sqrt(1-rho*rho)            ))*exp(-1/(2*sqrt(1-rho*rho)   )*(             ((x1-mu1)*(x1-mu1))/(delta1*delta1)   +   ((x2-mu2)*(x2-mu2))/(delta2*delta2)   -    (2*rho*(x1-mu1)*(x2-mu2))/(delta1*delta2)                                   )   );
    return ans;
}
/*
归为normal的后验概率
t为0表示female,1表示male
*/
double Posterior_probability1(double x1,double x2,bool t)
{
    double Pw;
    struct NORMAL normal;
    if(t==0)return (P(female_normal,x1,x2)*P_female)/(P(female_normal,x1,x2)*P_female+P(male_normal,x1,x2)*P_male);
    else return (P(male_normal,x1,x2)*P_male)/(P(female_normal,x1,x2)*P_female+P(male_normal,x1,x2)*P_male);
}
/*
判断是哪个类别,返回0表示female,1表示male
*/
bool Classify(double x1,double x2)
{
    //cout<<Posterior_probability1(x1,x2,0)<<" "<<Posterior_probability1(x1,x2,1)<<endl;
    if(Posterior_probability1(x1,x2,0)>=Posterior_probability1(x1,x2,1))return 0;
    else return 1;
}
/*
得到错误率并将错误率输出到result.txt中
*/
void Find_error_rate()
{
    double height,weight;
    char c;
    int right_num=0;
    int wrong_num=0;
    while(cin3>>height>>weight>>c)
    {
        if(   (c=='f' || c=='F')   && Classify(height,weight)==0)//分类为女性并且正确
             right_num++;
        else if(   (c=='m' || c=='M')   && Classify(height,weight)==1)//分类为男性并且正确
             right_num++;
        else
            wrong_num++;

        cout1<<height<<" "<<weight<<" "<<Classify(height,weight)<<endl;
    }
    cout<<"error rate is "<<(double)wrong_num/(double)(wrong_num+right_num)<<endl;
}
int main()
{
    In();
    Init();
    Normalization(female,female_num,female_normal);
    Normalization(male,male_num,male_normal);
    //female_normal.rho=0;
    //male_normal.rho=0;
    Find_error_rate();
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
文章知识点与官方知识档案匹配,可进一步学习相关知识
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/mmy1996/article/details/72743411

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值