分类算法(2) ---- 朴素贝叶斯算法(NB)

朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法。

朴素贝叶斯分类器假设样本每个特征与其他特征都不相关。


一. 基于离散变量

     下面以一个简单的数据集为例,阐述基于NB的回归/预测模型:

      

     上述三篇文本的词列表如下:

     

    首先可以将上述两篇训练文本(train1和train2),以及一篇测试文本(test1)转为如下向量格式:

     

分析:

     基于NB的回归模型如何在已知train1和train2的标准答案(即公众感到“joy”的概率)分别为0.6和0.7的前提下,预测test1对应的公众感到“joy”的概率值。
    为了便于模型的推导,我们将文本train1记为d1,train2记为d2,test1记为d3,情感joy记为j,词sheva记为s,词goal记为g。我们要估计的是p(d3, j),即文本test1和情感joy的联合概率值(也就是说,100名用户看到test1,会有多大的可能性将它关联到joy)。由于d3包含s和g两个词,因此要估计的p(d3, j)近似等于p(s, g, j),即词sheva、goal和情感joy的联合概率值。基于NB的回归模型利用所有的训练文本及其标准答案来估计这个值:
p(s, g, j) = p(d1, s, g, j) + p(d2, s, g, j) 概率的加法法则,

其中,p(d1, s, g, j) = p(d1, j, s, g) = p(d1, j)p(s | d1, j)p(g | d1, j, s) 概率的乘法法则,同上
上式中,p(d1, j) = 0.6;p(s | d1, j) = 0.33;p(g | d1, j, s) = 0,这里假设给定每篇文本和情感的前提下,词与词之间是独立的,也就是说p(g | d1, j, s) = p(g | d1, j) = 0。
所以,p(d1, s, g, j) = 0.6*0.33*0 = 0。
同理,p(d2, s, g, j) = 0.7*0.25*0.25 = 0.044。
所以,p(s, g, j) = 0 + 0.044 = 0.044。即,基于NB的回归模型会将test1对应的公众感到“joy”的概率值预测为0.044。


存在的问题:

(1)一个词概率为0就会得到全0结果

        解决方法:拉普拉斯平滑,将乘式中所有的0用一个很小的常数代替

(2)乘积过小

     下溢出解决方法:对乘积取自然对数,将相乘变为相加,计算完以后  加上一个数作补偿再做指数变换。

                     (这个方法更大的好处是,可以将计算过程转为非常简单的矩阵乘法)

    预测结果非常小解决方法:将所有结果进行归一化, 算出所有情感值之和,取每一个值除以总和的商。


二. 基于连续变量

   需要将连续变量离散化:

(1)使用相应的离散区间替换连续属性值。但是这种方法不方便控制离散区间划分的粒度。

(2)假设变量服从高斯分布,使用训练数据来估计分布的参数。

附上属性连续型代码,数据集格式为:第一行为58个属性名称,最后一个是分享值(0或1),接下来n行是训练数据集,再继续来m行是预测数据集,其share值为空。需要求出预测数据集的share预测值。

<span style="font-size:14px;">#include <bits/stdc++.h>
#define train_n 27751
#define test_n 11893
#define feature_n 58
#define pi acos(-1)
#define inf 1000000
using namespace std;
double MAX[60],MIN[60];
struct Continuous{	//连续型属性 
    double mean[2],var[2]; //m/v[i]是share=i的均值和方差 
}f[60];
typedef vector<double> feature;
vector <feature> text; //所有文本
vector <int> shares;   //测试文本的share值
double p[2];	// share=0/1概率 
int text_n = test_n+train_n; //所有文本个数 

void input()
{
	string line;
	double data;
	int n;
	ifstream fin("Datac_all.csv");
	getline(fin, line);
	for(int i=0;i<text_n;i++){ 
		getline(fin, line);
		istringstream ss(line);
		feature tmp;
		while (!ss.eof()){
			ss >> data;  //忽略逗号 
			ss.ignore(line.size(), ',');
			tmp.push_back(data);
		}
		text.push_back(tmp);
		if(i<train_n){
			shares.push_back(data);
		    if(data>0) n++;//计算share=1的个数 
		}
	}
	fin.close();
	p[1] = 1.0*n / train_n;
	p[0] = 1.0*(train_n-n) / train_n;
	cout << "The read is done\n";
}

void train_work()	//计算均值(mean)和方差(var) 
{
	for (int i=0; i<feature_n; i++)	//对每个属性 
	{
		for (int j=0; j<train_n; j++){
			int k = shares[j];
			f[i].mean[k] += text[j][i];
		}
		f[i].mean[1] /= train_n;	//share=1的均值 
		f[i].mean[0] /= train_n;	//share=0的均值 
		
		for (int j=0; j<train_n; j++){
			int k = shares[j];
			f[i].var[k] += (text[j][i]-f[i].mean[k])*(text[j][i]-f[i].mean[k]);
		}
		f[i].var[1] /= train_n;	//share=1的方差 
		f[i].var[0] /= train_n;	//share=0的方差 
	}
	cout << "The train is done\n";
}

double gauss_probability(int i, int j, int share)	//计算概率 
{
	double x = text[i][j];
	double m = f[j].mean[share];
	double v = f[j].var[share];
	return (exp(-(x-m)*(x-m)/(2*v)) / (sqrt(2*pi*v)));	//高斯分布 
}

void predict()	//进行预测 
{
	ofstream out("NB.txt");
	for (int i=train_n; i<text_n; i++){
		double share = p[1], not_share = p[0];
		for (int j=0; j<feature_n; j++){
			share *= gauss_probability(i, j, 1);
			not_share *= gauss_probability(i, j, 0);
		}
		out << (share>not_share) << endl;
	}
	cout << "The predict is done\n";
}

int main(){
	input();
	train_work();
	predict();	
	return 0;
}
</span>



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值