Skip to content

Commit 571ae61

Browse files
committed
贝叶斯分类 二维正态分布 感知机 线性单元 权重更新法则
贝叶斯分类 二维正态分布 感知机 线性单元 权重更新法则
0 parents  commit 571ae61

13 files changed

+1110
-0
lines changed

BayesFenLei.cpp

Lines changed: 394 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,394 @@
1+
//
2+
// BayesFenLei.cpp
3+
// CPPB20180806
4+
//
5+
// Created by admindyn on 2018/8/30.
6+
// Copyright © 2018年 admindyn. All rights reserved.
7+
//
8+
9+
/*
10+
贝叶斯分类器 C++
11+
12+
贝叶斯分类器原理
13+
14+
随机变量 W(类别标识 W1 W2 W3 W4) X(特征向量)
15+
16+
三种概率
17+
18+
P(W1) = 表示在所有分类结果中出现第一类的概率是多少 显然我们认为界定分类后 概率也就固定了 是四分之一
19+
20+
21+
接下来就是概率论中的条件概率了
22+
p(W1|X)= 表示在已知特征向量X的条件下最后分类结果为第一类的概率是多少
23+
根据贝叶斯条件概率知识 我们知道
24+
p(W1|X)= P(W1,X)/P(X)
25+
26+
以上是我们的目标 拿到特征向量 立马就能知道是哪一类数据的概率
27+
28+
但是上面明显不能立马得到结果 很多概率不知道
29+
30+
------让上面不知道的 联合概率P(W1,X) P(X) 知道 就是我们要重点解决的问题--
31+
32+
33+
P(X|W_) = 表示在某一个确定类别情况下,特征向量为X(已知特征向量)的概率 (看成是某一类别情况下该样本属于某一个特征的概率---概率密度函数)
34+
35+
这里由于W_此时为变量 对所有分类作出计算
36+
我们在这里称为类条件概率密度
37+
38+
39+
在这里补充贝叶斯全概率公式计算
40+
P(X) =∑P(X|W1)P(W1)
41+
42+
43+
44+
*/
45+
46+
47+
48+
49+
50+
#include <cmath>
51+
#include <cstdio>
52+
#include "BayesFenLei.hpp"
53+
54+
55+
const int MAXN = 1000;
56+
const double pi = 3.1415926;
57+
/*
58+
C++文件流
59+
https://www.cnblogs.com/gyq8962/p/9201820.html
60+
以下类型需要包含头文件 < fstream>
61+
62+
ofstream 输出流:是从内存(控制台)读到硬盘;
63+
ifstream 输入流:是从硬盘读到内存(控制台).
64+
fstream 文件流:是可对打开的文件进行读写操作.
65+
66+
getline()的原型是istream& getline ( istream &is , string &str , char delim );
67+
68+
其中 istream &is 表示一个输入流,譬如cin;string&str表示把从输入流读入的字符串存放在这个字符串中(可以自己随便命名,str什么的都可以);char delim表示遇到这个字符停止读入,在不设置的情况下系统默认该字符为'\n',也就是回车换行符(遇到回车停止读入)。
69+
70+
*/
71+
72+
ifstream cin1("female.txt");
73+
74+
ifstream cin2("male.txt");
75+
76+
ifstream cin3("test.txt");
77+
78+
// ofstream 输出流:是从内存(控制台)读到硬盘;
79+
ofstream cout1("result.txt");
80+
81+
82+
struct HUMAN
83+
{
84+
double height;
85+
double weight;
86+
87+
};
88+
89+
HUMAN female[MAXN];
90+
HUMAN male[MAXN];
91+
92+
int female_num;
93+
94+
int male_num;
95+
96+
double P_female;
97+
double P_male;
98+
struct NORMAL {
99+
double mu1;
100+
double mu2;
101+
double delta1;
102+
double delta2;
103+
double rho;
104+
};
105+
106+
NORMAL female_normal;
107+
108+
NORMAL male_normal;
109+
110+
111+
/*
112+
读入文件数据
113+
*/
114+
115+
void In()
116+
{
117+
male_num = 0;
118+
female_num = 0;
119+
120+
/*
121+
需要男女两张身高体重表
122+
123+
cin1 读取女性(两个维度)身高 体重 表
124+
统计 女性数目
125+
*/
126+
while (cin1>>female[female_num+1].height>>female[female_num+1].weight) {
127+
female_num++;
128+
}
129+
/*
130+
cin2 读取男性(两个维度) 身高 体重 表
131+
统计 男性数目
132+
*/
133+
while (cin2>>male[male_num+1].height>>male[male_num+1].weight) {
134+
male_num++;
135+
}
136+
137+
}
138+
139+
void Init()
140+
{
141+
/*
142+
人为分类 总共两大类
143+
因此 各自概率为定值 都是二分之一
144+
*/
145+
P_female = 0.5;
146+
P_male = 0.5;
147+
}
148+
149+
/*
150+
读入样本数量个样本
151+
并求出该样本的二维正态分布
152+
*/
153+
154+
void Normalization(struct HUMAN* human,int human_num,struct NORMAL&human_normal)
155+
{
156+
157+
double mu1,mu2,deltal1,deltal2,rho;
158+
159+
mu1 = 0; mu2 = 0; deltal1 = 0; deltal2 = 0 ;
160+
161+
rho = 0;
162+
163+
/*计算两个维度各自的期望 平均值*/
164+
165+
for (int i = 1; i<human_num; i++) {
166+
mu1 += human[i].height;
167+
mu2 += human[i].weight;
168+
}
169+
170+
mu1 /= human_num;
171+
172+
mu2 /= human_num;
173+
174+
/*计算两个维度各自的方差 */
175+
176+
for (int i=1; i<human_num; i++) {
177+
deltal1 += (human[i].height-mu1)*(human[i].height-mu1);
178+
179+
deltal2 += (human[i].weight-mu2)*(human[i].weight-mu2);
180+
}
181+
182+
deltal1 /= human_num;
183+
184+
deltal2 /= human_num;
185+
186+
/*计算两个维度各自的标准差 */
187+
188+
deltal1 = sqrt(deltal1);
189+
190+
deltal2 = sqrt(deltal2);
191+
/*某个随机变量的标准差的求法2 以上是先求方差再求标准差*/
192+
/*
193+
方法二
194+
方差 由 E(X²)-E²(X) 求得
195+
再开根号 求的标准差
196+
*/
197+
198+
/*计算两个维度的相关系数 rho 皮尔逊相关系数*/
199+
for (int i=1; i<human_num; i++) {
200+
rho += human[i].height*human[i].weight;
201+
}
202+
203+
/*计算E(X*Y) 的期望*/
204+
rho /= human_num;
205+
/*将E(X*Y) 的期望 减去 E(X)*E(Y)两个期望的积*/
206+
rho -= mu1*mu2;
207+
/*以上两个实际上是 协方差 的计算方法 cov(X,Y)*/
208+
/*将协方差 除以 两个随机变量的 标准差之积*/
209+
rho /= (deltal1 * deltal2);
210+
211+
/* 以上求得相关系数*/
212+
213+
human_normal.mu1 = mu1;
214+
215+
human_normal.mu2 = mu2;
216+
217+
human_normal.delta1 = deltal1;
218+
219+
human_normal.delta2 = deltal2;
220+
221+
human_normal.rho = rho;
222+
223+
cout<<mu1<<" "<< deltal1 <<" "<<mu2<<" "<< deltal2 <<" "<<rho<<endl;
224+
225+
}
226+
227+
/*
228+
在分布为normal的条件下特征为(x1,x2)的条件概率
229+
*/
230+
231+
double P(struct NORMAL& normal,double x1,double x2)
232+
{
233+
/*
234+
这里 使用标准正态分布 估计出
235+
P(height|male)=(1/√(2𝞹𝛅²))*exp((-(height-期望)²/(2𝛅²)))
236+
237+
238+
239+
*/
240+
double ans;
241+
242+
double mu1 = normal.mu1;
243+
244+
double mu2 = normal.mu2;
245+
246+
double delta1 = normal.delta1;
247+
248+
double delta2 = normal.delta2;
249+
250+
double rho = normal.rho;
251+
252+
rho = 0;
253+
254+
/*
255+
以下根据已经获得的 两个维度的随机变量的 期望 标准差 相关系数
256+
257+
进行概率估计
258+
259+
但是这里需要注意的是这里是二维正态分布 考虑相关系数
260+
这里我们暂时忽略相关系数
261+
262+
263+
*/
264+
/*
265+
(X,Y) 服从参数为 u1,u2,𝛅1,𝛅2,𝞺(相关系数) 的二维正态分布
266+
267+
分布函数
268+
𝐅(X,Y)=(2𝞹𝛅1𝛅2√(1-𝞺²))exp〔-1/(2(1-𝞺²))[(X-u1)²/𝛅1²-2𝞺(X-U1)(Y-U2)/𝛅1𝛅2+(Y-U2)²/𝛅2² ]〕
269+
270+
*/
271+
/*
272+
sqrt 开平方
273+
*/
274+
double d1 = (1/(2*pi*delta1*delta2)*sqrt(1-rho*rho));
275+
/*
276+
exp 以e为底的指数运算
277+
*/
278+
double d2 = -1/(2*sqrt(1-rho*rho));
279+
280+
double d3 = ((x1-mu1)*(x1-mu1))/(delta1*delta1);
281+
282+
double d4 = ((x2-mu2)*(x2-mu2))/(delta2*delta2);
283+
284+
double d5 = (2*rho*(x1-mu1)*(x2-mu2)/(delta1*delta2));
285+
286+
double d6 = (d3 - d5 + d4);
287+
288+
d6 = exp(d2*d6);
289+
290+
291+
292+
ans = d1*d6;
293+
294+
return ans;
295+
296+
}
297+
298+
/*
299+
归为normal的后验概率
300+
t为0表示female 1表示male
301+
*/
302+
double Posterior_probability1(double x1,double x2,bool t)
303+
{
304+
305+
double PW;
306+
struct NORMAL normal;
307+
308+
double d1 = P(female_normal, x1, x2)*P_female;
309+
310+
311+
double d2 = P(male_normal, x1, x2)*P_male;
312+
313+
double d3 = P(female_normal, x1, x2)*P_female+P(male_normal, x1, x2)*P_male;
314+
315+
if (t==0) {
316+
317+
return d1/d3;
318+
}else
319+
{
320+
return d2/d3;
321+
322+
}
323+
324+
}
325+
326+
/*
327+
判断是那个类别 返回0表示female 1表示male
328+
*/
329+
330+
bool Classify(double x1,double x2)
331+
{
332+
if (Posterior_probability1(x1, x2, 0)>=Posterior_probability1(x1, x2, 1)) {
333+
return 0;
334+
}else
335+
{
336+
return 1;
337+
}
338+
339+
}
340+
341+
342+
/*
343+
得到错误率并将错误率输出到result.txt中
344+
*/
345+
void Find_error_rate()
346+
{
347+
348+
double height,weight;
349+
350+
char c;
351+
352+
int right_num = 0;
353+
354+
int wrong_num = 0;
355+
356+
while (cin3>>height>>weight>>c) {
357+
if ((c=='f'||c=='F')&&Classify(height, weight)==0) {
358+
359+
//分类为女性并且正确
360+
right_num++;
361+
}else if((c=='m'||c=='M')&&Classify(height, weight)==1)
362+
{
363+
//分类为男性并且正确
364+
right_num++;
365+
}else
366+
{
367+
wrong_num++;
368+
}
369+
370+
cout1<<height<<" "<<weight<<" "<<Classify(height, weight)<<endl;
371+
}
372+
373+
374+
375+
cout<<"error rate is "<<(double)wrong_num/(double)(wrong_num+right_num)<<endl;
376+
377+
}
378+
379+
//二维正态分前 先标准正态分布
380+
void Normal()
381+
{
382+
383+
Normalization(female,female_num,female_normal);
384+
385+
Normalization(male,male_num,male_normal);
386+
387+
}
388+
389+
390+
391+
392+
393+
394+

0 commit comments

Comments
 (0)