1. 程式人生 > 實用技巧 >08-02 機器學習演算法原理

08-02 機器學習演算法原理

目錄
更新、更全的《機器學習》的更新網站,更有python、go、資料結構與演算法、爬蟲、人工智慧教學等著你:https://www.cnblogs.com/nickchen121/p/11686958.html

機器學習演算法原理

一、1.1 感知機演算法

每逢下午有體育課,總會有男孩和女孩在學校的操場上玩耍。

假設由於傳統思想的影響,男孩總會和男孩一起打打籃球,女孩總會和女孩一起踢毽子、跳跳繩,如下圖所示。

# 感知機演算法圖例
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties

%matplotlib inline
font = FontProperties(fname='/Library/Fonts/Heiti.ttc')

np.random.seed(1

)
x1 = np.random.random(20)+1.5
y1 = np.random.random(20)+0.5
x2 = np.random.random(20)+3
y2 = np.random.random(20)+0.5

# 一行二列第一個
plt.subplot(121)
plt.scatter(x1, y1, s=50, color='b', label='男孩(+1)')
plt.scatter(x2, y2, s=50, color='r', label='女孩(-1)')
plt.vlines(2.8, 0, 2, colors="r", linestyles="-", label='\(wx+b=0\)')
plt.title('線性可分', fontproperties=font, fontsize=20)
plt.xlabel('x')
plt.legend(prop=font)

# 一行二列第二個
plt.subplot(122)
plt.scatter(x1, y1, s=50, color='b', label='男孩(+1)')
plt.scatter(x2, y2, s=50, color='r', label='女孩(-1)')
plt.scatter(3.5, 1, s=50, color='b')
plt.title('線性不可分', fontproperties=font, fontsize=20)
plt.xlabel('x')
plt.legend(prop=font, loc='upper right')
plt.show()

從左圖中也可以看出總能找到一條直線將男孩和女孩分開,即男孩和女孩在操場上的分佈是線性可分的,此時該分隔直線為

ωx+b=0

其中ω,b是引數,x是男孩和女孩共有的某種特徵。

如果某個男孩不聽話跑到女孩那邊去了,如下圖右圖所示,則無法通過一條直線能夠把所有的男孩和女孩分開,則稱男孩和女孩在操場上的分佈是線性不可分的,即無法使用感知機演算法完成該分類過程。

上述整個過程其實就是感知機實現的一個過程。

1.1 1.1.1 決策函式

感知機演算法的決策函式為

