樸素貝葉斯算法及應用案例

2021-01-11 百度校園

作者:陳千鶴 來源:人工智慧學習圈

本篇主要介紹樸素貝葉斯算法及應用案例。

以Tatinic數據集為例進行應用,同時介紹數據處理,數據集的劃分,算法效果評估等內容。

一、簡介

樸素貝葉斯法是基於貝葉斯定理與特徵條件獨立假設的分類方法 。

和決策樹模型相比,樸素貝葉斯分類器(Naive Bayes Classifier 或 NBC)發源於古典數學理論,有著堅實的數學基礎,以及穩定的分類效率。同時,NBC模型所需估計的參數很少,對缺失數據不太敏感,算法也比較簡單。

樸素貝葉斯算法(Naive Bayesian algorithm) 是應用最為廣泛的分類算法之一。

也就是說沒有哪個屬性變量對於決策結果來說佔有著較大的比重,也沒有哪個屬性變量對於決策結果佔有著較小的比重。

雖然這個簡化方式在一定程度上降低了貝葉斯分類算法的分類效果,但是在實際的應用場景中,極大地簡化了貝葉斯方法的複雜性。

二、原理

設有樣本數據集D = {d~1~ ,d~2~,···,d~n~ },對應樣本集的特徵屬性集為X={x~1~,x~2~,···,x~d~},類變量為Y={y~1~,y~2~,···,y~m~},即D可以分成y~m~類別。其中x~1~,x~2~,···,x~d~相互隨機獨立,則Y的先驗概率P~prior~ = P(Y),Y的後驗概率P~post~ = P(Y|X),則由樸素貝葉斯算法可得,後驗概率可以由先驗概率P~prior~ = P(Y)、證據P(X)、類條件概率P(X|Y)計算出:

由於P(X)的大小是固定不變的,因此在比較後驗概率時,只比較上式的分子部分即可。

因此可以得到一個樣本數據屬於類別y~i~的樸素貝葉斯計算公式如下:

注意,一般只比較分子部分,這一點在後面會有一個在Titanic上應用的小討論

三、原理分析(實例)

這裡用一個實際案例來說明比較抽象的公式。

以瓜樹的案例來計算說明:

目標:對下例進行分類

計算過程:

那麼,我自己的理解就是:

先在訓練集中計算標籤為0和1的先驗概率,再分別計算每個特徵在標籤為0和1的條件概率。

預測過程中,將預測數據每個特徵在標籤為1時的條件概率之積與預測為1的概率直接相乘,記為P(1)

再將預測數據每個特徵在標籤為0時的條件概率之積與預測為0的概率直接相乘,記作P(0)

比較P(1)與P(0),哪個大就預測數據的標籤為0或1.

四、在Titanic數據集上的應用

1.數據集介紹

數據有如下特徵:

繼續觀察每個特徵下的具體情況:

我們會發現:

Age,Cabin,Embarked存在空值,需要進行處理

繼續看整體生存狀況

再綜合我們的常識可以得到結論:

女性的存活率高於男性Pclass1,2,3的生存率依次降低,這有可能與不同層的乘船人的社會地位,富裕程度有關年齡上來說,小孩先走,存活率較高Fare分布差異很大。Parch 代表同船的父母或子女,SipSp代表同船的兄弟姐妹,這都是兩個表現親人的關係,顯然這類因素會對存活率產生影響

那麼結合上面的分析的,可以做出如下處理:

對於不重要的特徵捨棄掉,簡化後面的計算,同時將SibSp和Parch兩項合併。

數據中很多為連續型和字符型數據,我們需要進行數值化,離散化處理。

年齡中位數28,缺失值補充為28。並且以25和31為界限分為三類sibsp&parch按照有無分為兩類生還共計342人。其中全體票價和生還票價均值均約為32。生還者票價高於32的126人死亡共計549人。其中票價低於32的464人 票價低於32共計680人,死亡率0.68票價低於64的共計773人,死亡512人 選擇以64為分界點

附上此部分分析代碼:

# 以下是最初的數據分析

# train_set, category = loadDataset('titanic.csv')

# print(category)

# print(train_set)

# k = [0, 0, 0, 0, 0, 0]

# min = train_set[0][3]

# max = 0

# age = []

# for data in train_set:

# for i in range(len(category)):

# if data[i] is None:

# k[i] += 1

# if data[3] is not None:

# if data[3] < min:

# min = data[3]

# if data[3] > max:

# max = data[3]

# age.append(data[3])

#

# age = sorted(age)

#

# print(category)

# print(k)

# print(min)

# print(max)

# print(age)

# print((len(train_set)-k[3])/2) #357

# print(age[int((len(train_set)-k[3])/2)]) # 28

# print(len(age)/3)

# print(age[297]) # 25

# print(age[297*2]) # 31

# for data in train_set:

# if data[3] is None:

# data[3] = 28

# print(train_set)

# s = 0

# for data in train_set:

# if data[-1] < 64:

# s += 1

#

# print(s)

# 以上是最初的數據分析

2.導入相關庫

import csvimport numpy as npimport matplotlib.pyplot as plt

3.讀入數據和數據處理

此部分函數實現以下內容:

