機器學習之樸素貝葉斯分類器

繼續我們的學習,今天我們記錄的是樸素貝葉斯分類器

什么是樸素貝葉斯

學過概率論的同學應該知道貝葉斯公式,就是那個全概率公式的逆形式,通過前驗概率來求后驗概率。


貝葉斯公式

我們這里只簡單的理解一下貝葉斯公式,因為這些基礎內容不是我們這篇文章重點介紹的內容

相比全概率公式是知道原因求結果概率,
貝葉斯公式是已知結果來求得原因概率

這是我們概率老師當時講的。

什么是樸素貝葉斯?樸素貝葉斯怎么分類?

舉個例子:

例子:
現在我們有5個訓練數據(2維特征向量),X = {x1, x2, x3, x4, x5},這五個數據分別屬于兩個類型Y,Y = {y1, y2}
現在,我隨便給你一個特征向量Xr,問你他屬于那個類別?
實際上,這個問題可以轉化為這樣的一個問題:

比較屬于那種類別的概率更大

那么前面我們用到的貝葉斯公式就排上了用場:
貝葉斯公式

根據貝葉斯公式以及鏈式法則,我們得到了這個公式,但是我們需要注意,這僅僅是二維的特征空間,就已經很難算了,如果維度達到三十維呢?

所以,樸素貝葉斯就被提出來了,其實樸素貝葉斯的naive不應該翻譯為樸素,還應該是“天真”(個人看法),為什么這么說呢?我們接著看這個例子:
因為上面的式子很難算,于是在20世紀50年代有人提出了這個假設(from wiki):

特征向量的各個特征獨立同分布

這意味著什么?


樸素貝葉斯

這樣就好算了很多,這個假設會使我們的分類模型損失一些精度,但是卻降低了特別多的計算難度。


接著,我們繼續計算這個條件概率:
首先,我們看分母,這是一個常數,對于比較概率大小沒有影響,所以將他忽略(不信可以全概率公式展開)。
然后,我們需要計算的就是:
p(y)先驗概率以及兩個條件概率,可能悟性好的朋友就已經知道了,這個可以通過訓練數據中的頻率來估計概率,這是沒錯的。
但是,這只有在數據樣本特別大的時候,才能這樣。那我們怎么做呢?

極大似然估計

這也是概率論里面的參數估計的方法,首先,我們先來理解一下什么是似然:

“似然性”與“或然性”或“概率”意思相近,都是指某種事件發生的可能性,但是在統計學中,“似然性”和“概率”(或然性)又有明確的區分。概率用于在已知一些參數的情況下,預測接下來的觀測所得到的結果,而似然性則是用于在已知某些觀測所得到的結果時,對有關事物的性質的參數進行估計。在這種意義上,似然函數可以理解為條件概率的逆反。在已知某個參數B時,事件A會發生的概率寫作:

似然

摘自wiki
我個人感覺:
這個似然函數的引入有些許tricky的味道,我現在對于他有兩種解釋:
1、頻率學派認為世界是確定的,有一個本體,這個本體的真值是不變的,我們的目標就是要找到這個真值或真值所在的范圍;所以對于一個未知的對象,我們要做的就是將他參數化,于是就將條件概率轉化為符合某種分布的聯合密度函數,我們要做的就是求解參數theta。
2、我們就是假設數據符合某種分布,就像中心極限定理說的一樣。然后這組數據的聯合條件密度分布就一定可以參數化,所以,我們就引入了極大似然的方法來估計參數值。
以上為個人看法,歡迎大家與我討論。

極大后驗估計

前面說到了頻率學派,當然不可避免的就得說到貝葉斯學派,極大后驗估計(MAP)是貝葉斯學派的參數估計方法。
在這里就不展開說了,如果想要深入了解,給大家推薦一篇文章,
這里

tricky

我想說一下,我在學習樸素貝葉斯過程中遇到的一些,感覺很tricky的地方。
我們先了解一下,極大似然估計的過程是什么樣的:
1、首先,假設數據成某一種分布,如果不確定可以根據中心極限定理,假設他為高斯分布。
2、然后,寫出他的似然函數,對于離散量,似然函數就是聯合分布函數,對于連續變量,似然函數就是聯合密度函數,然后根據不同的分布形式,會有不同的參數。
3、然后進行NLL優化,其實就是用對數函數將累乘變為累加,然后對參數求偏導等于零,然后就算出了參數值

但是我們再看一些文章時,包括sklearn的源碼,我們都可以發現一個地方,與我們所說的步驟不同,就是,他們都是直接算出了訓練數據集的均值以及方差,直接帶到了似然函數中,然后就直接比較了,得到了類別。

開始我十分納悶,為什么可以這樣?這和我們認知的不一樣,直到我動手推導了一下這個過程:

符合高斯分布的似然函數

NLL優化

注:這里使用e為底,是為了消去式子里的e方便計算,用2為底一樣
對mu求偏導等于零

我們可以發現,解得:mu就等于均值

對sigma求偏導等于零

很明顯,結果就是訓練數據集的方差

正是這樣,我們才可以將均值方差直接帶進去。
p(y)也是一個道理。

