机器学习--朴素贝叶斯

文章目录

    • 原理
      • 贝叶斯定理
      • 高斯朴素贝叶斯
    • 简单实现
    • sklearn的朴素贝叶斯

原理

设一个训练集为 { ( X 1 , y 1 ) , ( X 1 , y 2 ) . . . , ( X n , y n ) } \{(X_1, y_1), (X_1, y_2)...,(X_n, y_n)\} { (X1,y1),(X1,y2)...,(Xn,yn)}其中 X i ( i ∈ { 1 , 2 , . . . , n } ) X_i(i \in\{1,2,...,n\}) Xi(i{ 1,2,...,n})有m个特征,给出一个新的数据 X k X_k Xk,现在任务是要预测 X k X_k Xk的类别。
以前很多其它的算法都是根据预测数据的特征数值计算一个概率,然后选择概率最大的一个类别作为新的预测数据的类别,比如逻辑回归,我们选择的就是概率大于50%的那个类别。
用数学公式来描述就是要求这么一个式子
y k = arg max ⁡ c P ( y = c ∣ X = X k ) y_k=\argmax\limits_{c}P(y=c|X =X_k) yk=cargmaxP(y=cX=Xk)
其中c是X可以去到的类别,而 P ( y = c ∣ X = X k ) P(y=c|X =X_k) P(y=cX=Xk)就是后验概率,即在X已经确定的情况下求y等于某个类别的概率。我们知道能求出这个后验概率就能很轻松地解决上面的任务。

贝叶斯定理

贝叶斯定理告诉我们,假设一个概率空间 B B B分成若干个部分 B 1 , B 2 , . . . , B n B_1, B_2, ...,B_n B1,B2,...,Bn
那么对于随机事件 B i , D B_i,D Bi,D的后验概率 P ( B i ∣ D ) = P ( D ∣ B i ) P ( B i ) ∑ i = 1 n P ( D ∣ B i ) P ( B i ) P(B_i|D)=\frac{P(D|B_i)P(B_i)}{\sum\limits_{i = 1}^nP(D|B_i)P(B_i)} P(BiD)=i=1nP(DBi)P(Bi)P(DBi)P(Bi)
我们把这个式子带进去不就可以解决上述的任务了么?
把公式带入得到
P ( y = c , X = X k ) = P ( X = X k , y = c ) P ( y = c ) ∑ i = 1 w P ( X = X k ∣ y = c i ) P ( y = c i ) P(y = c, X=X_k)=\frac{P(X=X_k, y=c)P(y=c)}{\sum\limits_{i = 1}^wP(X = X_k|y=c_i)P(y=c_i)} P(y=c,X=Xk)=i=1wP(X=Xky=ci)P(y=ci)P(X=Xk,y=c)P(y=c)
其中w为X可能取到的类别的数目,即这里的概率空间是被各种不同的类别所划分的。
看样子似乎问题解决了,其实还没完,因为如果这么去算的话是很难计算的,也就是它的复杂度是不是一个多项式级别的。
首先看分母的计算,分母可以写成 P ( X 1 = X k 1 , X 2 = X k 2 . . . , X m = X k m ∣ y = c ) P ( y = c ) P(X^1=X_k^1, X^2=X_k^2..., X^m=X_k^m|y=c)P(y=c) P(X1=Xk1,X2=Xk2...,Xm=Xkmy=c)P(y=c)也就是每一个特征的值都要和要和要预测的数据的值相等,然后根据乘法公式,这个式子还可以写成 P ( X 1 = X k 1 , X 2 = X k 2 . . . , X m = X k m , y = c ) P(X^1=X_k^1, X^2=X_k^2..., X^m=X_k^m,y=c) P(X1=Xk1,X2=Xk2...,Xm=Xkm,y=c)即一个m + 1维度的联合分布的概率,假设每个变量的可取值有 u u u个,那么组合起来整个函数的参数可取值有 u m u^m um显然非常大,想要直接计算出这个联合分布是比较困难的。

所以朴素贝叶斯就做出了一个很强的假设,即:各个特征之间独立。
那么此时上式就会变成
p ( y = c ) ∏ i = 1 m P ( X i = X k i ∣ y = c ) p(y =c)\prod\limits_{i=1}^m P(X^i=X_k^i|y=c) p(y=c)i=1mP(Xi=Xkiy=c)
这样计算起来就很简单了,只需计算单独的每个特征的概率分布,然后把它们乘起来就可以了。

高斯朴素贝叶斯