讀入數據集

刪除分析中的不重要特徵

轉換數據格式為float

數據離散化:

性別以0,1區分 #此處其實更好的方法是one—hot處理,讀者可以自行研究年齡以25,31(60)為界限進行離散 #此處再優化分析時會在此說明sibsp和parcg加和後以2為界限,離散化fare以64為界限離散化

def loadDataset(filename):

with open(filename, 'r') as f:

lines = csv.reader(f)

data_set = list(lines)

if filename != 'titanic.csv':

for i in range(len(data_set)):

del(data_set[i][0])

# 整理數據

for i in range(len(data_set)):

del(data_set[i][0])

del(data_set[i][2])

data_set[i][4] += data_set[i][5]

del(data_set[i][5])

del(data_set[i][5])

del(data_set[i][6])

del(data_set[i][-1])

category = data_set[0]

del (data_set[0])

# 轉換數據格式

for data in data_set:

data[0] = int(data[0])

data[1] = int(data[1])

if data[3] != '':

data[3] = float(data[3])

else:

data[3] = None

data[4] = float(data[4])

data[5] = float(data[5])

# 補全缺失值 轉換記錄方式 分類

for data in data_set:

if data[3] is None:

data[3] = 28

# male : 1, female : 0

if data[2] == 'male':

data[2] = 1

else:

data[2] = 0

# age <25 為0, 25<=age<31為1,age>=31為2

if data[3] < 25:

data[3] = 0

elif data[3] >= 21 and data[3] < 60: # 但是測試得60分界準確率最高???!!!

data[3] = 1

else:

data[3] = 2

# sibsp&parcg以2為界限,小於為0,大於為1

if data[4] < 2:

data[4] = 0

else:

data[4] = 1

# fare以64為界限

if data[-1] < 64:

data[-1] = 0

else:

data[-1] = 1

return data_set, category

這一部分讀入數據要根據自己手中的數據來寫,無法直接應用

4.訓練集和測試集的劃分

常有hold-out,cross validation,bootstrapping法

hold—out

Hold-Out 是基本的劃分方法,字面意思就是「留出來一部分」,即將數據集直接按照一定比例劃分。

例如常用的 「2/8」 與 「3/7」,含義為訓練集 80% 或 70%,相應的測試集佔 20% 或 30%.

Hold-Out 的缺點較為明顯,即在驗證集上計算的出來的 最後評估指標與原始數據的順序有很大關係。

import randomimport csvimport pandas as pd

def loadDataset(filename, split, trainingSet = [], testSet = []):

with open(filename, 'r') as f:

lines = csv.reader(f)

dataset = list(lines)

for x in range(len(dataset)-1):

if random.random() < split: #將數據集隨機劃分

trainingSet.append(dataset[x])

else:

testSet.append(dataset[x])

if __name__ == "__main__":

train = []

test = []

loadDataset('', 0.7, train, test)

print(train)

print(test)

train2 = pd.DataFrame(data=train)

train2.to_csv('')

test2 = pd.DataFrame(data=test)

test2.to_csv('')

cross validation

簡單交叉驗證

將原始數據隨機分為兩組,一組做為訓練集,一組做為驗證集,利用訓練集訓練分類器,然後利用驗證集驗證模型,記錄最後的分類準確率為此分類器的性能指標。

好處:處理簡單,只需隨機把原始數據分為兩組即可

壞處:沒有達到交叉的思想,由於是隨機的將原始數據分組,所以最後驗證集分類準確率的高低與原始數據的分組有很大的關係,得到的結果並不具有說服性。

2-折交叉驗證(2-fold Cross Validation,記為2-CV)

做法是將數據集分成兩個相等大小的子集,進行兩次的分類器訓練。在第一次中,一個子集作為訓練集,另一個便作為測試集;在第二次訓練中,則將訓練集與測試集對換,

其並不常用:

主要原因是訓練集樣本數太少,不足以代表母體樣本的分布,導致te測試階段辨識率容易出現明顯落差。

K-折交叉驗證(K-fold Cross Validation,記為K-CV)

將原始數據分成K組(一般是均分),將每個子集數據分別做一次驗證集,其餘的K-1組子集數據作為訓練集,這樣會得到K個模型,用這K個模型最終的驗證集的分類準確率的平均數作為此K-CV下分類器的性能指標。K一般大於等於2,實際操作時一般從3開始取,只有在原始數據集合數據量小的時候才會嘗試取2。

應用最多,K-CV可以有效的避免過擬合與欠擬合的發生,最後得到的結果也比較具有說服性。

常見為十折交叉驗證

將數據集分成十份,輪流將其中9份作為訓練數據,1份作為測試數據,進行試驗。每次試驗都會得出相應的正確率。

10次的結果的正確率的平均值作為對算法精度的估計,一般還需要進行多次10折交叉驗證(例如10次10折交叉驗證),再求其均值,作為對算法準確性的估計

import csvimport pandas as pd

with open('titanic.csv', 'r') as f:

lines = csv.reader(f)

data_set = list(lines)del(data_set[0])length = len(data_set)//10print(length)data = []for i in range(10):

data.append(data_set[i*length:(i+1)*length])data.append(data_set[10*length:])