sign(ωTx)={1,ωTx>01,ωTx<0

該決策函式的意思是點x=x0對於超平面ωx+b=0

  • ωx0+b>0為正類
  • ωx0+b<0為反類

1.1.1 1.1.1.1 sign函式影象

sign函式也稱作符號函式,當x>0的時候y=1;當x=0的時候y=0;當x<0的時候y=-1。sign函式公式為

y={1,x>00,x=01,x<0

# sign函式影象
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline

x_list = [i for i in range(-100, 100)]
y_list = np.sign(x_list)

plt.figure()
plt.plot(x_list, y_list, color='r')
plt.plot(0, 0, color='k', marker='o')
plt.xlabel('x')
plt.ylabel('y')
plt.show()

1.2 1.1.2 損失函式

感知機的損失函式表示誤分類點到超平面的距離,源自於數學中點(x0,y0)到面Ax+By+C=0的公式

|Ax0+By0+C|A2+B2

當樣本點(xi,yi)為誤分類點時:

  • wTxi>0時,本來應該是yi=1,但由於誤分類,所以yi=1yi(wTxi)>0
  • wTxi<0時,本來應該是yi=1,但由於誤分類,所以yi=1yi(wTxi)>0

因此感知機演算法的損失函式為

yi(ωTxi)||ω||

1.3 1.1.3 目標函式

感知機演算法的目標函式為

J(ω)=xiMyi(ωTxi)||ω||

其中M是所有誤分類點的集合。

該目標函式不同於其他機器學習演算法的均值,它是對所有誤分類點的距離加和。

由於ωTxi=ω1x1+ω2x2++ωnxn+b,如果ωb成比例的增加,即分子的ωb擴大n倍時,分母的L2範數也將擴大n倍,也就是說分子和分母有固定的倍數關係,即可以將分子或分母固定為1,然後求分子自己或分母的倒數的最小化作為新的目標函式。(此處講解拿出b,事實上b對結果的影響很小,後續會繼續用向量的方式,並且忽略b)。

感知機將分母||ω||固定為1,然後將分子的最小化作為目標函式,因此感知機的目標函式更新為

J(ω)=xiMyi(ωTxi)

1.4 1.1.4 目標函式優化問題

感知機演算法的目標函式為

argminωJ(ω)=argminωxiMyi(ωTxi)

二、1.2 線性迴歸

假設房價和房子所在地區x1、佔地面積x2、戶型x3和採光度x4有關,那麼我是不是可以把這些因素假想成房子的特徵,然後給這些每個特徵都加上一個相應的權重ω,既可以得到如下的決策函式

y^=ω1x1+ω2x2+ω3x3+ω4x4+b

其中b可以理解為偏差,你也可以想成房子的這些特徵再差也可能會有一個底價。

基於上述給出房價的決策函式,我們就可以對一個某個不知名的房子輸入它的這些特徵,然後就可以得到這所房子的預測價格了。

2.1 1.2.1 決策函式

線性迴歸的決策函式為

y^=f(x)=ω1x1+ω2x2++ωnxn+b=wTx+b

2.2 1.2.2 目標函式

線性迴歸的目標函式為

(1)J(ω,b)=i=1m(yiyi^)2(2)=i=1m(yiwTxib)

其中yi為真實值,yi^為預測值。

該目標函式使用的損失函式為平方損失函式。

2.3 1.2.3 目標函式優化問題

線性迴歸的目標函式優化問題為

argminωJ(ω,b)=argminωi=1m(yiwTxib)

三、1.3 邏輯迴歸簡介

感知機演算法中講到,假設操場上男生和女生由於受傳統思想的影響,男生和女生分開站著,並且因為男生和女生散亂在操場上呈線性可分的狀態,因此我們總可以通過感知機演算法找到一條直線把男生和女生分開,並且最終可以得到感知機模型為

f(x)=sign(wTx)

如果你細心點會發現,由於感知模型使用的是sign函式,如果當計算一個樣本點wTx=0.001的時候,sign(wTx)=1,即該函式會把該樣本歸為1,但是為什麼他不能是0類呢?並且由於sign函式在x=0處有一個階躍,即函式不連續,該函式在數學上也是不方便處理的。

由此邏輯函式使用sigmoid函式對wTx做處理,並且把sigmoid函式得到的值y^當成概率進行下一步處理,這也正是邏輯迴歸對感知機的改進。

上述整個過程其實就是邏輯迴歸一步一步被假想出來的的一個過程,接下來將從理論層面抽象的講解邏輯迴歸。

3.1 1.3.1 Sigmoid函式

Sigmoid函式公式為

g(z)=11+ez

# Sigmoid函式影象圖例
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

def sigmoid(z):
return 1 / (1 + np.exp(-z))

ax = plt.subplot(111)

# 描繪十字線
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data', 0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data', 0))

z = np.linspace(-10, 10, 256)
hat_y = sigmoid(z)
plt.plot(z, hat_y, c='r', label='Sigmoid')

# 描繪y=0.5和y=1.0兩條直線
plt.yticks([0.0, 0.5, 1.0])
ax = plt.gca()
ax.yaxis.grid(True)

plt.xlabel('\(w^Tx\)')
plt.ylabel('\(\hat{y}\)')
plt.legend()
plt.show()

3.2 1.3.2 決策函式

邏輯迴歸的決策函式使用的Sigmoid函式,即

y=g(ωTx)=11+eωTx

其中g()為Sigmoid函式。

邏輯迴歸的決策函式為

(3)p(y=1|x,ω)=π(x)(4)p(y=0|x,ω)=1π(x)

其中10代表兩個類別,通過Sigmoid函式影象可以看出當ωTx>0y=1,當ωTx<0y=0

3.3 1.3.3 損失函式

邏輯迴歸的損失函式為

L(ω)=i=1m[π(xi)]yi[(1π(xi))](1yi)

  • yi=0時,L(ω)=i=1m[π(xi)]0[(1π(xi))](10)=i=1m[(1π(xi))]
  • yi=1時,L(ω)=i=1m[π(xi)]1[(1π(xi))](11)=i=1m[π(xi)]1

3.4 1.3.4 目標函式

對邏輯迴歸的損失函式取對數,即可得邏輯迴歸的目標函式為

J(ω)=i=1m[yilogπ(xi)+(1yi)log(1π(xi))]

