機器學習--用樸素貝葉斯分類法辨別男女聲音

和前面介紹到的kNN,決策樹同樣,貝葉斯分類法也是機器學習中經常使用的分類方法。貝葉斯分類法主要以機率論中貝葉斯定理爲分類依據,具備很普遍的應用。本文經過一個完整的例子,來介紹如何用樸素貝葉斯分類法實現分類。主要內容有下:git

    一、條件機率與貝葉斯定理介紹算法

    二、數據集選擇及處理數據庫

    三、樸素貝葉斯分類器實現網絡

    四、測試分類效果app

    五、寫在後面的話dom

 

一 、條件機率與貝葉斯定理介紹機器學習

條件機率:工具

條件機率是指事件A在另一個事件B已經發生條件下的發生機率,用P(A|B)表示。一般,事件A在事件B(發生)的條件下的機率,與事件B在事件A的條件下的機率是不同的。可是,這二者是有肯定的關係,貝葉斯定理 就是這種關係的陳述。學習

貝葉斯公式:測試

    

其中:P(c | x) 爲在事件 x 已經發生的前提下事件 c 發生的機率,P(c),P(x)分別爲事件 c 和事件 x 發生的機率。

舉個例子:

以下圖有6次搶火車票記錄,如今小明條件是:通常熟練 | 不用工具 | 網速適中,問他能搶到票的機率是多少?

電腦熟練程度 是否使用搶票軟件 網速 可以搶到票
超級熟練 不用工具 網速快 搶到
超級熟練 不用工具 網速慢 沒搶到
通常熟練 用工具 網速適中 搶到
通常熟練 不用工具 網速快 搶到
生疏 不用工具 網速適中 沒搶到
生疏 用工具 網速快 搶到

 

 

 

 

 

 

 

 根據貝葉斯定律,小明搶到票的機率爲:

P(搶到 | 通常熟練 ✕ 不用工具 ✕ 網速適中 )

= P(通常熟練 ✕ 不用工具 ✕ 網速適中 | 搶到 ) * P( 搶到 ) / P( 通常熟練 ✕ 不用工具 ✕ 網速適中 )

這裏用的是樸素貝葉斯方法,之因此被稱爲「樸素」,是由於 這裏假設全部特徵之間相互獨立,如電腦熟練程度 和 是否使用搶票軟件等無關。

則上面式子可展開爲:

P(搶到 | 通常熟練 ✕ 不用工具 ✕ 網速適中 )

= P(通常熟練 | 搶到 ) * P(不用工具 | 搶到 ) * P(網速適中 | 搶到 ) * P( 搶到 ) / P( 通常熟練  ) / P( 不用工具  )/ P( 網速適中  )

= 0.5 * 0.5 * 0.25 * 0.6667 / 0.3333/0.6667/0.3333  =  0.5625

咱們能夠大概算出 小明搶到票的機率爲 56.25%

二 、數據集選擇及處理

Kaggle 是一個提供機器學習競賽、託管數據庫、編寫和分享代碼的平臺,上面有一些用戶分享的開放數據集,本文選取Kory Becker提供的男女聲音特徵分類數據集 https://www.kaggle.com/primaryobjects/voicegender

該數據集樣例以下:

這裏的數據集是針對男女聲音使用聲波和調諧器包進行預處理,是基於聲音和語音的聲學特性而建立的,用來識別男性或女性的聲音。咱們沒必要過於糾結20個比較專業的的特徵名稱,這裏把其當作通常的連續性數值特徵就能夠了。這裏只展現了前兩條數據,前20列(meanfreq,sd,median......dfrange,modindx)爲聲音的各類特徵 ,最後一列 label 爲聲音的分類。咱們能夠看到 mode 和 dfrange 等列都有爲0 的值,說明數據可能有缺失,咱們在處理數據集時要考慮到數據缺失的問題.