print(data_set)print(data)

bootstrapping(自助法)

最常用的一種Bootstrap自助法,假設給定的數據集包含d個樣本。該數據集有放回地抽樣m次,產生m個樣本的訓練集。這樣原數據樣本中的某些樣本很可能在該樣本集中出現多次。沒有進入該訓練集的樣本最終形成檢驗集(測試集)。 顯然每個樣本被選中的概率是1/m,因此未被選中的概率就是(1-1/m),這樣一個樣本在訓練集中沒出現的概率就是m次都未被選中的概率,即(1-1/m)^m^。當m趨於無窮大時,這一概率就將趨近於e^-1=0.368,所以留在訓練集中的樣本大概就佔原來數據集的63.2%。

例如:人工樣本為1,2,3;只有三個樣本,則可以從隨機變量X,分布為P(X=k)=1/3, k=1,2,3; 這樣的經驗分布中用計算機根據上述分布自動產生樣本,如產生5個樣本:1 2 3 2 1;也可以是:3 3 2 1 1

#自助法import numpy as np#任意設置一個數據集X = [1, 4, 3, 23, 4, 6, 7, 8, 9, 45, 67, 89, 34, 54, 76, 98, 43, 52]

#通過產生的隨機數獲得抽取樣本的序號bootstrapping = []for i in range(len(X)):

bootstrapping.append(np.floor(np.random.random()*len(X)))#通過序號獲得原始數據集中的數據D_1 = []for i in range(len(X)):

D_1.append(X[int(bootstrapping[i])])

5.樸素貝葉斯計算

這部分沒什麼好說的,按照公式計算就好

class NaiveBayes:

def __init__(self):

pass

def train(self, data):

length = len(data)

p = []

for i in range(len(data[0])):

p.append([])

# 計算先驗概率

sur = 0

for i in data:

if i[0] == 1:

sur += 1

death = length - sur

p1 = sur/length

p0 = 1 - p1

p[0].append(p1)

p[0].append(p0)

print(p)

# 計算pclass的條件概率

a1 = 0

a0 = 0

b1 = 0

b0 = 0

c1 = 0

c0 = 0

for i in data:

if i[0] == 1 and i[1] == 1:

a1 += 1

elif i[0] == 0 and i[1] == 1:

a0 += 1

elif i[0] == 1 and i[1] == 2:

b1 += 1

elif i[0] == 0 and i[1] == 2:

b0 += 1

elif i[0] == 1 and i[1] == 3:

c1 += 1

elif i[0] == 0 and i[1] == 3:

c0 += 1

p[1].append(a1 / sur)

p[1].append(a0 / death)

p[1].append(b1 / sur)

p[1].append(b0 / death)

p[1].append(c1 / sur)

p[1].append(c0 / death)

# 計算sex的條件概率

m1 = 0

m0 = 0

f1 = 0

f0 = 0

for i in data:

if i[0] == 1 and i[2] == 1:

m1 += 1

elif i[0] == 0 and i[2] == 1:

m0 += 1

elif i[0] == 1 and i[2] == 0:

f1 += 1

elif i[0] == 0 and i[2] == 0:

f0 += 1

p[2].append(m1 / sur)

p[2].append(m0 / death)

p[2].append(f1 / sur)

p[2].append(f0 / death)

# 計算age的條件概率

a1 = 0

a0 = 0

b1 = 0

b0 = 0

c1 = 0

c0 = 0

for i in data:

if i[0] == 1 and i[3] == 1:

a1 += 1

elif i[0] == 0 and i[3] == 1:

a0 += 1

elif i[0] == 1 and i[3] == 2:

b1 += 1

elif i[0] == 0 and i[3] == 2:

b0 += 1

elif i[0] == 1 and i[3] == 3:

c1 += 1

elif i[0] == 0 and i[3] == 3:

c0 += 1

p[3].append(a1 / sur)

p[3].append(a0 / death)

p[3].append(b1 / sur)

p[3].append(b0 / death)

p[3].append(c1 / sur)

p[3].append(c0 / death)

# 計算sibsp&parch條件概率

m1 = 0

m0 = 0

f1 = 0

f0 = 0

for i in data:

if i[0] == 1 and i[4] == 1:

m1 += 1

elif i[0] == 0 and i[4] == 1:

m0 += 1

elif i[0] == 1 and i[4] == 0:

f1 += 1

elif i[0] == 0 and i[4] == 0:

f0 += 1

p[4].append(m1 / sur)

p[4].append(m0 / death)

p[4].append(f1 / sur)

p[4].append(f0 / death)

m1 = 0

m0 = 0

f1 = 0

f0 = 0

for i in data:

if i[0] == 1 and i[5] == 1:

m1 += 1

elif i[0] == 0 and i[5] == 1:

m0 += 1

elif i[0] == 1 and i[5] == 0:

f1 += 1

elif i[0] == 0 and i[5] == 0:

f0 += 1

p[5].append(m1 / sur)

p[5].append(m0 / death)

p[5].append(f1 / sur)

p[5].append(f0 / death)

return p

def predict(self, t_data, p):

result = []

pp = []

for data in t_data:

p1 = p[0][0]

p0 = p[0][1]

