1. 程式人生 > >sklearn中支援向量機部分

sklearn中支援向量機部分

寫在開頭:英文原文http://scikit-learn.org/stable/modules/svm.html。

只是對原文做了簡單的翻譯,主要自己學習,能給大家提供幫助就再好不過了。

************************************我是分割線************************************************

1.4 支援向量機(Support Vector Machine

支援向量機主要用於分類(classification)、迴歸(regression)、異常檢測(outliers detection)的監督分類方法。

支援向量機的優點:

能有效的作用於高維資料;

能有效的作用於資料樣本小於資料維數時;

高效利用記憶體,使用訓練集的幾個點作為支援向量;

核函式,將輸入空間變換到新的特徵空間。

支援向量機的一些缺點:

不能很好的處理特徵數遠大於樣本數的資料集;

不能提供概率估計。

sklearn中的svm可支援密向量集合稀疏向量集

1.4.1 分類(classification

▲SVCNuSVC以及LinearSVC可解決多類問題,三種分類器的表現如下


▲SVCNuSVC是相識的模型,但是在引數集和數學模型上略微不同。LinearSVC是一種線性核的分類方法,LinearSVC不接收kernel

引數,為線性核。SVCNuSVC以及LinearSVC以兩個陣列(array)作為輸入:訓練資料集X[n_samples,n_feature],標籤(string/integersY[n_samples]

	>>> from sklearn import svm
	>>> X = [[0, 0], [1, 1]]
	>>> y = [0, 1]
	>>> clf = svm.SVC()
	>>> clf.fit(X, y)  
	SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
	    decision_function_shape=None, degree=3, gamma='auto', kernel='rbf',
	    max_iter=-1, probability=False, random_state=None, shrinking=True,
	    tol=0.001, verbose=False)
	
	訓練完成後,可用於預測新的值
	>>> clf.predict([[2., 2.]])
	array([1])

▲SVMs決策函式取決於訓練集的部分資料,這些屬於支援向量。可通過support_vectors_support_n_support得到

	>>> # get support vectors
	>>> clf.support_vectors_
	array([[ 0.,  0.],
	       [ 1.,  1.]])
	>>> # get indices of support vectors
	>>> clf.support_ 
	array([0, 1]...)
	>>> # get number of support vectors for each class
	>>> clf.n_support_ 
	array([1, 1]...)

1.4.1.1 多類分類(Multi-classclassification

▲SVCNuSVC採用一對一方法實現多類分類。如果n_class是分類的個數,那麼將會構造n_class*(n_class-1)/2個分類器,每個訓練資料將會有被分為兩類To provide a consistent interface withother classifiers, the decision_function_shape option allows to aggregate theresults of the one-against-one classifiers to a decision function of shape (n_samples, n_classes):

	>>> X = [[0], [1], [2], [3]]
	>>> Y = [0, 1, 2, 3]
	>>> clf = svm.SVC(decision_function_shape='ovo')#ovo 一對一
	>>> clf.fit(X, Y) 
	SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
	    decision_function_shape='ovo', degree=3, gamma='auto', kernel='rbf',
	    max_iter=-1, probability=False, random_state=None, shrinking=True,
	    tol=0.001, verbose=False)
	>>> dec = clf.decision_function([[1]])
	>>> dec.shape[1] # 4 classes: 4*3/2 = 6
	6
	>>> clf.decision_function_shape = "ovr"#ovr 一對多
	>>> dec = clf.decision_function([[1]])
	>>> dec.shape[1] # 4 classes
	4

▲LinearSVC利用一對多的方法實現多類分類,因此只需訓練n個模型。


	>>> lin_clf = svm.LinearSVC()
	>>> lin_clf.fit(X, Y) 
	LinearSVC(C=1.0, class_weight=None, dual=True, fit_intercept=True,
	     intercept_scaling=1, loss='squared_hinge', max_iter=1000,
	     multi_class='ovr', penalty='l2', random_state=None, tol=0.0001,
	     verbose=0)
	>>> dec = lin_clf.decision_function([[1]])
	>>> dec.shape[1]
	4

▲LinearSVC提供了多種多分類決策,可通過multi_class = ‘crammer_singer’實現,該方法對one-vs-rest分類不適用。在實際中,首選one-vs-rest分類。

▲對於“one-vs-rest”的LinearSVC的屬性coef_([n_class,n_features])和intercept_([n_class])。

1.4.1.2 分值與概率(Scores andProbabilities)

▲SVC中decis_function模式給每種分類一個分數。當引數probability設定為True時,將會使用概率估計方法(predict_proba和predict_log_proba設定)。在二分問題中,概率校準使用普拉特縮放,對支援向量機的分值採用logistic迴歸,通過交叉驗證進行擬合。

1.4.1.3 不平衡問題(Unbalancedproblems)

▲在某些問題中我們會更加重視一些類或者一些樣本,可使用class_weight和sample_weight來實現

▲SVC中在fit方法中通過關鍵字class_weight來實現。字典形式({class_label : value}),每個value大於0。下圖為線性SVM權值的作用。


相關程式碼:

	# -*- coding: utf-8 -*-
	"""
	Created on Mon Jan  2 10:26:15 2017
	
	@author: ZQ
	"""
	
	import numpy as np
	import matplotlib.pyplot as plt
	from sklearn import svm
	
	rng = np.random.RandomState(0)
	n_samples_1 = 1000
	n_samples_2 = 100
	
	X = np.r_[1.5*rng.randn(n_samples_1,2),
	         0.5*rng.randn(n_samples_2,2) + [2,2]]
	y = [0] * (n_samples_1)+[1]*(n_samples_2)
	
	#擬合模型,並獲得超平面
	clf = svm.SVC(kernel = 'linear',C = 1.0)
	clf.fit(X,y)
	
	w = clf.coef_[0]
	a = -w[0] / w[1]
	xx = np.linspace(-5,5)
	yy = a*xx - clf.intercept_[0]/w[1]
	
	wclf = svm.SVC(kernel = 'linear',class_weight = {1:10})
	wclf.fit(X,y)
	
	ww = wclf.coef_[0]
	wa = -ww[0]/ww[1]
	wyy = wa*xx - wclf.intercept_[0]/ww[1]
	
	h0 = plt.plot(xx,yy,'k-',label = 'no weights')
	h1 = plt.plot(xx,wyy,'k--',label = 'with weights')
	plt.scatter(X[:,0],X[:,1],c = y,cmap = plt.cm.Paired)
	plt.legend()
	plt.axis('tight')
	plt.show()

▲SVCNuSVCSVRNuSVR以及OneClassSVM同樣可在fit方法中,使用samp_weight引數對個別樣本權重進行賦值。如下圖,左邊無權重,右邊有權重。



相關程式碼:

	# -*- coding: utf-8 -*-
	"""
	Created on Mon Jan  2 11:10:48 2017
	
	@author: ZQ
	"""
	import numpy as np
	import matplotlib.pyplot as plt
	from sklearn import svm
	
	def plot_decision_function(classifier,sample_weight,axis,title):
	    xx,yy = np.meshgrid(np.linspace(-4,5,500),np.linspace(-4,5,500))
	    
	    Z = classifier.decision_function(np.c_[xx.ravel(),yy.ravel()])
	    Z = Z.reshape(xx.shape)
	    
	    axis.contourf(xx,yy,Z,alpha = 0.75,cmap = plt.cm.bone)
	    axis.scatter(X[:,0],X[:,1],c=y,s=100*sample_weight,alpha = 0.9,
	                 cmap = plt.cm.bone)
	    axis.axis('off')
	    axis.set_title(title)
	    
	np.random.seed(0)
	X = np.r_[np.random.randn(10,2)+[1,1],np.random.randn(10,2)]
	y = [1]*10+[-1]*10
	
	sample_weight_last_ten = abs(np.random.randn(len(X)))
	sample_weight_constant = np.ones(len(X))
	sample_weight_last_ten[15:] *= 5
	sample_weight_last_ten[9] *= 15
	
	
	clf_weights = svm.SVC()
	clf_weights.fit(X,y,sample_weight = sample_weight_last_ten)
	clf_no_weights = svm.SVC()
	clf_no_weights.fit(X,y)
	
	fig,axes = plt.subplots(1,2,figsize = (14,6))
	plot_decision_function(clf_no_weights,sample_weight_constant,axes[0],'Constant weights')
	plot_decision_function(clf_weights,sample_weight_last_ten,axes[1],'Modified weights')
	plt.show()

1.4.2 迴歸(regression

支援向量分類方法,還可以擴充套件為支援向量迴歸。

支援向量分類只是取決於訓練集的部分資料,因為成本函式只是關心間隔上的資料。類似地,支援向量迴歸也是利用部分訓練資料集,成本函式同樣會忽略接近預測模型的訓練資料集。

提供了三種不同的支援向量迴歸:SVRNuSVR以及LinearSVR。線性SVR比非線性的快。

▲fit方法需要Xy引數,只有在這個例子中y是浮點型別。

	>>> from sklearn import svm
	>>> X = [[0, 0], [2, 2]]
	>>> y = [0.5, 2.5]
	>>> clf = svm.SVR()
	>>> clf.fit(X, y) 
	SVR(C=1.0, cache_size=200, coef0=0.0, degree=3, epsilon=0.1, gamma='auto',
	    kernel='rbf', max_iter=-1, shrinking=True, tol=0.001, verbose=False)
	>>> clf.predict([[1, 1]])
	array([ 1.5])

線性和非線性SVR例子,對同一資料,其結果如下:


從中可看出基於高斯核的擬合效果最好。

相關程式碼:


	# -*- coding: utf-8 -*-
	"""
	Created on Mon Jan  2 16:09:49 2017
	
	@author: ZQ
	"""
	
	import numpy as np
	from sklearn.svm import SVR
	import matplotlib.pyplot as plt
	
	#generate sample data
	X = np.sort(5 * np.random.rand(40,1),axis = 0)
	y = np.sin(X).ravel()
	
	#Add noise to targets
	y[::5] += 3*(0.5 - np.random.rand(8))
	
	#fit regression model擬合迴歸模型
	svr_rbf = SVR(kernel = 'rbf',C = 1e3,gamma = 0.1)
	svr_lin = SVR(kernel = 'linear',C = 1e3)
	svr_poly = SVR(kernel = 'poly',C = 1e3,degree = 2)
	y_rbf = svr_rbf.fit(X,y).predict(X)
	y_lin = svr_lin.fit(X,y).predict(X)
	y_poly = svr_poly.fit(X,y).predict(X)
	
	#result 結果
	lw = 2
	plt.scatter(X,y,color = 'r',label = 'data')
	#When hold is True, subsequent plot commands will be added to the current axes. When hold is False, the current axes and figure will be cleared on the next plot command.
	plt.hold('on')
	plt.plot(X,y_rbf,color = 'navy',lw = lw,label = 'RBF model')
	plt.plot(X,y_lin,color = 'c',lw = lw,label = 'Linear model')
	plt.plot(X,y_poly,color = 'blue',lw = lw,label = 'Polynomial model')
	plt.xlabel('data')
	plt.ylabel('target')
	plt.title('SVR')
	plt.legend()
	plt.show()

1.4.3 密度估計,異常檢測(Density estimation,novelty detection)

▲ 一種型別的SVM模型可以用於新型別檢測,該模型可以檢測出資料集的軟邊界,從而識別新的點是否屬於該型別。該情況屬於無監督學習,只使用X陣列作為擬合數據的輸入,無標籤。


相關程式碼:

	# -*- coding: utf-8 -*-
	"""
	Created on Mon Jan  2 16:58:07 2017
	
	@author: ZQ
	"""
	
	import numpy as np
	import matplotlib.pyplot as plt
	import matplotlib.font_manager
	from sklearn import svm
	
	xx,yy = np.meshgrid(np.linspace(-5,5,500),np.linspace(-5,5,500))
	
	#generate train data
	
	X = 0.3*np.random.rand(100,2)
	X_train = np.r_[X + 2,X - 2]
	#generate some regular novel observations
	X = 0.3*np.random.rand(20,2)
	X_test = np.r_[X + 2,X - 2]
	X_outliers = np.random.uniform(low = -4,high = 4,size = (20,2))
	
	#fit the model
	clf = svm.OneClassSVM(nu = 0.1,kernel = 'rbf',gamma = 0.1)
	clf.fit(X_train)
	y_pred_train = clf.predict(X_train)
	y_pred_test = clf.predict(X_test)
	y_pred_outliers = clf.predict(X_outliers)
	n_error_train = y_pred_train[y_pred_train == -1].size
	n_error_test = y_pred_test[y_pred_test == -1].size
	n_error_outliers = y_pred_outliers[y_pred_outliers == 1].size
	
	Z = clf.decision_function(np.c_[xx.ravel(),yy.ravel()])
	Z = Z.reshape(xx.shape)
	
	plt.title('Novelty Detection')
	plt.contourf(xx,yy,Z,levels = np.linspace(Z.min(),0,7),cmap = plt.cm.PuBu)
	a = plt.contour(xx,yy,Z,levels = [0],linewidths = 2,colors = 'darkred')
	plt.contourf(xx,yy,Z,levels = [0,Z.max()],color = 'palevioletred')
	
	s = 40
	b1 = plt.scatter(X_train[:,0],X_train[:,1],c = 'white',s = s)
	b2 = plt.scatter(X_test[:,0],X_test[:,1], c = 'blueviolet', s = s)
	c = plt.scatter(X_outliers[:,0],X_outliers[:,1],c = 'gold',s = s)
	plt.axis('tight')
	plt.xlim((-5,5))
	plt.ylim((-5,5))
	plt.legend([a.collections[0], b1, b2, c],
	           ["learned frontier", "training observations",
	            "new regular observations", "new abnormal observations"],
	           loc="upper left",
	           prop=matplotlib.font_manager.FontProperties(size=11))
	plt.xlabel(
	    "error train: %d/200 ; errors novel regular: %d/40 ; "
	    "errors novel abnormal: %d/40"
	    % (n_error_train, n_error_test, n_error_outliers))
	plt.show()

1.4.4  複雜性(complexity)

▲雖然支援向量機是強有力的工具,但是其時間和空間複雜度會隨著訓練集的增加而快速的增加。SVM的核心是二次規劃問題,從訓練資料中把支援向量分離出來。如果資料集很稀疏時需要注意相關問題(這感覺不能太好的解釋)(http://scikit-learn.org/stable/modules/svm.html#unbalanced-problems)。此外,還要說明一點,LinearSVC比基於libsvm的SVC更高效。

1.4.5 實際運用中的一些技巧(Tips on practical use)

▲ 避免複製資料(Avoiding data copy):對於SVC,SVR,NuSVC以及NuSVR,如果資料在傳遞到這些方法時,使用的資料不是C語言格式的連續區域以及雙精度的話,那麼在呼叫底層C語言實現之前,資料會被拷貝。

     對於LinearSVC(LogisticRegres)任何以numpy中array陣列形式的資料將會轉變為稀疏矩陣表示(liblinearinternal sparse data representation 。如果不想轉換,建議使用SGDClassifier。

▲核快取大小(Kernel cache size):對於SVC,SVR,nuSVC和NuSVR,核快取的大小將會解決大問題的時間。如果有足夠的記憶體,可以通過cache_size引數提高核記憶體。

▲設定C引數(Setting C):預設值為1,在噪聲較多的情況下可以適當的降低。

▲增加資料(Scale data)

▲在NuSVC/OneClassSVM/NuSVR中,引數nu幾乎接近訓練誤差和支援向量的比值

▲在SVC中,如果資料分類不平衡,設定class_weight = 'balanced' 或者使用不同的引數C

▲在擬合LinearSVC模型時,採用隨機生產數的方式去選擇特徵。因此對於相同的資料可能有不同的結果,可減小tol引數避免

▲略。。。。

1.4.6 核方法(kernel functions)

▲核方法有如下幾種:

線性核(linear):<x,x'>

多項式核(polynomial):(r<x,x'>+r)d 其中d由degree引數指定,r由引數coef0指定

高斯核(rbf):exp(-r|x - x'|^2).r由引數gamma指定,必須大於0

sigmod核(tanh(r<x,x'>+r)),r由引數coef指定

▲初始化時核關鍵字指定不同的核方法

	>>> linear_svc = svm.SVC(kernel='linear')
	>>> linear_svc.kernel
	'linear'
	>>> rbf_svc = svm.SVC(kernel='rbf')
	>>> rbf_svc.kernel
	'rbf'