3.5 1.3.5 目標函式優化問題

其中邏輯迴歸的目標函式的優化問題為最大化目標函式

argmaxωJ(ω)=argmaxωi=1m[yilogπ(xi)+(1yi)log(1π(xi))]

四、1.4 樸素貝葉斯法簡介

假設現在有一個有兩個類別的鳶尾花資料集,並且已經知曉每個資料的分類情況,並且假設資料的分佈如下圖所示。

# 樸素貝葉斯引入圖例
from matplotlib.font_manager import FontProperties
import matplotlib.pyplot as plt
from sklearn import datasets
%matplotlib inline

font = FontProperties(fname='/Library/Fonts/Heiti.ttc')

iris_data = datasets.load_iris()
X = iris_data.data[0:100, [0, 1]]
y = iris_data.target[0:100]

plt.scatter(X[0:50, [0]], X[0:50, [1]], color='r',
s=50, marker='o', label='山鳶尾')
plt.scatter(X[50:100, [0]], X[50:100, [1]],
color='b', s=50, marker='x', label='雜色鳶尾')
plt.scatter(5.5,3.2,color='g',marker='*',label='新樣本',s=100)

plt.xlabel('花瓣長度(cm)', fontproperties=font)
plt.ylabel('花瓣寬度(cm)', fontproperties=font)
plt.legend(prop=font)
plt.show()

現在假設有一個未知分類的鳶尾花資料(x1(),x2()),用p1(x1,x2)表示樣本屬於山鳶尾(red)的概率,用p2(x1,x2)表示屬於雜色鳶尾(blue)的概率,p1(x1,x2)+p2(x1,x2)=1

假設如果p1(x1,x2)>p2(x1,x2)(x1,x2)為山鳶尾,否則為雜色鳶尾,即選擇概率高的類別作為新樣本的分類結果。這就是貝葉斯決策理論的核心思想,選擇具有最高概率的決策。

如果使用條件概率來表示這個上述所說的分類,則可以表示為

(5)p(red|x1,x2)>p(blue|x1,x2)樣本屬於山鳶尾(6)p(red|x1,x2)<p(blue|x1,x2)樣本屬於雜色鳶尾

也就是說求如下表達式結果

argmax(p(red|x1,x2),p(blue|x1,x2))

如果只有兩個特徵x1x2,那麼計算並不會很難,按照條件公式計算即可,但是你有沒有想過如果有n特徵,K個分類呢?即計算

argmaxckp(cj|x1,x2,,xn)(k=1,2,,K)

上述的計算量是非常大的,那麼我們有沒有一種簡單的方法能夠改善該公式呢?有是有一定有的,即樸素貝葉斯法。

4.1 1.4.1 貝葉斯公式

若果AB相互獨立,並有條件概率公式

p(A|B)=p(A,B)p(B)p(B|A)=p(A,B)p(A)

通過條件概率可得

p(A,B)=p(B|A)p(A)p(A|B)=p(B|A)p(A)p(B)簡寫的貝葉斯公式

4.2 1.4.2 樸素貝葉斯法

假設已經得到了訓練集的p(ck)p(xj|ck)值,假設現有一個測試樣本(x1,x2,,xn),則可以根據貝葉斯公式求得K個分類c1,c2,,ck各自的概率。

p(ck|x1,x2,,xn)=p(x1,x2,,xn|ck)p(ck)p(x1,x2,,xn)

假設特徵之間相互獨立,則可以把上述公式轉化為

p(ck|x1,x2,,xn)=p(x1|ck)p(x2|ck)p(xn|ck)p(ck)p(x1,x2,,xn)

求得所有分類各自的概率之後,哪一個分類的概率最大,則樣本屬於哪一個分類。

(7)=max(p(c1|x1,x2,,xn),p(c2|x1,x2,,xn),,p(ck|x1,x2,,xn))(8)=argmaxckp(x1|ck)p(x2|ck)p(xn|ck)p(x1,x2,,xn)

其中y=maxf(x)表示yf(x)中所有的值中最大的輸出;y=argmaxf(x)表示yf(x)中,輸出的那個引數t

由於每一個類別的概率公式的分子都是相同的,把分子去掉後則可以把上述公式轉化為樸素貝葉斯模型的基本公式

(9)=argmaxckp(x1|ck)p(x2|ck)p(xn|ck)p(ck)(10)=argmaxckp(ck)j=1np(xj|ck)