# pclass

if data[1] == 1:

p1 *= p[1][0]

p0 *= p[1][1]

elif data[1] == 2:

p1 *= p[1][2]

p0 *= p[1][3]

elif data[1] == 3:

p1 *= p[1][4]

p0 *= p[1][5]

# sex

if data[2] == 1:

p1 *= p[2][0]

p0 *= p[2][1]

else:

p1 *= p[2][2]

p0 *= p[2][3]

# age

if data[3] == 0:

p1 *= p[3][0]

p0 *= p[3][1]

elif data[3] == 1:

p1 *= p[3][2]

p0 *= p[3][3]

else:

p1 *= p[3][4]

p0 *= p[3][5]

#sibsp&parch

if data[4] == 1:

p1 *= p[4][0]

p0 *= p[4][1]

else:

p1 *= p[4][2]

p0 *= p[4][3]

# fare

if data[5] == 1:

p1 *= p[5][0]

p0 *= p[5][1]

else:

p1 *= p[5][2]

p0 *= p[5][3]

pp.append(p1)

if p1 >= p0:

result.append(1)

else:

result.append(0)

return pp, result

6.模型評估1

此處評估標準選取ROC_AUC

先給出混淆矩陣:

ROC 圖像:

縱軸為 TPR 真正例率,預測為正且實際為正的樣本佔所有正例樣本的比例。

橫軸為 FPR 假正例率,預測為正但實際為負的樣本佔所有負例樣本的比例。

ROC圖像分析

第一個點,(0,1),即 FPR=0, TPR=1,這意味著 FN(false negative)=0,並且FP(false positive)=0。這意味著分類器很完美,因為它將所有的樣本都正確分類。

第二個點,(1,0),即 FPR=1,TPR=0,這個分類器是最糟糕的,因為它成功避開了所有的正確答案。

第三個點,(0,0),即 FPR=TPR=0,即 FP(false positive)=TP(true positive)=0,此時分類器將所有的樣本都預測為負樣本(negative)。

第四個點(1,1),分類器將所有的樣本都預測為正樣本。

對角線上的點表示分類器將一半的樣本猜測為正樣本,另外一半的樣本猜測為負樣本。

因此,ROC 曲線越接近左上角,分類器的性能越好。

怎麼畫ROC曲線

按 Score 從大到小排列

依次將每個 Score 設定為閾值,然後這 20 個樣本的標籤會變化,當它的 score 大於或等於當前閾值時,則為正樣本,否則為負樣本。

這樣對每個閾值,可以計算一組 FPR 和 TPR,此例一共可以得到 20 組。

當閾值設置為 1 和 0 時, 可以得到 ROC 曲線上的 (0,0) 和 (1,1) 兩個點。

怎麼計算AUC

def roc_auc(p, test, result):

tp = 0

tn = 0

for i in test:

if i[0] == 1:

tp += 1

else:

tn += 1

for i in range(len(test)):

test[i] = test[i][0]

p[i] = [p[i]]

p[i].append(test[i])

p[i].append(result[i])

p = sorted(p, reverse=True)

print(p)

tpr = [0]

fpr = [0]

length = len(p)

for i in range(1, length):

if p[i][1] == 1:

fpr.append(fpr[i-1])

tpr.append(tpr[i-1]+1/tp)

elif p[i][1] == 0:

fpr.append(fpr[i-1]+1/tn)

tpr.append(tpr[i-1])

tpr.append(1)

fpr.append(1)

print(fpr)

print(tpr)

auc = 0

for i in range(len(fpr)-1):

auc += (fpr[i+1]-fpr[i])*(tpr[i]+tpr[i+1])

auc = auc/2

print(auc)

fpr = np.array(fpr)

tpr = np.array(tpr)

plt.title("ROC curve of %s (AUC = %.4f)" % ('svm', auc))

plt.xlabel("False Positive Rate")

plt.ylabel("True Positive Rate")

plt.plot(fpr, tpr)

plt.show()

7.模型評估2——F1_score

tp = 0

tn = 0

for i in range(len(result)):

if test[i][0] == result[i] == 1:

tp += 1

if test[i][0] == result[i] == 0:

tn += 1

print(tp)

print(tn)

f1 = (2*tp)/(len(test)+tp-tn)

print(f1)

roc_auc(pp, test, result)

8.評估結果

準確率:74.5%

F1 : 0.678

9.完整代碼

import csvimport numpy as npimport matplotlib.pyplot as plt

# 0PassengerId:乘客的ID 不重要# 1Survived:乘客是否獲救,Key:0=沒獲救,1=已獲救# 2Pclass:乘客船艙等級(1/2/3三個等級艙位)# 3Name:乘客姓名 不重要# 4Sex:性別# 5Age:年齡# 6SibSp:乘客在船上的兄弟姐妹/配偶數量# 7Parch:乘客在船上的父母/孩子數量# 8Ticket:船票號 不重要# 9Fare:船票價# 10Cabin:客艙號碼 不重要# 11Embarked:登船的港口 不重要

