任務安排
1、機器學習導論 8、稀疏表示
2、KNN及其實現 9、核方法
3、K-means聚類 10、高斯混合模型
4、主成分分析 11、嵌入學習
5、線性判別分析 12、強化學習
6、貝葉斯方法 13、PageRank
7、邏輯迴歸 14、深度學習
貝葉斯方法(Bayes Methods)
Ⅰ先驗概率與後驗概率
在貝葉斯統計推斷論中,一個未確定數目的先驗概率分佈(一般簡稱爲先驗)是一種表達了某人對於該數目的信仰的一種概率分佈,這種信仰是沒有考慮到一些(當前的)證據的;
先驗概率即邊緣概率,通俗點理解爲“第六感”,它往往作爲"由因求果"問題中的“因”出現的概率
在貝葉斯推斷中,一個隨機事件的後驗概率是指:當與事件相關的一些證據或背景也被考慮進來時的條件概率。“後驗”在這個語境下指在考慮了與要被檢驗的特定事件相關的證據;
後驗概率即條件概率,即你收集證據以後,佐證了你的直覺,或是開始質疑直覺,是“由果溯因”問題中的"果"
比如你開了一局王者榮耀,剛好在一樓,因爲你每個位置的勝率都只有53%(先驗概率),但是你心血來潮想玩打野,就在選下去的一剎那,二、三、四、五樓的隊友都發出了勝率,打野73%、射手66%、中單65%、邊路57%,爲了團隊,你忍辱負重,改選了一手輔助,你感覺,這把穩了,勝率>>53%(後驗概率)
這就是先驗概率和後驗概率的區別:先驗概率基於已有知識對隨機事件進行概率預估,但不考慮任何相關因素——。後驗概率基於已有知識對隨機事件進行概率預估,並考慮相關因素——
Ⅱ 貝葉斯公式
貝葉斯方法是一種非常神奇,由後驗概率求先驗概率的方法,即科學地預知未來。其核心就是利用我們所熟知的——貝葉斯公式: 雖然貝葉斯公式很好用,但通常都是建立在,我們的題目是設計好了的情況下,但是實際生活中的問題,往往不會按我們期望的那樣出現,貝葉斯公式也會有乏力的時候
例①:以下是某門診截至目前的問診情況(某樣本集,症狀、職業都是該樣本集的特徵,疾病是決策結果(標籤))
ID | 症狀 | 職業 | 疾病 |
---|---|---|---|
1 | 打噴嚏 | 護士 | 感冒 |
2 | 打噴嚏 | 農夫 | 過敏 |
3 | 頭疼 | 建築工人 | 腦震盪 |
4 | 頭疼 | 建築工人 | 感冒 |
5 | 打噴嚏 | 教師 | 感冒 |
6 | 頭疼 | 教師 | 腦震盪 |
現在又來了第七個病人,是一個打噴嚏的建築工人。請問他患上感冒的概率有多大?
由貝葉斯公式,我們可以很容易得到 但是根據表格 ,我們求出來竟然是——0?,顯然這不可能,那麼單單靠貝葉斯公式是無法解決此問題了。
那麼,就出現了樸素貝葉斯
★Ⅲ 樸素貝葉斯(Naive Bayes)
“樸素”是指:屬性條件獨立性假設
樸素貝葉斯分類器假設:
所有特徵條件獨立於決策(特徵獨立性),(用到了數理統計裏的極大似然估計)即
每個特徵條件同等重要(特徵均衡性)
有了新的假設,那麼我們可以接着解決上面的問題了
故最終答案這裏特別注意一下,
能夠成功求解該題分母的值僅僅是因爲,根據實際生活情況我們可以知道,症狀與職業是相互獨立,與樸素貝葉斯分類器做的假設毫無關係,即假如症狀與職業不相互獨立,這題根據目前知識無法求解
但是這仍然不妨礙我們引出樸素貝葉斯分類器的使用,顧名思義,“分類”,屬於監督學習,所以我們實際應用中,只是爲了與其他決策(標籤)作比較,得出最有可能的標籤,即我們的預測標籤,故實際的概率值不是我們的目標,我們只需要得到分子的值,而分母的值大家都一樣,對預測結果沒有影響
仍然拿上面那題舉例,這次問,第七個病人是一個打噴嚏的建築工人,他最有可能得什麼病?
即比較 、、 的值,由貝葉斯公式變形後,分母均爲 ,故只需比較分子 、、 的值就可以得出結論
例②(數值型樸素貝葉斯):
性別 | 身高(英尺) | 體重(磅) | 腳掌(英寸) |
---|---|---|---|
男 | 6 | 180 | 12 |
男 | 5.92 | 190 | 11 |
男 | 5.58 | 170 | 12 |
男 | 5.92 | 165 | 10 |
女 | 5 | 100 | 6 |
女 | 5.5 | 150 | 8 |
女 | 5.42 | 130 | 7 |
女 | 5.75 | 150 | 9 |
已知某人身高英尺,體重磅,腳掌英寸,求該人的性別
由貝葉斯公式得到: 這裏出現的難點就是,對於數值型,每一個新的數值,都是該特徵新的一類,如果參照上一題的做法,求解起來就會顯得非常複雜。
這裏採用樸素貝葉斯里的其中一種解決方法——高斯樸素貝葉斯(還有多元樸素貝葉斯,伯努利模型,暫時沒用到,就先不提了)
高斯樸素貝葉斯
如果要處理的是連續數據,一種通常的假設是這些連續數值爲高斯分佈(正態分佈)。例如假設訓練集中有一個連續屬性。我們首先對數據根據類別分類,然後計算每個類別中的的均值和方差。令表示爲在類上的均值,令爲在類上的方差。在給定類中某個值的概率,可以通過將表示成均值爲方差爲的正態分佈,得到。
處理連續數值問題的另一種常用的技術是通過離散化連續數值的方法(不會QUQ)。通常,當訓練樣本數量較少或精確的分佈已知時,通過概率分佈的方法是一種更好的選擇。在大量樣本的情形下離散化的方法表現更優,因爲大量的樣本可以學習到數據的分佈。由於樸素貝葉斯是一種典型的用到大量樣本的方法(越大計算量的模型可以產生越高的分類精度),所以樸素貝葉斯方法更多用到離散化方法,而不是概率分佈估計的方法(雖然這裏用到)。
對於該題,求解出男性的身高滿足均值是,方差是的正態分佈,即 ,得到 其他類似,最終就可以預測性別了!
Ⅳ 貝葉斯網絡
定義:
令 表示一個有向無環圖(拓撲圖),其中 代表圖形中所有節點的集合,而 代表有向連接線段的集合,且令 爲其有向無環圖中的某一節點 所代表的隨機變量,若節點 的聯合概率可以表示成: 則稱 爲相對於有向無環圖 的貝葉斯網絡,其中 (parents) 表示節點 之“因”。此外,對於任意的隨機變量,其聯合概率可由各自的局部條件概率分配相乘而得出,即 例:比如我們可能會經歷過的,因爲太久不玩某個遊戲,被官方“刪號了”,而它的決策機制就是基於貝葉斯網絡
弧上用條件概率 表示權值(連接強度)
連接兩個節點的箭頭代表此兩個隨機變量是具有因果關係,或非條件獨立
貝葉斯網絡的三種形式:
對於一個(有向無環圖),引入方法可以快速地判斷出兩個節點之間是否是條件獨立,從而化簡概率計算(是一種用來判斷變量是否條件獨立的圖形化方法)
形式1:
由圖知
由聯合概率與各自局部條件概率的關係得出
聯立可得
即在 未知的條件下,、被阻斷(blocked),是獨立的,稱之爲條件獨立
如形式1,可以求如下概率時得到化簡:,,
形式2:
由圖知
由聯合概率與各自局部條件概率的關係得出
聯立得
即在 給定的條件下,、被阻斷(blocked),是獨立的,稱之爲 條件獨立
形式3:
由圖知
由聯合概率與各自局部條件概率的關係得出
聯立得
即在 給定的條件下,、被阻斷(blocked),是獨立的,稱之爲 條件獨立
介紹的不詳細,僅作了解,詳細分析可看從貝葉斯方法談到貝葉斯網絡
Ⅴ 小結
● 通過估計條件概率來進行分類和推理
● 樸素貝葉斯假設每個特徵是條件獨立
● 將每個特徵(屬性)看作隨機變量
今日任務
1.給定數據集,比較樸素貝葉斯和KNN的分類性能
2.垃圾郵件過濾器(選做)
任務解決
1、可視化在上一篇博客機器學習實戰筆記5——線性判別分析裏寫過了,這裏學習一下樸素貝葉斯的調用即可(和KNN使用方法基本一致,用起來比較簡單),注意一點,樣本集一定要劃分成訓練集和測試集
from sklearn.datasets import load_digits
from sklearn import naive_bayes
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from myModule import clustering_performance
import numpy as np
import os
import cv2 as cv
# KNN分類器
def test_KNN(*data):
X_train, X_test, y_train, y_test = data
knn = KNeighborsClassifier()
knn.fit(X_train, y_train)
y_sample = knn.predict(X_test)
print('KNN分類器')
ACC = clustering_performance.clusteringMetrics1(y_test, y_sample)
print('Testing Score: %.4f' % ACC)
return ACC
# 高斯貝葉斯分類器
def test_GaussianNB(*data):
X_train, X_test, y_train, y_test = data
cls = naive_bayes.GaussianNB() # ['BernoulliNB', 'GaussianNB', 'MultinomialNB', 'ComplementNB','CategoricalNB']
cls.fit(X_train, y_train)
# print('高斯貝葉斯分類器')
print('貝葉斯分類器')
print('Testing Score: %.4f' % cls.score(X_test, y_test))
return cls.score(X_test, y_test)
path_face = 'C:/Users/1233/Desktop/Machine Learning/face_images/'
path_flower = 'C:/Users/1233/Desktop/Machine Learning/17flowers/'
# 讀取Face image
def createDatabase(path):
# 查看路徑下所有文件
TrainFiles = os.listdir(path) # 遍歷每個子文件夾
# 計算有幾個文件(圖片命名都是以 序號.jpg方式)
Train_Number = len(TrainFiles) # 子文件夾個數
X_train = []
y_train = []
# 把所有圖片轉爲1維並存入X_train中
for k in range(0, Train_Number):
Trainneed = os.listdir(path + '/' + TrainFiles[k]) # 遍歷每個子文件夾裏的每張圖片
Trainneednumber = len(Trainneed) # 每個子文件裏的圖片個數
for i in range(0, Trainneednumber):
image = cv.imread(path + '/' + TrainFiles[k] + '/' + Trainneed[i]).astype(np.float32) # 數據類型轉換
image = cv.cvtColor(image, cv.COLOR_RGB2GRAY) # RGB變成灰度圖
X_train.append(image)
y_train.append(k)
X_train = np.array(X_train)
y_train = np.array(y_train)
return X_train, y_train
X_train_flower, y_train_flower = createDatabase(path_flower)
X_train_flower = X_train_flower.reshape(X_train_flower.shape[0], 180*200)
X_train_flower, X_test_flower, y_train_flower, y_test_flower = \
train_test_split(X_train_flower, y_train_flower, test_size=0.2, random_state=22)
digits = load_digits()
X_train_digits, X_test_digits, y_train_digits, y_test_digits = \
train_test_split(digits.data, digits.target, test_size=0.2, random_state=22)
X_train_face, y_train_face = createDatabase(path_face)
X_train_face = X_train_face.reshape(X_train_face.shape[0], 180*200)
X_train_face, X_test_face, y_train_face, y_test_face = \
train_test_split(X_train_face, y_train_face, test_size=0.2, random_state=22)
print('17flowers分類')
test_KNN(X_train_flower, X_test_flower, y_train_flower, y_test_flower)
test_GaussianNB(X_train_flower, X_test_flower, y_train_flower, y_test_flower)
print('Digits分類')
test_KNN(X_train_digits, X_test_digits, y_train_digits, y_test_digits)
test_GaussianNB(X_train_digits, X_test_digits, y_train_digits, y_test_digits)
print('Face images分類')
test_KNN(X_train_face, X_test_face, y_train_face, y_test_face)
test_GaussianNB(X_train_face, X_test_face, y_train_face, y_test_face)
效果圖()
2、原理簡單點理解就是,提供訓練樣本及其標籤, 爲 (垃圾郵件), 爲 (正常郵件),生成語料庫,然後輸入測試樣本時,根據語料庫裏提供的數據,計算該郵件中、單詞出現的頻率,求出該郵件是的概率,大於某我們設定的閾值,即預測它爲
核心代碼老師基本都寫完了然後給我們(文本轉向量相關的知識還沒有學,目前搞不定),我們主要就做個分類,老師給的庫及垃圾郵件樣本集已上傳到個人資源裏了可以下載
因爲以後可能自己也會寫庫,量多了,全放在和程序相同的目錄下會看得眼花繚亂,這裏最好自己封裝起來之後直接import調用就好
路徑如圖所示
創建一個myModule文件夾,把自己寫的.py文件放進去即可(_pycache_裏的文件是調用時自動生成的,可以加快之後調用的速度)
主代碼
from sklearn.metrics import confusion_matrix
import seaborn as sns
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
# 老師給的庫
from myModule import clustering_performance
import myModule.EmailFeatureGeneration as Email
X, Y = Email.Text2Vector()
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.2, random_state=22)
# print("X_train.shape =", X_train.shape)
# print("X_test.shape =", X_test.shape)
# 樸素貝葉斯
clf = GaussianNB()
clf.fit(X_train, y_train)
y_sample_bayes = clf.predict(X_test)
Bayes_ACC = clustering_performance.clusteringMetrics1(y_test, y_sample_bayes)
print("Bayes_ACC =", Bayes_ACC)
fig = plt.figure()
plt.subplot(121)
plt.title('Bayes')
confusion = confusion_matrix(y_sample_bayes, y_test)
confusion = confusion/X_test.shape[0]
# print(confusion)
sns.heatmap(confusion, annot=True, cmap='Blues', fmt='.3g')
plt.xlabel('Predicted label')
plt.ylabel('True label')
# KNN
knn = KNeighborsClassifier()
knn.fit(X_train, y_train)
y_sample_knn = knn.predict(X_test)
KNN_ACC = clustering_performance.clusteringMetrics1(y_test, y_sample_knn)
print("KNN_ACC =", KNN_ACC)
plt.subplot(122)
plt.title('KNN')
confusion = confusion_matrix(y_sample_knn, y_test)
confusion = confusion/X_test.shape[0]
sns.heatmap(confusion, annot=True, cmap='YlGn', fmt='.3g')
plt.xlabel('Predicted label')
plt.show()
老師給的代碼(部分)
(EmailFeatureGeneration)
"""
@Author: Shiping Wang
@ Email: [email protected]
"""
from myModule import AdaboostNavieBayes as boostNaiveBayes
from sklearn import preprocessing
import numpy as np
path = 'C:/Users/1233/Desktop/Machine Learning/SpamEmailDetector/SpamEmailDetector/'
def Text2Vector( ):
"""
return: feature matrix: nxd
labels: n x 1
"""
### Step 1: Read data
filename = path + 'emails/training/SMSCollection.txt'
smsWords, classLabels = boostNaiveBayes.loadSMSData(filename)
classLabels = np.array(classLabels)
### STEP 2: Transform the original data into feature matrix
vocabularyList = boostNaiveBayes.createVocabularyList(smsWords)
print("生成語料庫!")
trainMarkedWords = boostNaiveBayes.setOfWordsListToVecTor(vocabularyList, smsWords)
print("數據標記完成!")
# 轉成array向量
trainMarkedWords = np.array(trainMarkedWords) ### Traning feature matrix N x d
#print("The all feature matrix size is: ", trainMarkedWords.shape)
return trainMarkedWords, classLabels
(AdaboostNaiveBayes)
path = 'C:/Users/1233/Desktop/Machine Learning/SpamEmailDetector/SpamEmailDetector/'
def textParser(text):
"""
對SMS預處理,去除空字符串,並統一小寫
:param text:
:return:
"""
import re
regEx = re.compile(r'[^a-zA-Z]|\d') # 匹配非字母或者數字,即去掉非字母非數字,只留下單詞
words = regEx.split(text)
# 去除空字符串,並統一小寫
words = [word.lower() for word in words if len(word) > 0]
return words
def loadSMSData(fileName):
"""
加載SMS數據
:param fileName:
:return:
"""
f = open(fileName, 'rb')
classCategory = [] # 類別標籤,1表示是垃圾SMS,0表示正常SMS
smsWords = []
for line in f.readlines():
linedatas = line.decode('utf-8').strip().split('\t')
if linedatas[0] == 'ham':
classCategory.append(0)
elif linedatas[0] == 'spam':
classCategory.append(1)
# 切分文本
words = textParser(linedatas[1])
smsWords.append(words)
return smsWords, classCategory
def createVocabularyList(smsWords):
"""
創建語料庫
:param smsWords:
:return:
"""
vocabularySet = set([])
for words in smsWords:
vocabularySet = vocabularySet | set(words)
vocabularyList = list(vocabularySet)
return vocabularyList
def getVocabularyList(fileName):
"""
從詞彙列表文件中獲取語料庫
:param fileName:
:return:
"""
fr = open(fileName)
vocabularyList = fr.readline().strip().split('\t')
fr.close()
return vocabularyList
def setOfWordsToVecTor(vocabularyList, smsWords):
"""
SMS內容匹配預料庫,標記預料庫的詞彙出現的次數
:param vocabularyList:
:param smsWords:
:return:
"""
vocabMarked = [0] * len(vocabularyList)
for smsWord in smsWords:
if smsWord in vocabularyList:
vocabMarked[vocabularyList.index(smsWord)] += 1
return np.array(vocabMarked)
def setOfWordsListToVecTor(vocabularyList, smsWordsList):
"""
將文本數據的二維數組標記
:param vocabularyList:
:param smsWordsList:
:return:
"""
vocabMarkedList = []
for i in range(len(smsWordsList)):
vocabMarked = setOfWordsToVecTor(vocabularyList, smsWordsList[i])
vocabMarkedList.append(vocabMarked)
return vocabMarkedList
def trainingNaiveBayes(trainMarkedWords, trainCategory):
"""
訓練數據集中獲取語料庫中詞彙的spamicity:P(Wi|S)
:param trainMarkedWords: 按照語料庫標記的數據,二維數組
:param trainCategory:
:return:
"""
numTrainDoc = len(trainMarkedWords)
numWords = len(trainMarkedWords[0])
# 是垃圾郵件的先驗概率P(S)
pSpam = sum(trainCategory) / float(numTrainDoc)
# 統計語料庫中詞彙在S和H中出現的次數
wordsInSpamNum = np.ones(numWords)
wordsInHealthNum = np.ones(numWords)
spamWordsNum = 2.0
healthWordsNum = 2.0
for i in range(0, numTrainDoc):
if trainCategory[i] == 1: # 如果是垃圾SMS或郵件
wordsInSpamNum += trainMarkedWords[i]
spamWordsNum += sum(trainMarkedWords[i]) # 統計Spam中語料庫中詞彙出現的總次數
else:
wordsInHealthNum += trainMarkedWords[i]
healthWordsNum += sum(trainMarkedWords[i])
pWordsSpamicity = np.log(wordsInSpamNum / spamWordsNum)
pWordsHealthy = np.log(wordsInHealthNum / healthWordsNum)
return pWordsSpamicity, pWordsHealthy, pSpam
def getTrainedModelInfo():
"""
獲取訓練的模型信息
:return:
"""
# 加載訓練獲取的語料庫信息
vocabularyList = getVocabularyList(path + 'vocabularyList.txt')
pWordsHealthy = np.loadtxt(path + 'pWordsHealthy.txt', delimiter='\t')
pWordsSpamicity = np.loadtxt(path + 'pWordsSpamicity.txt', delimiter='\t')
fr = open(path + 'pSpam.txt')
pSpam = float(fr.readline().strip())
fr.close()
return vocabularyList, pWordsSpamicity, pWordsHealthy, pSpam
def classify(pWordsSpamicity, pWordsHealthy, DS, pSpam, testWordsMarkedArray):
"""
計算聯合概率進行分類
:param testWordsMarkedArray:
:param pWordsSpamicity:
:param pWordsHealthy:
:param DS: adaboost算法額外增加的權重係數
:param pSpam:
:return:
"""
# 計算P(Ci|W),W爲向量。P(Ci|W)只需計算P(W|Ci)P(Ci)
ps = sum(testWordsMarkedArray * pWordsSpamicity * DS) + np.log(pSpam)
ph = sum(testWordsMarkedArray * pWordsHealthy) + np.log(1 - pSpam)
if ps > ph:
return ps, ph, 1
else:
return ps, ph, 0
效果圖(KNN跑起來明顯要慢不少,但是效果更好)
()