我们可以先假设每个特征服从怎么怎么样的分布,然后使用极大似然估计来计算出概率密度函数。
现实中的变量大多都服从高斯分布,所以可以假设所有的特征都服从高斯分布然后进行估计。
高斯分布的概率密度函数是这样的:
f ( x ) = 1 2 π σ 2 e − ( μ − x ) 2 2 σ 2 f(x)=\frac{1}{\sqrt{2\pi\sigma^2}}e^{-\frac{(\mu-x)^2}{2\sigma^2}} f(x)=2πσ2 1e2σ2(μx)2
我们知道对于一个连续型的随机变量,其取单个值的概率为0,是没法用于估计的,但是我们可以近似的替代。
我们用 x x x x + ξ x+\xi x+ξ区间内的概率值代替 f ( x ) f(x) f(x),此时就有:
P ( x ) = ∫ x x + ξ f ( x ) d x P(x) = \int_{x}^{x + \xi}f(x)dx P(x)=xx+ξf(x)dx
ξ \xi ξ特别小时就可以用以下公式替代
P ( x ) = ∫ x x + ξ f ( x ) d x ≈ ξ ∗ f ( x ) P(x) = \int_{x}^{x + \xi}f(x)dx \approx\xi*f(x) P(x)=xx+ξf(x)dxξf(x)
我们把它带入后验概率公式,假设第 i i i个特征计算出来的概率密度为 f i ( x ) f_i(x) fi(x)那么就有
P ( y = c , X = X k ) = p ( y = c ) ∏ i = 1 m f i ( x ) ∗ ξ ∑ i = 1 w P ( X = X k ∣ y = c i ) P ( y = c i ) P(y = c, X=X_k)=\frac{p(y =c)\prod\limits_{i=1}^m f_i(x) * \xi}{\sum\limits_{i = 1}^wP(X = X_k|y=c_i)P(y=c_i)} P(y=c,X=Xk)=i=1wP(X=Xky=ci)P(y=ci)p(y=c)i=1mfi(x)ξ
注意到,分母其实就是 p ( X = X k ) p(X = X_k) p(X=Xk)所以上式其实就是
P ( y = c , X = X k ) = p ( y = c ) ∏ i = 1 m f i ( x ) ∗ ξ p ( X = X k ) P(y = c, X=X_k)=\frac{p(y =c)\prod\limits_{i=1}^m f_i(x) * \xi}{p(X = X_k)} P(y=c,X=Xk)=p(X=Xk)p(y=c)i=1mfi(x)ξ
由于 ξ \xi ξ是常量,所以把它提出。
P ( y = c , X = X k ) = ξ m p ( y = c ) ∏ i = 1 m f i ( x ) p ( X = X k ) P(y = c, X=X_k)=\frac{\xi^m p(y =c)\prod\limits_{i=1}^m f_i(x)}{p(X = X_k)} P(y=c,X=Xk)=p(X=Xk)ξmp(y=c)i=1mfi(x)
我们相求解的是在不同c的情况下的概率,所以与c无关的都应该是常量,所以可以把常量去除掉。
P ( y = c , X = X k ) = p ( y = c ) ∏ i = 1 m f i ( x ) P(y = c, X=X_k)=p(y =c)\prod\limits_{i=1}^m f_i(x) P(y=c,X=Xk)=p(y=c)i=1mfi(x)
于是就得到了最终的计算公式,对于P(y = c)可以通过统计样本中不同类别的占比数目得出,也可以直接指定。
比如男性与女性,我们很容易知道在没有条件约束时男性女性比例天然就是1 : 1

简单实现

class GaussianNaiveBayes:
    
    def __init__(self):
        self.means = None # 存放均值
        self.var = None # 存放方差
        self.Pc = None # 存放P(y = c)
        self.categories = None # 存放类别

    def fit(self, X, y):
        self.categories = list(set(y)) # 提取所有类别
        self.var, self.means, self.Pc = [], [], [] # 初始化
        for i in self.categories:
            tmp = X[y == i] 
            self.Pc.append(1 / tmp.shape[0]) # 统计得出所有先验概率
            self.means.append(np.mean(tmp, axis=0)) # 计算每个类别中的各个特征的均值
            self.var.append(np.var(tmp, axis=0))# 计算每个类别中的各个特征的方差
        self.X = X
        self.y = y
        
        return self

    def __single_predict(self, x):
        prob = []
        for i in range(len(self.categories)):
            P = np.log(self.Pc[i]) # 初始化P
            tmp = np.exp(-(x - self.means[i]) ** 2 / (2 * self.var[i] ** 2)
                                     / np.sqrt(2 * np.pi * self.var[i] ** 2)) # Guass函数
            P += np.sum(np.log(tmp) + self.p) # 使用取对数的方法转乘法为加法
            prob.append(P)
        return self.categories[np.argmax(np.array(prob))] # 取概率最大的一个类别
    
    def predict(self, X):
        return [self.__single_predict(x) for x in X]
    
    def score(self, X, y):
        return np.sum(self.predict(X) == y) / y.shape[0] # 计算ACC

sklearn的朴素贝叶斯

sklearn里可以从naive_bayes里倒入各种朴素贝叶斯,不同的朴素贝叶斯,差别之处就在于对特征的分布做出了不同的假设。

你可能感兴趣的:(机器学习)