五、1.5 k近鄰演算法簡介

不知道同學們在看電影的時候有沒有思考過你是如何判斷一部電影是愛情片還是動作片的,你可以停下來想想這個問題再往下看看我的想法。

我說說我是如何判斷一部電影是愛情片還是動作片的,首先絕對不是靠那些預告片,畢竟預告片太短了,愛情片的預告可能是動作片,動作片的預告可能是愛情片也說不定。

相比較預告片我用了一個很愚蠢很繁瑣但很有效的方法。首先我用一部電影的接吻鏡頭的次數作為x軸,打鬥的場景次數作為y軸生成了一個二維空間,即平面圖,如下圖所示。(注:以下電影的接吻鏡頭次數和打鬥場景次數都是假設的)

# k近鄰演算法引入圖例
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
%matplotlib inline
font = FontProperties(fname='/Library/Fonts/Heiti.ttc')

# 動作片
plt.scatter(2, 10, marker='o', c='r', s=50)
plt.text(2, 9, s='《戰狼2》(2,10)', fontproperties=font, ha='center')
plt.scatter(4, 12, marker='o', c='r', s=50)
plt.text(4, 11, s='《復仇者聯盟2》(4,12)', fontproperties=font, ha='center')
plt.scatter(2, 15, marker='o', c='r', s=50)
plt.text(2, 14, s='《猩球崛起》(2,15)', fontproperties=font, ha='center')

# 愛情片
plt.scatter(10, 4, marker='x', c='g', s=50)
plt.text(10, 3, s='《泰坦尼克號》(10,4)', fontproperties=font, ha='center')
plt.scatter(12, 2, marker='x', c='g', s=50)
plt.text(12, 1, s='《致我們終將逝去的青春》(12,2)', fontproperties=font, ha='center')
plt.scatter(15, 5, marker='x', c='g', s=50)
plt.text(15, 4, s='《誰的青春不迷茫》(15,5)', fontproperties=font, ha='center')

# 測試點
plt.scatter(5, 6, marker='s', c='k', s=50)
plt.text(5, 5, s='《未知型別的電影》(5,5)', fontproperties=font, ha='center')

plt.xlim(0, 18)
plt.ylim(0, 18)
plt.xlabel('接吻鏡頭(次)', fontproperties=font)
plt.ylabel('打鬥場景(次)', fontproperties=font)
plt.title('k近鄰演算法引入圖例', fontproperties=font, fontsize=20)
plt.show()

通過上圖我們可以發現動作片《戰狼2》的打鬥場景次數明顯多於接吻鏡頭,而愛情片《泰坦尼克號》的接吻鏡頭明顯多於打鬥場景,並且其他的動作片和愛情片都有這樣的規律,因此我做了一個總結:愛情片的接吻鏡頭次數會明顯比打鬥的場景次數多,而動作片反之。

通過上述的總結,如果我再去看一部新電影的時候,我會在心裡默數這部電影的接吻鏡頭的次數和打鬥場景,然後再去判斷。這種方法看起來無懈可擊,但是如果碰到了上述黑點《未知型別的電影》所在的位置,即當接吻鏡頭次數和打鬥場景次數差不多的時候,往往很難判斷它是愛情片還是動作片。

這個時候我們的主角k近鄰演算法就應該出場了,因為使用k近鄰演算法可以很好的解決《未知型別的電影》這種尷尬的情形。

  1. 假設我們把平面圖中的每一個電影看成一個點,例如《戰狼2》是(2,10)、《未知型別的電影》是(5,6)、《泰坦尼克號》是(10,4)……
  2. 我們使用k近鄰的思想,通過歐幾里得距離公式計算出每一部電影在平面圖中到《未知型別的電影》的距離
  3. 然後假設k=4,即獲取離《未知型別的電影》最近的4部電影
  4. 如果這4部電影中愛情片型別的電影多,則《未知型別的電影》是愛情片;如果動作片型別的電影多,則《未知型別的電影》是動作片;如果兩種型別的電影數量一樣多,則另選k

上述整個過程其實就是k近鄰演算法實現的一個過程。

5.1 1.5.1 距離度量工具

k近鄰演算法對於距離度量的方式,有很多種方法可以選擇,一般選擇我們電影分類例子中講到的歐幾里得距離,也稱作歐氏距離。同時還可能會使用曼哈頓距離或閔可夫斯基距離,這裡統一給出它們的公式。

