机器学习之贝叶斯分类器(C语言描述)

统计学习方法3

例如:第三章 贝叶斯分类器



前言

最近拜读了机器学习领域,经典书籍,李航老师的《统计学习方法》,深受裨益。现实现算法,记录分享。


一、贝叶斯分类器是什么?

贝叶斯分类器基于贝叶斯定理与特征条件独立假设的分类方法。对于给定的训练数据集,首先基于特征条件独立假设学习输入输出的联合概率分布模型,然后基于此模型,对于给定的输入 x x x,利用贝叶斯定理求出后验概率最大的输出 y y y,贝叶斯分类器实现简单,学习与预测的效率也很高。

二、贝叶斯分类器,数学原理分析

输入空间 X ⊆ R n X\subseteq R^n XRn 为 n 维向量集合,输出空间为类标记集合 Y = { c 1 , c 2 , . . . c k } Y = \{c_1, c_2, ...c_k\} Y={c1,c2,...ck}。输入为特征向量 x ⊊ X x\subsetneq X xX,输出 y ⊊ Y y\subsetneq Y yY P ( X , Y ) P(X, Y) P(X,Y) X , Y X, Y X,Y的联合概率分布。训练数据集: T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . ( x n , y n ) } T = \{(x_1, y_1), (x_2, y_2), ...(x_n, y_n)\} T={(x1,y1),(x2,y2),...(xn,yn)} P ( X , Y ) P(X, Y) P(X,Y) 独立分布产生。因有: P ( X , Y ) = P ( X ∣ Y ) P ( Y ) P(X,Y) = P(X|Y) P(Y) P(X,Y)=P(XY)P(Y)我们可以从训练集中得到先验概率分布 P ( Y ) P(Y) P(Y),以及条件概率分布 P ( X ∣ Y ) P(X|Y) P(XY)。这里补充一句,啥叫先验概率?就是数数,举个栗子: P ( Y = c k ) P(Y=c_k) P(Y=ck) 怎么求。那便是 C k / C C_k/C Ck/C,数一下第 k 种类别的数量占总数的比例便是 P ( Y = c k ) P(Y=c_k) P(Y=ck)。以前总被陌生的数学名词唬住,了解后也不过如此。接着便是求条件概率分布 P ( X ∣ Y ) P(X|Y) P(XY)。先验概率好求,但条件概率 : P ( X = x ∣ Y = c k ) = P ( X = x 1 , X = x 2 . . . X ( n ) = x ( n ) ∣ Y = c k ) P(X=x|Y=c_k)=P(X=x^1, X=x^2...X^{(n)}=x^{(n)} | Y=c_k) P(X=xY=ck)=P(X=x1,X=x2...X(n)=x(n)Y=ck) 有指数级别的参数。假设 x ( j ) x^{(j)} x(j) 取值有 S j S_j Sj 个,Y 的取值有 K 个,那么总共参数为: K ∏ j = 1 n S j K\prod_{j=1}^nS_j Kj=1nSj 。实在是臣妾办不到啊。

于是这里强作 了一个假设,假设特征向量 X 的各个分量的取值是独立的。也就是说 X ( 1 ) = a X^{(1)} =a X(1)=a X ( 2 ) = b X^{(2)} = b X(2)=b 概率上是独立的。于是有: P ( X = x ∣ Y = c k ) = P ( X ( 1 ) = x ( 1 ) , X ( 2 ) = x ( 2 ) . . . , X ( n ) = x ( n ) ∣ Y = c k ) = ∏ j = 1 n P ( X ( j ) = x ( j ) ∣ Y = c k ) P(X=x|Y=c_k) = P(X^{(1)}=x^{(1)}, X^{(2)}=x^{(2)}...,X^{(n)}=x^{(n)}|Y=c_k) \\=\prod_{j=1}^nP(X^{(j)} = x^{(j)}|Y=c_k) P(X=xY=ck)=P(X(1)=x(1),X(2)=x(2)...X(n)=x(n)Y=ck)=j=1nP(X(j)=x(j)Y=ck)得到这个公式后。我们要干嘛呢?绕来绕去,差点忘记要干啥了。