處理缺失數據:

  咱們將值爲 0 的 特徵值 視爲缺失,彌補缺失的辦法是用該特徵的平均值填充。

 1         # 求每個特徵的平均值
 2         data_mat = np.array(data_mat).astype(float)
 3         count_vector = np.count_nonzero(data_mat, axis=0)
 4         sum_vector = np.sum(data_mat, axis=0)
 5         mean_vector = sum_vector / count_vector
 6 
 7         # 數據缺失的地方 用 平均值填充
 8         for row in range(len(data_mat)):
 9             for col in range(num):
10                 if data_mat[row][col] == 0.0:
11                     data_mat[row][col] = mean_vector[col]

 

數據離散化

貝葉斯公式 適合標稱型數據,這裏每一個特徵都是連續的浮點數值,咱們須要將特徵值離散化。

離散的方法以下:

  

max min分別爲該特徵的最大值和最小值,n爲離散的程度,Floor()爲向下取整

本文中 n 取 10 ,每一個特徵的值離散爲 [0,1,2,3,4,5,6,7,8,9] 中的一個,離散化後的數據樣例以下:

實現以下:

 1         # 將數據連續型的特徵值離散化處理
 2         min_vector = data_mat.min(axis=0)
 3         max_vector = data_mat.max(axis=0)
 4         diff_vector = max_vector - min_vector
 5         diff_vector /= 9
 6 
 7         new_data_set = []
 8         for i in range(len(data_mat)):
 9             line = np.array((data_mat[i] - min_vector) / diff_vector).astype(int)
10             new_data_set.append(line)

切分訓練、測試數據集

本數據集公有3168條數據,爲了讓男性聲音樣本和女性聲音樣本隨機地分佈到訓練和測試數據集,這裏使用隨機算法隨機選取2000條做爲訓練數據集,其他的1168條做爲測試數據集:

 1         # 隨機劃分數據集爲訓練集 和 測試集
 2         test_set = list(range(len(new_data_set)))
 3         train_set = []
 4         for i in range(2000):
 5             random_index = int(np.random.uniform(0, len(test_set)))
 6             train_set.append(test_set[random_index])
 7             del test_set[random_index]
 8 
 9         # 訓練數據集
10         train_mat = []
11         train_classes = []
12         for index in train_set:
13             train_mat.append(new_data_set[index])
14             train_classes.append(list_class[index])
15 
16         # 測試數據集
17         test_mat = []
18         test_classes = []
19         for index in test_set:
20             test_mat.append(new_data_set[index])
21             test_classes.append(list_class[index])

 

三 、樸素貝葉斯分類器實現

咱們假設20個特徵值分類爲F1,F2 ,F3 ......,F20

F1i1表示 特徵F1 取 第i1 個 分類

則一個測試樣本向量能夠表示以下:

test_vector = [F1i1 , F2i2 , F3i3  .....  F19i19 , F20i20]

則 其是男性的機率爲:

P(男 | F1i1 ✕ F2i2 ✕ F3i3  .....  F19i19 ✕ F20i20)

= P(F1i1 ✕ F2i2 ✕ F3i3  .....  F19i19 ✕ F20i20 | 男) * P(男) / P(F1i1 ✕ F2i2 ✕ F3i3  .....  F19i19 ✕ F20i20)

實現爲:

 1 def native_bayes(train_matrix, list_classes):
 2     """
 3     :param train_matrix: 訓練樣本矩陣
 4     :param list_classes: 訓練樣本分類向量
 5     :return:p_1_class 任同樣本分類爲1的機率  p_feature,p_1_feature 分別爲給定類別的狀況下因此特徵全部取值的機率
 6     """
 7 
 8     # 訓練樣本個數
 9     num_train_data = len(train_matrix)
