四、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、運行結果
二維數據中心的移動
圖片壓縮