# 數據分析得: 年齡中位數28,缺失值補充為28。並且以25和31為界限分為三類# sibsp&parch按照有無分為兩類# 生還共計342人。其中全體票價和生還票價均值均約為32。# 生還者票價高於32的126人# 死亡共計549人。其中票價低於32的464人# 票價低於32共計680人,死亡率0.68# 票價低於64的共計773人,死亡512人 選擇以64為分界點

def loadDataset(filename):

with open(filename, 'r') as f:

lines = csv.reader(f)

data_set = list(lines)

if filename != 'titanic.csv':

for i in range(len(data_set)):

del(data_set[i][0])

# 整理數據

for i in range(len(data_set)):

del(data_set[i][0])

del(data_set[i][2])

data_set[i][4] += data_set[i][5]

del(data_set[i][5])

del(data_set[i][5])

del(data_set[i][6])

del(data_set[i][-1])

category = data_set[0]

del (data_set[0])

# 轉換數據格式

for data in data_set:

data[0] = int(data[0])

data[1] = int(data[1])

if data[3] != '':

data[3] = float(data[3])

else:

data[3] = None

data[4] = float(data[4])

data[5] = float(data[5])

# 補全缺失值 轉換記錄方式 分類

for data in data_set:

if data[3] is None:

data[3] = 28

# male : 1, female : 0

if data[2] == 'male':

data[2] = 1

else:

data[2] = 0

# age <25 為0, 25<=age<31為1,age>=31為2

if data[3] < 25:

data[3] = 0

elif data[3] >= 21 and data[3] < 60: # 但是測試得60分界準確率最高???!!!

data[3] = 1

else:

data[3] = 2

# sibsp&parcg以2為界限,小於為0,大於為1

if data[4] < 2:

data[4] = 0

else:

data[4] = 1

# fare以64為界限

if data[-1] < 64:

data[-1] = 0

else:

data[-1] = 1

return data_set, category

class NaiveBayes:

def __init__(self):

pass

def train(self, data):

length = len(data)

p = []

for i in range(len(data[0])):

p.append([])

# 計算先驗概率

sur = 0

for i in data:

if i[0] == 1:

sur += 1

death = length - sur

p1 = sur/length

p0 = 1 - p1

p[0].append(p1)

p[0].append(p0)

print(p)

# 計算pclass的條件概率

a1 = 0

a0 = 0

b1 = 0

b0 = 0

c1 = 0

c0 = 0

for i in data:

if i[0] == 1 and i[1] == 1:

a1 += 1

elif i[0] == 0 and i[1] == 1:

a0 += 1

elif i[0] == 1 and i[1] == 2:

b1 += 1

elif i[0] == 0 and i[1] == 2:

b0 += 1

elif i[0] == 1 and i[1] == 3:

c1 += 1

elif i[0] == 0 and i[1] == 3:

c0 += 1

p[1].append(a1 / sur)

p[1].append(a0 / death)

p[1].append(b1 / sur)

p[1].append(b0 / death)

p[1].append(c1 / sur)

p[1].append(c0 / death)

# 計算sex的條件概率

m1 = 0

m0 = 0

f1 = 0

f0 = 0

for i in data:

if i[0] == 1 and i[2] == 1:

m1 += 1

elif i[0] == 0 and i[2] == 1:

m0 += 1

elif i[0] == 1 and i[2] == 0:

f1 += 1

elif i[0] == 0 and i[2] == 0:

f0 += 1

p[2].append(m1 / sur)

p[2].append(m0 / death)

p[2].append(f1 / sur)

p[2].append(f0 / death)

# 計算age的條件概率

a1 = 0

a0 = 0

b1 = 0

b0 = 0

c1 = 0

c0 = 0

for i in data:

if i[0] == 1 and i[3] == 1:

a1 += 1

elif i[0] == 0 and i[3] == 1:

a0 += 1

elif i[0] == 1 and i[3] == 2:

b1 += 1

elif i[0] == 0 and i[3] == 2:

b0 += 1

elif i[0] == 1 and i[3] == 3:

c1 += 1

elif i[0] == 0 and i[3] == 3:

c0 += 1

p[3].append(a1 / sur)

p[3].append(a0 / death)

p[3].append(b1 / sur)

p[3].append(b0 / death)

p[3].append(c1 / sur)

p[3].append(c0 / death)

# 計算sibsp&parch條件概率

m1 = 0

m0 = 0

f1 = 0

f0 = 0

for i in data:

if i[0] == 1 and i[4] == 1:

m1 += 1

elif i[0] == 0 and i[4] == 1:

m0 += 1

elif i[0] == 1 and i[4] == 0:

f1 += 1

elif i[0] == 0 and i[4] == 0:

f0 += 1

p[4].append(m1 / sur)

p[4].append(m0 / death)

p[4].append(f1 / sur)

p[4].append(f0 / death)

m1 = 0

m0 = 0

f1 = 0

f0 = 0

for i in data:

if i[0] == 1 and i[5] == 1:

m1 += 1

elif i[0] == 0 and i[5] == 1:

m0 += 1

elif i[0] == 1 and i[5] == 0:

f1 += 1

elif i[0] == 0 and i[5] == 0:

f0 += 1

p[5].append(m1 / sur)

p[5].append(m0 / death)

p[5].append(f1 / sur)

p[5].append(f0 / death)

