|
| 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