假設n維空間中有兩個點xixj,其中xi=(xi(1),xi(2),,xi(n))xj=(xj(1),xj(2),,xj(n))

歐氏距離為

d(xi,xj)=l=1n(xi(l)xj(l))2

曼哈頓距離為

d(xi,xj)=l=1n|xi(l)xj(l)|

閔可夫斯基距離為

d(xi,xj)=l=1n(|xi(l)xj(l)|)pp

其中曼哈頓距離是閔可夫斯基距離p=1時的特例,而歐氏距離是閔可夫斯基距離p=2時的特例。

六、1.6 決策樹簡介

假設銀行需要構造一個徵信系統用來發放貸款,如果你是構建該系統的人,你會如何構建該系統呢?

我說說我將如何構建一個銀行的徵信系統,首先,我會判斷徵信人的年收入有沒有50萬,如果有我直接判定他可以貸款,如果沒有我會再做其他的判斷;其次,判斷徵信人有沒有房產,如果有房產也就是說他有了可以抵押的不動產,既可以判定他可以貸款,如果沒有,則不能貸款……

上述整個過程其實就是決策樹實現的一個過程。

七、1.7 支援向量機簡介

# 感知機引入圖例
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties

%matplotlib inline
font = FontProperties(fname='/Library/Fonts/Heiti.ttc')

np.random.seed(1)
x1 = np.random.random(20)+1.5
y1 = np.random.random(20)+0.5
x2 = np.random.random(20)+3
y2 = np.random.random(20)+0.5

# 一行二列第一個
plt.subplot(121)
plt.scatter(x1, y1, s=50, color='b', label='男孩(+1)')
plt.scatter(x2, y2, s=50, color='r', label='女孩(-1)')
plt.vlines(2.8, 0, 2, colors="r", linestyles="-", label='\(wx+b=0\)')
plt.title('線性可分', fontproperties=font, fontsize=20)
plt.xlabel('x')
plt.legend(prop=font)

# 一行二列第二個
plt.subplot(122)
plt.scatter(x1, y1, s=50, color='b', label='男孩(+1)')
plt.scatter(x2, y2, s=50, color='r', label='女孩(-1)')
plt.scatter(3.5, 1, s=50, color='b')
plt.title('線性不可分', fontproperties=font, fontsize=20)
plt.xlabel('x')
plt.legend(prop=font, loc='upper right')
plt.show()

在二維空間中,感知機模型試圖找到一條直線能夠把二元資料分隔開;在高維空間中感知機模型試圖找到一個超平面S,能夠把二元資料隔離開。這個超平面Sωx+b=0,在超平面S上方的資料定義為1,在超平面S下方的資料定義為1,即當ωx>0y^=+1;當ωx<0y^=1

上張線性可分和線性不可分的區別圖第一張圖則找到了一條直線能夠把二元資料分隔開,但是能夠發現事實上可能不只存在一條直線將資料劃分為兩類,因此再找到這些直線後還需要找到一條最優直線,對於這一點感知機模型使用的策略是讓所有誤分類點到超平面的距離和最小,即最小化該式

J(ω)=xiMyi(ωxi+b)||ω||2

上式中可以看出如果ωb成比例的增加,則分子的ωb擴大n倍時,分母的L2範數也將擴大n倍,也就是說分子和分母有固定的倍數關係,既可以分母||ω||2固定為1,然後求分子的最小化作為代價函式,因此給定感知機的目標函式為

J(ω)=xiMyi(ωxi+b)

既然分子和分母有固定倍數,那麼可不可以固定分子,把分母的倒數作為目標函式呢?一定是可以的,固定分子就是支援向量機使用的策略。

7.1 1.7.1 目標函式優化問題

# 間隔最大化圖例
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
from sklearn import svm
%matplotlib inline
font = FontProperties(fname='/Library/Fonts/Heiti.ttc')

np.random.seed(8) # 保證資料隨機的唯一性

# 構造線性可分資料點
array = np.random.randn(20, 2)
X = np.r_[array-[3, 3], array+[3, 3]]
y = [0]20+[1]20

# 建立svm模型
clf = svm.SVC(kernel='linear')
clf.fit(X, y)

# 構造等網個方陣
x1_min, x1_max = X[:, 0].min(), X[:, 0].max(),
x2_min, x2_max = X[:, 1].min(), X[:, 1].max(),
x1, x2 = np.meshgrid(np.linspace(x1_min, x1_max),
np.linspace(x2_min, x2_max))