贝叶斯分类器的目的是给定输入的 x x x, 输出 y = c k y=c_k y=ck。那便是通过学习到的模型计算后验概率分布: P ( Y = c k ∣ X = x ) P(Y=c_k|X=x) P(Y=ckX=x)。根据联合概率与条件概率的公式有: P ( Y = c k ∣ X = x ) = P ( X , Y ) P ( X ) = P ( X = x ∣ Y = c k ) P ( Y = c k ) P ( X ) P(Y=c_k|X=x) = \frac {P(X, Y)}{P(X)}=\frac{P(X=x|Y=c_k)P(Y=c_k)}{P(X)} P(Y=ckX=x)=P(X)P(X,Y)=P(X)P(X=xY=ck)P(Y=ck)而根据边缘概率公式: P ( X ) = ∑ Y = c k P ( X , Y ) = ∑ Y = c k P ( X = x ∣ Y = c k ) P ( Y = c k ) P(X)=\sum_{Y=c_k} P(X, Y)=\sum_{Y=c_k}P(X=x|Y=c_k)P(Y=c_k) P(X)=Y=ckP(X,Y=Y=ckP(X=xY=ck)P(Y=ck)两者结合便有: P ( Y = c k ∣ X = x ) = P ( X = x ∣ Y = c k ) P ( Y = c k ) ∑ Y = c k P ( X = x ∣ Y = c k ) P ( Y = c k ) P(Y=c_k|X=x)=\frac{P(X=x|Y=c_k)P(Y=c_k)}{\sum_{Y=c_k}P(X=x|Y=c_k)P(Y=c_k)} P(Y=ckX=x)=Y=ckP(X=xY=ck)P(Y=ck)P(X=xY=ck)P(Y=ck)再加上前面所述条件独立假设后的条件概率分布,最终得到后验概率分布如下: P ( Y = c k ∣ X = x ) = P ( Y = c k ) ∏ j P ( X ( j ) = x ( j ) ∣ Y = c k ) ∑ k P ( Y = c k ) ∏ j P ( X ( j ) = x ( j ) ∣ Y = c k ) , k = 1 , 2 , 3... , K P(Y=c_k|X=x)=\frac{P(Y=c_k)\prod_{j}P( X^{(j)}=x^{(j)}|Y=c_k)}{\sum_kP(Y=c_k)\prod_jP(X^{(j)}=x^{(j)}|Y=c_k)}, k=1,2,3...,K P(Y=ckX=x)=kP(Y=ck)jP(X(j)=x(j)Y=ck)P(Y=ck)jP(X(j)=x(j)Y=ck),k=1,2,3...,K以上朴素贝叶斯法分类的基本公式,作为贝叶斯分类器可表示为: y = f ( x ) = a r g m a x c k P ( Y = c k ) ∏ j P ( X ( j ) = x ( j ) ∣ Y = c k ) ∑ k P ( Y = c k ) ∏ j P ( X ( j ) = x ( j ) ∣ Y = c k ) y=f(x)=argmax_{c_k}\frac{P(Y=c_k)\prod_{j}P( X^{(j)}=x^{(j)}|Y=c_k)}{\sum_kP(Y=c_k)\prod_jP(X^{(j)}=x^{(j)}|Y=c_k)} y=f(x)=argmaxckkP(Y=ck)jP(X(j)=x(j)Y=ck)P(Y=ck)jP(X(j)=x(j)Y=ck)由于下面那坨分母对于求每个 C k C_k Ck 的概率都是一样的,于是我们的朴素贝叶斯分类其最终可以简化为以下公式: y = f ( x ) = a r g m a x c k P ( Y = c k ) ∏ j P ( X ( j ) = x ( j ) ∣ Y = c k ) y=f(x)=argmax_{c_k}P(Y=c_k)\prod_{j}P( X^{(j)}=x^{(j)}|Y=c_k) y=f(x)=argmaxckP(Y=ck)jP(X(j)=x(j)Y=ck)

三、贝叶斯分类器,训练预测

那么,我们学习数据 T 时,训练出来的模型到底是什么呢?实际上其模型包含两部分:
1、 P ( Y = c k ) P(Y=c_k) P(Y=ck) ,计算出每个类别的概率。在代码实现中,使用一个 Hashmap 存储计算结果。其键值对为< c k , P r o b c_k, Prob ck,Prob>。
2、 ∏ j P ( X ( j ) = x ( j ) ∣ Y = c k ) \prod_{j}P( X^{(j)}=x^{(j)}|Y=c_k) jP(X(j)=x(j)Y=ck),计算出在 C k C_k Ck 类别的情况下,及每个特征向量的每一个分量 x j x_j xj取值 S j S_j Sj 的情况下的概率。在代码实现中,使用一个 Hashmap 存储结果。其键值对为<{ C k C_k Ck, S j Sj Sj}, P r o b Prob Prob>。
3、在计算得到以上两个结果后,按照公式 P ( Y = c k ) ∏ j P ( X ( j ) = x ( j ) ∣ Y = c k ) P(Y=c_k)\prod_{j}P( X^{(j)}=x^{(j)}|Y=c_k) P(Y=ck)jP(X(j)=x(j)Y=ck),计算每个类别得到的概率,取概率最大的类别作为预测结果。

四、上代码

以下是贝叶斯分类器伪代码

int bayes_classifier_train(matrix_t* data, matrix_t* labal, hashmap_t* Ck, hashmap_t* Ck_Si)
{
	// 将所有的类别去重。
	matrix_t* unique_ck = matrix_unique(label);
	// 得类别的数量
	int type_number = unique_ck->size;
	// 得到每个类别的数量
	int* ck_number = count_ck_number(labbel);
	// 计算每个类别的概率
	for (i : type_number)
	{
		// 将每个类别的数量除以总数,便是每个类别的概率。
		double prob = ck_number[i]/label->rows;
		Ck->push(unique[i], prob);
	}
	
	for (i : type_number){
		// 获取所有类别为 ck[i] 的数据
		matrix_t* data_cki = fatch_rows_of_ck(data, unique_ck[i]);
		for (j : data_cki->cols){
			// 截取每一列数据
			matrix_t* data_cki_col = matrix_slice_col(data_cki, j);
			// 去掉重复的值
			matrix_t* unique_si = matrix_unique(data_cki_col);
			// 统计有多少种数值
			int si_type_number = unique_si->size;
			// 统计每种数值的数量
			int* si_number = count_si_number(data_cki);
			for (k : si_type_number) {
				// 统计每种值的数量占的比例,即是概率
				double prob = si_number / data_cki_col->rows;
				// 保存下这个概率。
				Ck_Si->push({unique_ck[i], unique_si[k]}, prob);
			}
		}
	}
	
	return 0;
}

贝叶斯分类器,推理代码

int bayes_classifier_predict(matrix_t* _Input, hashmap_t* Ck, hashmap_t* Ck_Si)
{
	float probs[Ck->size];
	int   cks[Ck->size];
	for (i : Ck->size){
		int ck_type = Ck->keys[i];
		// 根据 Ck 类型获取其概率
		double prob = hashmap_get(Ck, ck_type);
		
		for (j : _Input-cols) {
			int si_type = _Input[j];
			// 连乘在当前类别 Ck 与 当前取值 Si 的情况下所统计的概率。
			prob *= hashmap_get({ck_type, si_type});
		}
		probs[i] = prob;
		cks[i]   = ck_type;
	}
	int max_prob_ck = get_max(probs, cks);
	return max_prob_ck;
}

源码https://github.com/zuweie/boring-code/blob/main/src/statistical_learning/naive_bayes.c


总结

朴素贝叶斯法是经典生成学习方法。生成方法由训练数据学习联合概率分布 P ( X , Y ) P(X, Y) P(X,Y), 然后求得后验概率分布 P ( Y ∣ X ) P(Y|X) P(YX)。这个也是挺简单的算法。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值