如何用Python實現常見機器學習算法-4


四、SVM支持向量機

1、代價函數

在邏輯回歸中,我們的代價為:

其中:

如圖所示,如果y=1,cost代價函數如圖所示

我們想讓,即z>>0,這樣的話cost代價函數才會趨於最小(這正是我們想要的),所以用圖中紅色的函數代替邏輯回歸中的cost

 當y=0時同樣用代替

最終得到的代價函數為:

最后我們想要

之前我們邏輯回歸中的代價函數為:

可以認為這里的,只是表達形式問題,這里C的值越大,SVM的決策邊界的margin也越大,下面會說明。

2、Large Margin

如下圖所示,SVM分類會使用最大的margin將其分開

先說一下向量內積

表示U的歐幾里德范數(歐式范數),

向量V在向量U上的投影的長度記為p,則:向量內積:

根據向量夾角公式推導一即可,

前面說過,當C越大時,margin也就越大,我們的目的是最小化代價函數J(θ),當margin最大時,C的乘積項

要很小,所以金絲猴為:

我們最后的目的就是求使代價最小的θ

可以得到:

p即為x在θ上的投影

如下圖所示,假設決策邊界如圖,找其中的一個點,到θ上的投影為p,則或者,若是p很小,則需要很大,這與我們要求的θ使最小相違背,所以最后求的是large margin

3、SVM Kernel(核函數)

對於線性可分的問題,使用線性核函數即可

對於線性不可分的問題,在邏輯回歸中,我們是將feature映射為使用多項式的形式,SVM中也有多項式核函數,但是更常用的是高斯核函數,也稱為RBF核

高斯核函數為:

假設如圖幾個點,

令:

可以看出,若是x與距離較近,可以推出,(即相似度較大);

若是x與距離較遠,可以推出,(即相似度較低)。

高斯核函數的σ越小,f下降的越快

如何選擇初始的

訓練集:

選擇:

對於給出的x,計算f,令:

所以:

最小化J求出θ,

 

如果,==》預測y=1

4、使用scikit-learn中的SVM模型代碼

全部代碼

 1 import numpy as np
 2 from scipy import io as spio
 3 from matplotlib import pyplot as plt
 4 from sklearn import svm
 5 
 6 def SVM():
 7     '''data1——線性分類'''
 8     data1 = spio.loadmat('data1.mat')
 9     X = data1['X']
10     y = data1['y']
11     y = np.ravel(y)
12     plot_data(X,y)
13     
14     model = svm.SVC(C=1.0,kernel='linear').fit(X,y) # 指定核函數為線性核函數
15     plot_decisionBoundary(X, y, model)  # 畫決策邊界
16     '''data2——非線性分類'''
17     data2 = spio.loadmat('data2.mat')
18     X = data2['X']
19     y = data2['y']
20     y = np.ravel(y)
21     plt = plot_data(X,y)
22     plt.show()
23     
24     model = svm.SVC(gamma=100).fit(X,y)     # gamma為核函數的系數,值越大擬合的越好
25     plot_decisionBoundary(X, y, model,class_='notLinear')   # 畫決策邊界
26     
27     
28     
29 # 作圖
30 def plot_data(X,y):
31     plt.figure(figsize=(10,8))
32     pos = np.where(y==1)    # 找到y=1的位置
33     neg = np.where(y==0)    # 找到y=0的位置
34     p1, = plt.plot(np.ravel(X[pos,0]),np.ravel(X[pos,1]),'ro',markersize=8)
35     p2, = plt.plot(np.ravel(X[neg,0]),np.ravel(X[neg,1]),'g^',markersize=8)
36     plt.xlabel("X1")
37     plt.ylabel("X2")
38     plt.legend([p1,p2],["y==1","y==0"])
39     return plt
40     
41 # 畫決策邊界
42 def plot_decisionBoundary(X,y,model,class_='linear'):
43     plt = plot_data(X, y)
44     
45     # 線性邊界        
46     if class_=='linear':
47         w = model.coef_
48         b = model.intercept_
49         xp = np.linspace(np.min(X[:,0]),np.max(X[:,0]),100)
50         yp = -(w[0,0]*xp+b)/w[0,1]
51         plt.plot(xp,yp,'b-',linewidth=2.0)
52         plt.show()
53     else:  # 非線性邊界
54         x_1 = np.transpose(np.linspace(np.min(X[:,0]),np.max(X[:,0]),100).reshape(1,-1))
55         x_2 = np.transpose(np.linspace(np.min(X[:,1]),np.max(X[:,1]),100).reshape(1,-1))
56         X1,X2 = np.meshgrid(x_1,x_2)
57         vals = np.zeros(X1.shape)
58         for i in range(X1.shape[1]):
59             this_X = np.hstack((X1[:,i].reshape(-1,1),X2[:,i].reshape(-1,1)))
60             vals[:,i] = model.predict(this_X)
61         
62         plt.contour(X1,X2,vals,[0,1],color='blue')
63         plt.show()
64     
65 
66 if __name__ == "__main__":
67     SVM()

 

線性可分的代碼,指定核函數為linear:

1 '''data1——線性分類'''
2     data1 = spio.loadmat('data1.mat')
3     X = data1['X']
4     y = data1['y']
5     y = np.ravel(y)
6     plot_data(X,y)
7     
8     model = svm.SVC(C=1.0,kernel='linear').fit(X,y) # 指定核函數為線性核函數
9     plot_decisionBoundary(X, y, model)  # 畫決策邊界

非線性可分的代碼,默認核函數為rbf

 1 '''data2——非線性分類'''
 2     data2 = spio.loadmat('data2.mat')
 3     X = data2['X']
 4     y = data2['y']
 5     y = np.ravel(y)
 6     plt = plot_data(X,y)
 7     plt.show()
 8     
 9     model = svm.SVC(gamma=100).fit(X,y)     # gamma為核函數的系數,值越大擬合的越好