# 得到向量w: w_0x_1+w_1x_2+b=0
w = clf.coef_[0]
# 加1後才可繪製 -1 的等高線 [-1,0,1] + 1 = [0,1,2]
f = w[0]x1 + w[1]x2 + clf.intercept_[0] + 1

# 繪製H1,即wx+b=-1
plt.contour(x1, x2, f, [0], colors='k', linestyles='--')
plt.text(2, -4, s='\(H_2={\omega}x+b=-1\)', fontsize=10, color='r', ha='center')

# 繪製分隔超平面,即wx+b=0
plt.contour(x1, x2, f, [1], colors='k')
plt.text(2.5, -2, s='\(\omega{x}+b=0\)', fontsize=10, color='r', ha='center')
plt.text(2.5, -2.5, s='分離超平面', fontsize=10,
color='r', ha='center', fontproperties=font)

# 繪製H2,即wx+b=1
plt.contour(x1, x2, f, [2], colors='k', linestyles='--')
plt.text(3, 0, s='\(H_1=\omega{x}+b=1\)', fontsize=10, color='r', ha='center')

# 繪製資料散點圖
plt.scatter(X[0:20, 0], X[0:20, 1], cmap=plt.cm.Paired, marker='x')
plt.text(1, 1.8, s='支援向量', fontsize=10, color='gray',
ha='center', fontproperties=font)

plt.scatter(X[20:40, 0], X[20:40, 1], cmap=plt.cm.Paired, marker='o')
plt.text(-1.5, -0.5, s='支援向量', fontsize=10,
color='gray', ha='center', fontproperties=font)
# plt.scatter(clf.support_vectors_[:,0],clf.support_vectors_[:,1) # 繪製支援向量點

plt.xlim(x1_min-1, x1_max+1)
plt.ylim(x2_min-1, x2_max+1)
plt.show()

支援向量機的目標函式的最優化問題,即硬間隔最大化為

(11)minω,b12||ω||2(12)s.t.yi(ωxi+b)1,i=1,2,,m

八、1.8 k均值聚類演算法簡介

# k均值聚類演算法簡介舉例
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
from sklearn.datasets import make_classification
%matplotlib inline
font = FontProperties(fname='/Library/Fonts/Heiti.ttc')

X, y = make_classification(
n_samples=500, n_features=20, random_state=1, n_informative=2, shuffle=False)
plt.scatter(X[0:250, [0]], X[0:250, [1]], c='r', s=30)
plt.scatter(X[250:500, [0]], X[250:500, [1]], c='g', s=30)

plt.scatter(2, 1, c='k', s=100)
plt.text(s='初始點1\((2,1)\)', x=2, y=1, fontproperties=font, fontsize=15)
plt.scatter(2, 2, c='b', s=100)
plt.text(s='初始點2\((2,2)\)', x=2, y=2, fontproperties=font, fontsize=15)

plt.scatter(-1.2, 0.2, c='k', s=100)
plt.text(s='中心點1\((-1.2,0.2)\)', x=-1.2, y=0.2, fontproperties=font, fontsize=15)
plt.scatter(1, -0.2, c='b', s=100)
plt.text(s='中心點1\((1,-0.2)\)', x=1, y=-0.2, fontproperties=font, fontsize=15)

plt.show()

以上圖舉例,k均值演算法則是隨機定義兩個點(2,1)(2,2),然後可以使用k均值演算法慢慢收斂,初始點最後會收斂到兩個簇的中心,距離中心點更近的將被劃入中心點代表的簇。(注:此處只是為了方便舉例,並不是使用了真正的k均值演算法聚類)

九、1.9 整合學習簡介

# 整合學習簡介圖例
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.font_manager import FontProperties
%matplotlib inline
font = FontProperties(fname='/Library/Fonts/Heiti.ttc', size=15)

fig1 = plt.figure()
ax1 = fig1.add_subplot(111, aspect='equal')
ax1.add_patch(patches.Rectangle((1, 1), 5, 1.5, color='b'))
plt.text(2.6, 3.5, s='\(\cdots\)', fontsize=30)
ax1.add_patch(patches.Rectangle((1, 5), 5, 1.5, color='b'))
ax1.add_patch(patches.Rectangle((1, 7), 5, 1.5, color='b'))