10     num_feature = len(train_matrix[0])
11     # 分類爲1的樣本佔比
12     p_1_class = sum(list_classes) / float(num_train_data)
13 
14     n = 10
15     list_classes_1 = []
16     train_data_1 = []
17 
18     for i in list(range(num_train_data)):
19         if list_classes[i] == 1:
20             list_classes_1.append(i)
21             train_data_1.append(train_matrix[i])
22 
23     # 分類爲1 狀況下的各特徵的機率
24     train_data_1 = np.matrix(train_data_1)
25     p_1_feature = {}
26     for i in list(range(num_feature)):
27         feature_values = np.array(train_data_1[:, i]).flatten()
28         # 避免某些特徵值機率爲0 影響整體機率,每一個特徵值最少個數爲1
29         feature_values = feature_values.tolist() + list(range(n))
30         p = {}
31         count = len(feature_values)
32         for value in set(feature_values):
33             p[value] = np.log(feature_values.count(value) / float(count))
34         p_1_feature[i] = p
35 
36     # 全部分類下的各特徵的機率
37     p_feature = {}
38     train_matrix = np.matrix(train_matrix)
39     for i in list(range(num_feature)):
40         feature_values = np.array(train_matrix[:, i]).flatten()
41         feature_values = feature_values.tolist() + list(range(n))
42         p = {}
43         count = len(feature_values)
44         for value in set(feature_values):
45             p[value] = np.log(feature_values.count(value) / float(count))
46         p_feature[i] = p
47 
48     return p_feature, p_1_feature, p_1_class

 

問題1:

由於 計算中有 P(F1i1 ✕ F2i2 ✕ F3i3  .....  F19i19 ✕ F20i20)= P(F1i1 )*P( F2i2 )   .....  P(F20i20)

須要多個機率相乘,但若是某個機率爲0,則總的機率就會爲0,這樣計算就會出現錯誤,因此這裏給每一個分類至少添加一條數據,如上圖第29行和第41行

問題2:

由於本文的數據集有20個特徵,多個特徵的機率相乘,乘積的結果將會很是小,可能會在四捨五入過程當中被捨棄掉,從而影響實驗結果。因此這裏統一取對數,如上圖第33行和45行

 

四 、測試分類效果

按照貝葉斯公式,計算測試樣本在特定條件下 爲男性的機率 和 爲女性的機率,選取機率大的分類爲最終的分類:

 1 def classify_bayes(test_vector, p_feature, p_1_feature, p_1_class):
 2     """
 3     :param test_vector: 要分類的測試向量
 4     :param p_feature: 全部分類的狀況下特徵全部取值的機率
 5     :param p_1_feature: 類別爲1的狀況下全部特徵全部取值的機率
 6     :param p_1_class: 任同樣本分類爲1的機率
 7     :return: 1 表示男性 0 表示女性
 8     """
 9     # 計算每一個分類的機率(機率相乘取對數 = 機率各自對數相加)
10     sum = 0.0
11     for i in list(range(len(test_vector))):
12         sum += p_1_feature[i][test_vector[i]]
13         sum -= p_feature[i][test_vector[i]]
14     p1 = sum + np.log(p_1_class)
15     p0 = 1 - p1
16     if p1 > p0:
17         return 1
18     else:
19         return 0

因爲程序每次執行都是隨機選取2000個樣本做爲訓練樣本,因此每次執行的訓練集也是不一樣的,所以獲得的正確率也是波動的。

測試了幾下,識別正確率分別以下:0.88955 | 0.8998 | 0.8844 | 0.8904 | 0.8981

能夠看到正確率基本在0.89 左右

五 、寫在後面的話

 本文的完整代碼已上傳碼雲倉庫 https://gitee.com/beiyan/machine_learning/tree/master/naive_bayes  

樸素貝葉斯分類器的原理和實現都比較簡單,這是基於各個特徵都是相對獨立的狀況。爲了提升識別率,還能夠經過好比 特徵加權、增長特徵值離散程度等改進辦法來實現。

假如各個特徵不是相互獨立,例如身高特徵和體重特徵有必定關係等,在這種狀況下,就須要基於有向圖的決策模:貝葉斯網絡。

相關文章
相關標籤/搜索