10     plot_decisionBoundary(X, y, model,class_='notLinear')   # 畫決策邊界

5、運行結果

線性可分的決策邊界:

線性不可分的決策邊界:

五、K-Means聚類算法

1、聚類過程

聚類屬於無監督學習,不知道y的標記分為K類

K-Means算法分為兩個步驟

第一步:簇分配,隨機選K個點作為中心,計算到這K個點的距離,分為K個簇;

第二步:移動聚類中心,重新計算每個簇的中心,移動中心,重復以上步驟。

如下圖所示

隨機分配聚類中心:

重新計算聚類中心,移動一次

最后10步之后的聚類中心

計算每條數據到哪個中心最近的代碼如下:

 1 # 找到每條數據距離哪個類中心最近    
 2 def findClosestCentroids(X,initial_centroids):
 3     m = X.shape[0]                  # 數據條數
 4     K = initial_centroids.shape[0]  # 類的總數
 5     dis = np.zeros((m,K))           # 存儲計算每個點分別到K個類的距離
 6     idx = np.zeros((m,1))           # 要返回的每條數據屬於哪個類
 7     
 8     '''計算每個點到每個類中心的距離'''
 9     for i in range(m):
10         for j in range(K):
11             dis[i,j] = np.dot((X[i,:]-initial_centroids[j,:]).reshape(1,-1),(X[i,:]-initial_centroids[j,:]).reshape(-1,1))
12     
13     '''返回dis每一行的最小值對應的列號,即為對應的類別
14     - np.min(dis, axis=1)返回每一行的最小值
15     - np.where(dis == np.min(dis, axis=1).reshape(-1,1)) 返回對應最小值的坐標
16      - 注意:可能最小值對應的坐標有多個,where都會找出來,所以返回時返回前m個需要的即可(因為對於多個最小值,屬於哪個類別都可以)
17     '''  
18     dummy,idx = np.where(dis == np.min(dis, axis=1).reshape(-1,1))
19     return idx[0:dis.shape[0]]  # 注意截取一下

計算類中心代碼實現:

1 # 計算類中心
2 def computerCentroids(X,idx,K):
3     n = X.shape[1]
4     centroids = np.zeros((K,n))
5     for i in range(K):
6         centroids[i,:] = np.mean(X[np.ravel(idx==i),:], axis=0).reshape(1,-1)   # 索引要是一維的,axis=0為每一列,idx==i一次找出屬於哪一類的,然后計算均值
7     return centroids

2、目標函數

也叫做失真代價函數

最后我們想得到:

其中表示i條數據距離哪個類中心最近,其中即為聚類的中心

3、聚類中心的選擇

隨機初始化,從給定的數據中隨機抽取K個作為聚類中心

隨機一次的結果可能不好,可以隨機多次,最后取使代價函數最小的作為中心。

代碼實現:(這里隨機一次)

1 # 初始化類中心--隨機取K個點作為聚類中心
2 def kMeansInitCentroids(X,K):
3     m = X.shape[0]
4     m_arr = np.arange(0,m)      # 生成0-m-1
5     centroids = np.zeros((K,X.shape[1]))
6     np.random.shuffle(m_arr)    # 打亂m_arr順序    
7     rand_indices = m_arr[:K]    # 取前K個
8     centroids = X[rand_indices,:]
9     return centroids

4、聚類個數K的選擇

聚類是不知道y的label的,所以也不知道真正的聚類個數

肘部法則(Elbow method)

做代價函數J和K的圖,若是出現一個拐點,如下圖所示,K就取拐點處的值,下圖顯示K=3

若是很平滑就不明確,人為選擇。

第二種就是人為觀察選擇

5、應用-圖片壓縮

將圖片的像素分為若干類,然后用這個類代替原來的像素值。

執行聚類的算法代碼:

 1 # 聚類算法
 2 def runKMeans(X,initial_centroids,max_iters,plot_process):
 3     m,n = X.shape                   # 數據條數和維度
 4     K = initial_centroids.shape[0]  # 類數
 5     centroids = initial_centroids   # 記錄當前類中心
 6     previous_centroids = centroids  # 記錄上一次類中心
 7     idx = np.zeros((m,1))           # 每條數據屬於哪個類
 8     
 9     for i in range(max_iters):      # 迭代次數
10         print u'迭代計算次數:%d'%(i+1)
11         idx = findClosestCentroids(X, centroids)
12         if plot_process:    # 如果繪制圖像
13             plt = plotProcessKMeans(X,centroids,previous_centroids) # 畫聚類中心的移動過程
14             previous_centroids = centroids  # 重置
15         centroids = computerCentroids(X, idx, K)    # 重新計算類中心
16     if plot_process:    # 顯示最終的繪制結果
17         plt.show()
18     return centroids,idx    # 返回聚類中心和數據屬於哪個類

6、使用scikit-learn庫中的線性模型實現聚類

 1 import numpy as np
 2 from scipy import io as spio
 3 from matplotlib import pyplot as plt
 4 from sklearn.cluster import KMeans
 5 
 6 def kMenas():
 7     data = spio.loadmat("data.mat")
 8     X = data['X']   
 9     model = KMeans(n_clusters=3).fit(X) # n_clusters指定3類,擬合數據
10     centroids = model.cluster_centers_  # 聚類中心
11     
12     plt.scatter(X[:,0], X[:,1])     # 原數據的散點圖
13     plt.plot(centroids[:,0],centroids[:,1],'r^',markersize=10)  # 聚類中心
14     plt.show()
15 
16 if __name__ == "__main__":
17     kMenas()

7、運行結果

二維數據中心的移動

圖片壓縮


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM