1. 程式人生 > >樸素貝葉斯總結+kaggle例項

樸素貝葉斯總結+kaggle例項

原作者:bd-liuming  原文:https://blog.csdn.net/fisherming/article/details/79509025 

一. 樸素貝葉斯

      樸素貝葉斯中的樸素一詞的來源就是假設各特徵之間相互獨立。這一假設使得樸素貝葉斯演算法變得簡單,但有時會犧牲一定的分類準確率。

    首先給出貝葉斯公式:     換成分類任務的表示式:      我們最終求的p(類別|特徵)即可!就相當於完成了我們的任務。      則,樸素貝特斯公式為:

二. 例項解析 首先,給出資料如下:

現在給我們的問題是,如果一對男女朋友,男生想女生求婚,男生的四個特點分別是不帥,性格不好,身高矮,不上進,請你判斷一下女生是嫁還是不嫁?

這是典型的二分類問題,按照樸素貝葉斯的求解,轉換為P(嫁|不帥、性格不好、矮、不上進)和P(不嫁|不帥、性格不好、矮、不上進)的概率,最終選擇嫁與不嫁的答案。

這裡我們根據貝特斯公式:

由此,我們將(嫁|不帥、性格不好、矮、不上進)轉換成三個可求的P(嫁)、P(不帥、性格不好、矮、不上進|嫁)、P(不帥、性格不好、矮、不上進)。進一步分解可以得: P(不帥、性格不好、矮、不上進)=P(嫁)P(不帥|嫁)P(性格不好|嫁)P(矮|嫁)P(不上進|嫁)+P(不嫁)P(不帥|不嫁)P(性格不好|不嫁)P(矮|不嫁)P(不上進|不嫁)。 P(不帥、性格不好、矮、不上進|嫁)=P(不帥|嫁)P(性格不好|嫁)P(矮|嫁)P(不上進|嫁)

將上面的公式整理一下可得:

 P(嫁)=1/2、P(不帥|嫁)=1/2、P(性格不好|嫁)=1/6、P(矮|嫁)=1/6、P(不上進|嫁)=1/6。  P(不嫁)=1/2、P(不帥|不嫁)=1/3、P(性格不好|不嫁)=1/2、P(矮|不嫁)=1、P(不上進|不嫁)=2/3  但是由貝葉斯公式可得:對於目標求解為不同的類別,貝葉斯公式的分母總是相同的。所以,只求解分子即可:

於是,對於類別“嫁”的貝葉斯分子為:P(嫁)P(不帥|嫁)P(性格不好|嫁)P(矮|嫁)P(不上進|嫁)=1/2 * 1/2 * 1/6 * 1/6 * 1/6=1/864      對於類別“不嫁”的貝葉斯分子為:P(不嫁)P(不帥|不嫁)P(性格不好|不嫁)P(矮|不嫁)P(不上進|不嫁)=1/2 * 1/3 * 1/2 * 1* 2/3=1/18。 經代入貝葉斯公式可得:P(嫁|不帥、性格不好、矮、不上進)=(1/864) / (1/864+1/18)=1/49=2.04% P(不嫁|不帥、性格不好、矮、不上進)=(1/18) / (1/864+1/18)=48/49=97.96% 則P(不嫁|不帥、性格不好、矮、不上進) > P(嫁|不帥、性格不好、矮、不上進),則該女子選擇不嫁! 三. 樸素貝葉斯的優缺點

優點:   (1) 演算法邏輯簡單,易於實現(演算法思路很簡單,只要使用貝葉斯公式轉化即可!) (2)分類過程中時空開銷小(假設特徵相互獨立,只會涉及到二維儲存) 缺點:       樸素貝葉斯假設屬性之間相互獨立,這種假設在實際過程中往往是不成立的。在屬性之間相關性越大,分類誤差也就越大。 四. 樸素貝葉斯實戰

    sklearn中有3種不同型別的樸素貝葉斯:

高斯分佈型:用於classification問題,假定屬性/特徵服從正態分佈的。 多項式型:用於離散值模型裡。比如文字分類問題裡面我們提到過,我們不光看詞語是否在文字中出現,也得看出現次數。如果總詞數為n,出現詞數為m的話,有點像擲骰子n次出現m次這個詞的場景。 伯努利型:最後得到的特徵只有0(沒出現)和1(出現過)。   4.1  我們使用iris資料集進行分類 from sklearn.naive_bayes import GaussianNB from sklearn.model_selection import cross_val_score from sklearn import datasets iris = datasets.load_iris() gnb = GaussianNB() scores=cross_val_score(gnb, iris.data, iris.target, cv=10) print("Accuracy:%.3f"%scores.mean())     輸出: Accuracy:0.953     4.2 Kaggle比賽之“舊金山犯罪分類預測”

       題目資料:第一種獲取方式:Kaggle網站上;第二種獲取方式:百度網盤

        題目背景:『水深火熱』的大米國,在舊金山這個地方,一度犯罪率還挺高的,然後很多人都經歷過大到暴力案件,小到東西被偷,車被劃的事情。當地警方也是努力地去總結和想辦法降低犯罪率,一個挑戰是在給出犯罪的地點和時間的之後,要第一時間確定這可能是一個什麼樣的犯罪型別,以確定警力等等。後來乾脆一不做二不休,直接把12年內舊金山城內的犯罪報告都丟帶Kaggle上,說『大家折騰折騰吧,看看誰能幫忙第一時間預測一下犯罪型別』。犯罪報告裡面包括日期,描述,星期幾,所屬警區,處理結果,地址,GPS定位等資訊。當然,分類問題有很多分類器可以選擇,我們既然剛講過樸素貝葉斯,剛好就拿來練練手好了。

     (1) 首先我們來看一下資料

import pandas as pd   import numpy as np   from sklearn import preprocessing   from sklearn.metrics import log_loss   from sklearn.cross_validation import train_test_split train = pd.read_csv('/Users/liuming/projects/Python/ML資料/Kaggle舊金山犯罪型別分類/train.csv', parse_dates = ['Dates'])   test = pd.read_csv('/Users/liuming/projects/Python/ML資料/Kaggle舊金山犯罪型別分類/test.csv', parse_dates = ['Dates'])   train  

 我們依次解釋一下每一列的含義:

Date: 日期 Category: 犯罪型別,比如 Larceny/盜竊罪 等. Descript: 對於犯罪更詳細的描述 DayOfWeek: 星期幾 PdDistrict: 所屬警區 Resolution: 處理結果,比如說『逮捕』『逃了』 Address: 發生街區位置 X and Y: GPS座標         train.csv中的資料時間跨度為12年,包含了將近90w的記錄。另外,這部分資料,大家從上圖上也可以看出來,大部分都是『類別』型,比如犯罪型別,比如星期幾。

    (2)特徵預處理

       sklearn.preprocessing模組中的 LabelEncoder函式可以對類別做編號,我們用它對犯罪型別做編號;pandas中的get_dummies( )可以將變數進行二值化01向量,我們用它對”街區“、”星期幾“、”時間點“進行因子化。

#對犯罪類別:Category; 用LabelEncoder進行編號   leCrime = preprocessing.LabelEncoder()   crime = leCrime.fit_transform(train.Category)   #39種犯罪型別   #用get_dummies因子化星期幾、街區、小時等特徵   days=pd.get_dummies(train.DayOfWeek)   district = pd.get_dummies(train.PdDistrict)   hour = train.Dates.dt.hour   hour = pd.get_dummies(hour)   #組合特徵   trainData = pd.concat([hour, days, district], axis = 1)  #將特徵進行橫向組合   trainData['crime'] = crime   #追加'crime'列   days = pd.get_dummies(test.DayOfWeek)   district = pd.get_dummies(test.PdDistrict)   hour = test.Dates.dt.hour   hour = pd.get_dummies(hour)   testData = pd.concat([hour, days, district], axis=1)   trainData      特徵預處理後,訓練集feature,如下圖所示:

   (3) 建模

from sklearn.naive_bayes import BernoulliNB import time features=['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday', 'BAYVIEW', 'CENTRAL', 'INGLESIDE', 'MISSION',    'NORTHERN', 'PARK', 'RICHMOND', 'SOUTHERN', 'TARAVAL', 'TENDERLOIN']   X_train, X_test, y_train, y_test = train_test_split(trainData[features], trainData['crime'], train_size=0.6)   NB = BernoulliNB()   nbStart = time.time()   NB.fit(X_train, y_train)   nbCostTime = time.time() - nbStart   #print(X_test.shape)   propa = NB.predict_proba(X_test)   #X_test為263415*17; 那麼該行就是將263415分到39種犯罪型別中,每個樣本被分到每一種的概率   print("樸素貝葉斯建模%.2f秒"%(nbCostTime))   predicted = np.array(propa)   logLoss=log_loss(y_test, predicted)   print("樸素貝葉斯的log損失為:%.6f"%logLoss)   輸出: 樸素貝葉斯建模0.55秒 樸素貝葉斯的log損失為:2.582561 ---------------------