return p

def predict(self, t_data, p):

result = []

pp = []

for data in t_data:

p1 = p[0][0]

p0 = p[0][1]

# pclass

if data[1] == 1:

p1 *= p[1][0]

p0 *= p[1][1]

elif data[1] == 2:

p1 *= p[1][2]

p0 *= p[1][3]

elif data[1] == 3:

p1 *= p[1][4]

p0 *= p[1][5]

# sex

if data[2] == 1:

p1 *= p[2][0]

p0 *= p[2][1]

else:

p1 *= p[2][2]

p0 *= p[2][3]

# age

if data[3] == 0:

p1 *= p[3][0]

p0 *= p[3][1]

elif data[3] == 1:

p1 *= p[3][2]

p0 *= p[3][3]

else:

p1 *= p[3][4]

p0 *= p[3][5]

#sibsp&parch

if data[4] == 1:

p1 *= p[4][0]

p0 *= p[4][1]

else:

p1 *= p[4][2]

p0 *= p[4][3]

# fare

if data[5] == 1:

p1 *= p[5][0]

p0 *= p[5][1]

else:

p1 *= p[5][2]

p0 *= p[5][3]

pp.append(p1)

if p1 >= p0:

result.append(1)

else:

result.append(0)

return pp, result

def roc_auc(p, test, result):

tp = 0

tn = 0

for i in test:

if i[0] == 1:

tp += 1

else:

tn += 1

for i in range(len(test)):

test[i] = test[i][0]

p[i] = [p[i]]

p[i].append(test[i])

p[i].append(result[i])

p = sorted(p, reverse=True)

print(p)

tpr = [0]

fpr = [0]

length = len(p)

for i in range(1, length):

if p[i][1] == 1:

fpr.append(fpr[i-1])

tpr.append(tpr[i-1]+1/tp)

elif p[i][1] == 0:

fpr.append(fpr[i-1]+1/tn)

tpr.append(tpr[i-1])

tpr.append(1)

fpr.append(1)

print(fpr)

print(tpr)

auc = 0

for i in range(len(fpr)-1):

auc += (fpr[i+1]-fpr[i])*(tpr[i]+tpr[i+1])

auc = auc/2

print(auc)

fpr = np.array(fpr)

tpr = np.array(tpr)

plt.title("ROC curve of %s (AUC = %.4f)" % ('svm', auc))

plt.xlabel("False Positive Rate")

plt.ylabel("True Positive Rate")

plt.plot(fpr, tpr)

plt.show()

if __name__ == "__main__":

# 以下是最初的數據分析

# train_set, category = loadDataset('titanic.csv')

# print(category)

# print(train_set)

# k = [0, 0, 0, 0, 0, 0]

# min = train_set[0][3]

# max = 0

# age = []

# for data in train_set:

# for i in range(len(category)):

# if data[i] is None:

# k[i] += 1

# if data[3] is not None:

# if data[3] < min:

# min = data[3]

# if data[3] > max:

# max = data[3]

# age.append(data[3])

#

# age = sorted(age)

#

# print(category)

# print(k)

# print(min)

# print(max)

# print(age)

# print((len(train_set)-k[3])/2) #357

# print(age[int((len(train_set)-k[3])/2)]) # 28

# print(len(age)/3)

# print(age[297]) # 25

# print(age[297*2]) # 31

# for data in train_set:

# if data[3] is None:

# data[3] = 28

# print(train_set)

# s = 0

# for data in train_set:

# if data[-1] < 64:

# s += 1

#

# print(s)

# 以上是最初的數據分析

train_set, category = loadDataset('titanic_train.csv')

test_set, category = loadDataset('titanic_test.csv')

print(category)

print(train_set)

bayes = NaiveBayes()

p = bayes.train(train_set)

print(p)

pp, result = bayes.predict(test_set, p)

print(result)

count = 0

for i in range(len(result)):

if test_set[i][0] == result[i]:

count += 1

accuracy = count/len(test_set)

print(accuracy)

# # 十折交叉驗證

# data_set, category = loadDataset('titanic.csv')

#

# length = len(data_set) // 10

# print(length)

# data = []

# for i in range(10):

# data.append(data_set[i * length:(i + 1) * length])

# data.append(data_set[10 * length:])

#

# sum = 0

#

# for i in range(9):

# p = bayes.train(data[i])

# print(p)

#

# pp, result = bayes.predict(data[9], p)

# print(result)

# count = 0

# for i in range(len(result)):

# if test_set[i][0] == result[i]:

# count += 1

# sum += count/len(data[9])

#

# print(sum/10)

# 自助法

data_set, category = loadDataset('titanic.csv')

bootstrapping = []

for i in range(len(data_set)):

bootstrapping.append(np.floor(np.random.random()*len(data_set)))

test = []

for i in range(len(data_set)):

test.append(data_set[int(bootstrapping[i])])

p = bayes.train(data_set)

print(p)

pp, result = bayes.predict(test, p)

print(result)

count = 0

for i in range(len(result)):

if test[i][0] == result[i]:

count += 1

accuracy = count / len(test)

print(accuracy)

#基於自助法計算F1-score

tp = 0

tn = 0