代碼實現:

import numpy as np
import math


class NaiveBayes:
    """
    a step to archieve my dream
    """
    def __init__(self, data_dim, data_num, class_num = 2):
        super(NaiveBayes, self).__init__()
        self.data_dim = data_dim
        self.data_num = data_num
        self.class_num = class_num
        self.data = self.data_make(data_dim, data_num)
        self.mean = np.zeros((class_num, data_dim)).reshape((class_num, data_dim))
        self.var = np.zeros((class_num, data_dim)).reshape((class_num, data_dim))
        self.p_y1 = 0
        self.p_y2 = 0

    def data_make(self, data_dim, data_num):
        """
        make train data
        :param data_dim: dimension of the feature
        :param data_num: the number of train data
        :return: a list of data whose type is dict
        """
        train_data = []
        for _ in range(data_num):

            tmp_data = {}
            tmp_data["data"] = np.random.randn(1, data_dim)
            if _ % 2 == 0:
                flag = -1
            else:
                flag = 1
            tmp_data["flag"] = flag

            train_data.append(tmp_data)
        return train_data

    def fit(self):
        """
        calculate the mean and var of the data
        :return: NULL
        """
        data_list_1 = [data["data"] for data in self.data if data["flag"] == 1]
        data_list_2 = [data["data"] for data in self.data if data["flag"] == -1]
        self.p_y1 = len(data_list_1)/self.data_num
        self.p_y2 = len(data_list_2)/self.data_num
        self.mean[0] = np.mean(data_list_1, axis=0, keepdims=True).reshape(self.data_dim)
        self.mean[1] = np.mean(data_list_2, axis=0, keepdims=True).reshape(self.data_dim)
        self.var[0] = np.std(data_list_1, axis=0, keepdims=True, ddof=1).reshape(self.data_dim)
        self.var[1] = np.std(data_list_1, axis=0, keepdims=True, ddof=1).reshape(self.data_dim)

    def predict(self, data):
        """
        to classify the data
        :param data: the data u wanna classify
        :return: int
        """
        p1 = (1/(pow(2*math.pi, 0.5)*self.var[0][0]))*pow(math.e, -(pow((data[0] - self.mean[0][0]), 2)/2*pow(self.var[0][0], 2)))*(1/(pow(2*math.pi, 0.5)*self.var[0][1]))*pow(math.e, -(pow((data[1] - self.mean[0][1]), 2)/2*pow(self.var[0][1], 2)))
        p2 = (1/(pow(2*math.pi, 0.5)*self.var[1][0]))*pow(math.e, -(pow((data[0] - self.mean[1][0]), 2)/2*pow(self.var[1][0], 2)))*(1/(pow(2*math.pi, 0.5)*self.var[1][1]))*pow(math.e, -(pow((data[1] - self.mean[1][1]), 2)/2*pow(self.var[1][1], 2)))


        print(p1,',',p2)

        if p2 > p1:
            print("[*]: the data belongs to the second class")
        else:
            print("[*]: the data belongs to the first class")

加油

更新

在與小伙伴討論完這塊的內容后,我對于極大似然估計有了新的理解,現在記錄一下:
前面我們說了似然概率既有相同之處,又有不同的地方,但具體表現在什么地方呢?

我們得從似然是什么重新說起:
我們先看一個例子:
我們現在拋一個瓶蓋,有正反兩種情況,但是由于瓶蓋密度不均勻,所以我們不知道正面的概率是多少,所以在這里我們假設正面的概率為theta,那么問題來了:
現在我拋了五次,出現了三次正面,兩次反面。所以,我問大家theta估計是多少?
那么,現在我們沒有別的辦法了,所以這里就用到了參數估計的方法:頻率學派的最大似然估計法。
似然就是一個事情發生的可能性,但是卻不同于概率,概率是告知的theta,但似然是不知道theta,要通過采樣來估計theta。
那么對于這個問題的似然函數是什么呢?


似然函數

在開始學習的時候,我有一個誤區,就是極大似然估計的似然函數必須是概率密度函數的乘積,正因為這個認識,讓我不知道似然函數的實際意義,所以理解不了為啥在這個特定的情景下要引入這個似然函數,但是實際上似然函數是什么呢?
似然其實就是特定事件發生的可能性,只不過我們假設他符合某種分布,然后將概率參數化,也就是化為與theta有關的函數,一個特定的theta對應一個事情發生的概率,就比如說上面的拋瓶蓋,根據采樣三正一反的樣本已經出現,所以我們要通過修正theta值來讓他的似然最大化,所以真正的,最正統的似然函數應該是概率公式,也就是上面的那個公式,但是為什么有的時候,我們看到的似然函數是聯合密度函數的形式呢?
是因為:在數學上可以證明,概率密度函數的乘積與概率的乘積是有相關性的,而我們的任務是求出使似然函數最大時的theta值,所以概率密度函數也可以用來表示似然函數。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,208評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,746評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,666評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,477評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,960評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,200評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,726評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,617評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,807評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,049評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,425評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,674評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,432評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,769評論 2 372

推薦閱讀更多精彩內容