樸素貝葉斯總結+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 ---------------------