plt.text(3.5, 7.5, s='個體學習器\(_1\)', fontsize=20, color='white',
ha='center', fontproperties=font)
plt.text(3.5, 5.5, s='個體學習器\(_2\)', fontsize=20, color='white',
ha='center', fontproperties=font)
plt.text(3.5, 1.5, s='個體學習器\(_T\)', fontsize=20, color='white',
ha='center', fontproperties=font)

plt.annotate(s='', xytext=(6, 7.8), xy=(8, 4.7),
arrowprops=dict(arrowstyle="->", connectionstyle="arc3", color='orange'))
plt.annotate(s='', xytext=(6, 5.8), xy=(8, 4.2),
arrowprops=dict(arrowstyle="->", connectionstyle="arc3", color='orange'))
plt.annotate(s='', xytext=(6, 1.7), xy=(8, 4.0),
arrowprops=dict(arrowstyle="->", connectionstyle="arc3", color='orange'))

ax1.add_patch(patches.Rectangle((8, 3.4), 4, 2, color='g'))
plt.text(10, 4.2, s='結合模組', fontsize=20, color='white',
ha='center', fontproperties=font)

plt.annotate(s='', xytext=(12, 4.2), xy=(13, 4.2),
arrowprops=dict(arrowstyle="->", connectionstyle="arc3", color='orange'))
ax1.add_patch(patches.Rectangle((13, 3.4), 4, 2, color='purple'))
plt.text(15, 4.2, s='強學習器', fontsize=20, color='white',
ha='center', fontproperties=font)

plt.annotate(s='', xytext=(17, 4.2), xy=(18, 4.2),
arrowprops=dict(arrowstyle="->", connectionstyle="arc3", color='orange'))
plt.text(19, 4, s='輸出', fontsize=20, color='r',
ha='center', fontproperties=font)

plt.xlim(0, 20)
plt.ylim(0, 10)
plt.show()

如上圖所示,整合學習可以理解成,若干個個體學習器,通過結合策略構造一個結合模組,形成一個強學習器。其中所有的個體學習器中,可以是相同型別也可以是不同型別的個體學習器。

因此為了獲得強學習器,我們首先得獲得若干個個體學習器,之後選擇一種較好的結合策略。

9.1 1.9.1 個體學習器

上一節我們講到,構造強學習器的所有個體學習器中,個體學習器可以是相同型別的也可以是不同型別的,對於相同型別的個體學習器,這樣的整合是同質(homogeneous)的,例如決策樹整合中全是決策樹,神經網路整合中全是神經網路;對於不同型別的個體學習器,這樣的整合是異質(heterogenous)的,例如某個整合中既含有決策樹,又含有神經網路。

目前最流行的是同質整合,在同質整合中,使用最多的模型是CART決策樹和神經網路,並且個體學習器在同質整合中也被稱為弱學習器(weak learner)。按照同質弱學習器之間是否存在依賴關係可以將同質整合分類兩類:第一個是弱學習器之間存在強依賴關係,一系列弱學習器基本都需要序列生成,代表演算法是Boosting系列演算法;第二個是弱學習器之間沒有較強的依賴關係,一系列弱學習器可以並行生成,代表演算法是Bagging系列演算法,Baggin系列演算法中最著名的是隨機森林(random forest)。

9.2 1.9.2 Boosting系列演算法

Boosting是一種可將弱學習器提升為強學習器的演算法。它的工作機制為:先從初始訓練集中訓練出一個弱學習器,再根據弱學習器的表現對訓練樣本分佈進行調整,使得先前弱學習器訓練錯誤的樣本權重變高,即讓錯誤樣本在之後的弱學習器中受到更多關注,然後基於調整後的樣本分佈來訓練下一個弱學習器。

不斷重複上述過程,直到弱學習器數達到事先指定的數目T,最終通過集合策略整合這T個弱學習器,得到最終的強學習器。

Boosting系列演算法中最著名的演算法有AdaBoost演算法和提升樹(boosting tree)系列演算法,提升樹系列演算法中應用最廣泛的是梯度提升樹(gradient boosting tree)。

Boosting由於每一個弱學習器都基於上一個弱學習器,因此它的偏差較小,即模型擬合能力較強,但是模型泛化能力會稍差,即方差偏大,而Boosgting則是需要選擇一個能減小方差的學習器,一般選擇較簡單模型,如選擇深度很淺的決策樹。

9.3 1.9.3 Bagging系列演算法