for i in range(len(result)):

if test[i][0] == result[i] == 1:

tp += 1

if test[i][0] == result[i] == 0:

tn += 1

print(tp)

print(tn)

f1 = (2*tp)/(len(test)+tp-tn)

print(f1)

roc_auc(pp, test, result)

五、模型優化與提升

性別數值化更好的方法是one—hot處理

年齡離散化的標準。後續再測試的過程中發現,年齡的離散化標準對模型的準確率影響極大,這一點可以在探索後進行優化進而提升模型效果

對於貝葉斯的概率計算時,原方法是只計算分子進行比較。但是我們可以換一種方法,計算完整的概率值,然後與0.5進行比較,然後分類。這種方法再結合更加合適的年齡劃分標準可以是本地的準確率達到90%以上,在kaggle上也可以達到80%以上

這幾種優化思路提供給讀者自行探索嘗試。

相關焦點

  • 聚類算法簡析(一):樸素貝葉斯算法的場景案例
    本文作者通過一些場景案例,帶領大家了解一下樸素貝葉斯算法作為聚類算法中的一員,如何來區分各類數組。通過一組參數模型來區分互斥群組中的個體十分常見,我們可以使用樸素貝葉斯分析來應用於這種場景,取決於模型的相似矩陣算法常常運用在估算決策論框架的矩陣中。
  • 樸素貝葉斯算法及其應用
    在這篇文章中,我們將嘗試以簡單的方式理解什麼是樸素貝葉斯,它是如何工作的以及我們如何應用樸素貝葉斯分類器將文本或評論分類為「肯定」或「否定」,我們將通過電影評論案例進行研究。什麼是樸素貝葉斯?貝葉斯定理是由Reverend Bayes開發的最早的概率推理算法之一(他過去常常嘗試推斷上帝的存在)並且對於某些用例仍然表現得非常好。
  • 機器學習算法之樸素貝葉斯
    一、貝葉斯定理貝葉斯定理由英國數學家貝葉斯(Thomas Bayes 1702-1761)發展用來描述兩個條件概率之間的關係在B條件下A發生的概率: P(A∣B)=P(AB)/P(B)在A條件下B發生的概率: P(B∣A)=P(AB)/P
  • 基於貝葉斯定理的算法——樸素貝葉斯分類
    不過今天我們介紹的樸素貝葉斯分類器通過獨立假設簡化了概率的計算,節省了內存,可以很好地用於數據量大的情況。下面我們首先來了解這一算法的數理背景——貝葉斯定理。這一算法是由我們在概率論中學到的貝葉斯定理延伸出來的。我們知道貝葉斯公式為:其中,
  • 樸素貝葉斯與文本分類
    樸素貝葉斯 (Naive Bayesian algorithm) 是一種基於概率統計的分類方法,主要用到了貝葉斯定理和特徵條件獨立性假設。樸素貝葉斯具有悠久的歷史,其算法邏輯比較簡單,有健壯的性能,通常可以用於文本分類、信用評估等方面。
  • 為什麼樸素貝葉斯定理會被叫做樸素的?
    樸素貝葉斯算法是一種基於著名貝葉斯定理的分類算法。那麼讓我們先了解一下Bayes定理是怎麼說的,並為樸素貝葉斯算法定理建立自己的理解,它是如何工作的,它為什麼被稱作樸素的?貝葉斯定理在深入研究貝葉斯定理之前,我們需要了解一些術語-獨立事件和從屬事件邊際概率聯合概率條件概率獨立事件和從屬事件考慮兩個事件A和B。
  • 科普丨樸素貝葉斯了解一下
    樸素貝葉斯用貝葉斯定理來預測結果值,該值同時依賴於多個要素,因此必須遵循上述假設。這就是為什麼它被稱為樸素!01樸素貝葉斯的實際應用在幾乎所有的現實世界中,大多數特徵都是相互依賴的。這將使樸素貝葉斯在現實生活中幾乎不可能實現。那麼它在哪裡使用呢?
  • 樸素貝葉斯實戰篇之新浪新聞分類
    這樣,我們的樸素貝葉斯分類器就改進完畢了。三、樸素貝葉斯之過濾垃圾郵件在上篇文章那個簡單的例子中,我們引入了字符串列表。使用樸素貝葉斯解決一些現實生活中的問題時,需要先從文本內容得到字符串列表,然後生成詞向量。下面這個例子中,我們將了解樸素貝葉斯的一個最著名的應用:電子郵件垃圾過濾。
  • 樸素貝葉斯(Naive Bayes)和校正曲線(Calibration Curve)
    算法回顧圖片來源:medium.com貝葉斯分類算法屬於有監督機器學習(Supervised Learning)。貝葉斯分類器是一類分類算法的總稱,這類算法均以貝葉斯定理為基礎,故統稱為貝葉斯分類。其中樸素貝葉斯分分類是貝葉斯分類中最簡單的,也是最常見的一種分類方法。樸素貝葉斯分類算法的核心如下公式:P(A):它是先驗(Prior Probability),是A發生的概率。P(B): 是邊際可能性(Marginal Likelihood):是B發生的概率。
  • python實現高斯樸素貝葉斯分類器
    python實現高斯樸素貝葉斯分類器    在這篇文章中,我們將使用我最喜歡的機器學習庫scikit-learn在Python中實現樸素貝葉斯分類器。接下來,我們將使用經過訓練的樸素貝葉斯(監督分類法)模型來預測人口收入。
  • 解讀實踐中最廣泛應用的分類模型:樸素貝葉斯算法
    貝葉斯模型在機器學習以及人工智慧中都有出現,cherry 分類器使用了樸素貝葉斯模型算法,經過簡單的優化,使用 1000 個訓練數據就能得到 97.5% 的準確率。雖然現在主流的框架都帶有樸素貝葉斯模型算法,大多數開發者只需要直接調用 api 就能使用。但是在實際業務中,面對不同的數據集,必須了解算法的原理,實現以及懂得對結果進行分析,才能達到高準確率。
  • 樸素貝葉斯:幫助AI產品經理「小步快跑,快速迭代」
    貝葉斯定理得以廣泛應用是因為它符合人類認知事物的自然規律。我們並非生下來就知道一切事情的內在的規律,大多數時候,我們面對的是信息不充分、不確定的情況。這個時候我們只能在有限資源的情況下,作出決定,再根據後續的發展進行修正。一、樸素貝葉斯登場貝葉斯分類是一類分類算法的總稱,這類算法均以「貝葉斯定理」為基礎,以「特徵條件獨立假設」為前提。
  • 樸素貝葉斯詳解及中文輿情分析(附代碼實踐)
    作者|楊秀璋  整理|AI科技大本營本文主要講述樸素貝葉斯分類算法並實現中文數據集的輿情分析案例,希望這篇文章對大家有所幫助,提供些思路
  • ...詳解線性回歸、樸素貝葉斯、隨機森林在R和Python中的實現應用...
    、邏輯回歸、樸素貝葉斯(Naive Bayes)、kNN、隨即森林,等等。樸素貝葉斯(Naive Bayes)6. K最近鄰(kNN)7. K均值算法(K-Means)8. 隨機森林(Random Forest)9. 降維算法(Dimensionality Reduction Algorithms)10.
  • 樸素貝葉斯分類器詳解及中文文本輿情分析(附代碼實踐)
    本文主要講述樸素貝葉斯分類算法並實現中文數據集的輿情分析案例,希望這篇文章對大家有所幫助,提供些思路。
  • 基於人工智慧的貝葉斯分類算法
    基於人工智慧的貝葉斯分類算法  貝爾斯算法的應用:  1.百度實時路況  2.騰訊新聞分類  3.數據清洗:數據補全  4.數據歸類  5.垃圾郵箱  什麼是貝爾斯算法  貝爾斯算法就是貝葉斯所研究的逆向概率: 給出一個條件
  • 詳解線性回歸、樸素貝葉斯、隨機森林在R和Python中的...
    :算法覆蓋——線性回歸、邏輯回歸、樸素貝葉斯(Naive Bayes)、kNN、隨即森林,等等。樸素貝葉斯(Naive Bayes)這是一種以貝葉斯定理為基礎的分類技術,假設預測變量間相互獨立。簡單來講,樸素貝葉斯分類器假設一個分類的特性與該分類的其它特性無關。例如,如果一個水果又紅又圓,且直徑約為3英寸,那麼這個水果可能會是蘋果。即便這些特徵互相依賴,或者依賴於其他特徵的存在,樸素貝葉斯分類器還是會假設這些特徵分別獨立,暗示這個水果是蘋果。
  • 【華泰金工林曉明團隊】金工:人工智慧選股之樸素貝葉斯模型
    本報告對樸素貝葉斯模型及線性判別分析、二次判別分析進行系統測試  「生成模型」是機器學習中監督學習方法的一類。本文中,我們從樸素貝葉斯算法入手,分析比較了幾種常見的生成模型(包括線性判別分析和二次判別分析)應用於多因子選股的異同,希望對本領域的投資者產生有實用意義的參考價值。  樸素貝葉斯模型構建細節:月頻滾動訓練,結合基於時間序列的交叉驗證  樸素貝葉斯模型的構建包括特徵和標籤提取、特徵預處理、訓練集合成和滾動訓練等步驟。
  • 機器學習算法集錦:從貝葉斯到深度學習及各自優缺點
    選自static.coggle.it機器之心編譯在我們日常生活中所用到的推薦系統、智能圖片美化應用和聊天機器人等應用中,各種各樣的機器學習和數據處理算法正盡職盡責地發揮著自己的功效。本文篩選並簡單介紹了一些最常見算法類別,還為每一個類別列出了一些實際的算法並簡單介紹了它們的優缺點。
  • 「NLP」經典分類模型樸素貝葉斯解讀
    貝葉斯分類器在早期的自然語言處理任務中有著較多實際的應用,例如大部分的垃圾郵件處理都是用的貝葉斯分類器。貝葉斯分類器的理論對於理解後續的NLP模型有很大的進益,感興趣的小夥伴一定要好好看看,本文會詳細的講述貝葉斯分類器的原理。本文會是我們NLP基礎系列最後一篇機器學習模型的講解,後面會進入深度學習相關的內容。