Boosting的弱學習器之間是有依賴關係的,而Bagging的弱學習器之間是沒有依賴關係的,因此它的弱學習器是並行生成。

Bagging的弱學習器的訓練集是通過隨機取樣得到的。通過T次的隨機取樣,我們可以通過自主取樣法(bootstrap sampling)得到T個取樣集,然後對於這T個取樣集獨立的訓練出T個弱學習器,之後我們通過某種結合策略將這T個弱學習器構造成一個強學習器。

Bagging系列演算法中最著名的演算法有隨機森林,但是隨機森林可以說是一個進階版的Bagging演算法,雖然隨機森林的弱學習器都是決策樹,但是隨機森林在Baggin的樣本隨機取樣的基礎上,又進行了特徵的隨機選擇。

Bagging由於通過隨機取樣獲得資料,因此它的方差較小,即模型泛化能力較強,但是模型擬合能力較弱,即偏差偏大,而Bagging則是需要選擇一個能減小偏差的學習器,一般選擇較複雜模型,如選擇深度很深的決策樹或不剪枝的決策樹。

十、1.10 降維演算法簡介

10.1 1.10.1 維數災難和降維

對於高維資料,會出現資料樣本稀疏、距離計算困難等問題。尤其是在KNN演算法中這種問題會被放大,而其他的機器學習演算法也會因為高維資料對訓練模型造成極大的障礙,這種問題一般被稱為維數災難(curse of dimensionality)。

解決維數災難最常用的方法是降維(dimension reduction),即通過某種數學變換將原始高維特徵空間轉變為一個低維子空間,在這個子空間中樣本密度大幅提高,距離計算也變得更容易。

# 維數災難和降維圖例
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
from sklearn.decomposition import PCA
%matplotlib inline
font = FontProperties(fname='/Library/Fonts/Heiti.ttc')

np.random.seed(0)
X = np.empty((100, 2))
X[:, 0] = np.random.uniform(0, 100, size=100)
X[:, 1] = 0.75 * X[:, 0] + 3. + np.random.normal(0, 10, size=100)
pca = PCA(n_components=1)
X_reduction = pca.fit_transform(X)
X_restore = pca.inverse_transform(X_reduction)

plt.scatter(X[:, 0], X[:, 1], color='g', label='原始資料')
plt.scatter(X_restore[:, 0], X_restore[:, 1],
color='r', label='降維後的資料')
plt.annotate(s='', xytext=(40, 60), xy=(65, 30),
arrowprops=dict(arrowstyle='-', color='b', linewidth=5))
plt.legend(prop=font)
plt.show()

如上圖所示,綠點即原始高維空間中的樣本點,紅點即我們降維後的樣本點。由於圖中的高維是二維,低維是一維,所以樣本在低維空間是一條直線。

接下來我們的目標就是聊一聊如何做到把高維空間樣本點對映到低維空間,即各種降維演算法。

10.2 1.10.2 主成分分析

主成分分析(principal component analysis,PCA)是最常用的一種降維方法,我們已經利用“維數災難和降維圖例”解釋了降維的過程,PCA的降維過程則是儘可能的使用資料最主要的特徵來代表資料原有的所有特徵。但是有沒有同學想過為什麼使用PCA降維是上圖的紅點組成的線而不是藍線呢?這裡就需要說到我們PCA的兩個條件了。

對於“維數災難和降維圖例”中的紅線和藍線我們可以把它看成一個超平面S,理論上紅線和藍線構成的超平面都可以做到對樣本特徵的降維,但是一般我們希望這種能夠做到降維的超平面滿足以下兩個條件

  1. 最近重構性:樣本點到這個超平面的距離都足夠近
  2. 最大可分性:樣本點到這個超平面上的投影儘可能分開

基於最近重構性和最大可分性,就可以得到主成分分析的兩種等價推導,也可以得出為什麼紅線是更合理的超平面。

十一、1.11 本章小結

本章主要是帶大家對傳統機器學習的演算法有一個大概的瞭解,由於神經網路可以理解成多個感知機組成的演算法,此處不多介紹。後期進階課程將會涉及神經網路以及深度學習。

由於本課程片應用,所以演算法都是點到為止,如果需要對演算法原理想要有一個清晰認識的同學,可以看我們未來的進階課程,會詳細介紹,每一個函式的損失函式、目標函式、目標函式優化問題為什麼是這樣的,敬請期待。