用Scikit-learn和TensorFlow进行机器学习(五)
文章目錄
- 支持向量機(jī)(SVM)
- 一、線性支持向量機(jī)分類
- 1、硬間隔分類
- 2、軟間隔分類
- 二、非線性支持向量機(jī)分類
- 1、多項式核(Polynomial Kernel)
- 2、增加相似特征
- 3、計算復(fù)雜度
- 三、SVM回歸
- 1、線性SVM回歸
- 2、非線性SVM回歸
- 四、SVM理論
支持向量機(jī)(SVM)
可做線性或者非線性的分類、回歸,甚至異常值檢測。
適用于:復(fù)雜但中小規(guī)模數(shù)據(jù)集的分類問題。
一、線性支持向量機(jī)分類
1、硬間隔分類
左圖雖紅線和紫線都可以區(qū)分不同類別,但是兩條直線都非常靠近樣本,如果有新的樣本加入,有比較大的可能會分類錯誤。
右圖為線性SVM結(jié)果,其的**思想:決策邊界在正確分類的同時離最近的樣本盡可能的遠(yuǎn)。**而這些最近的樣本(途中虛線上的點)即為支持向量(support vector)。因此只要沒有點在這些點劃分的區(qū)域之間,決策邊界就只由這些支持向量所決定。
注意:SVM對特征縮放敏感==》需先進(jìn)行
不足:
- 只適用于線性可分?jǐn)?shù)據(jù)集;
- 對異常值敏感,eg:如下圖所示
2、軟間隔分類
在sklearn中的SVM類,用 C 超參數(shù)(懲罰系數(shù),松弛因子) 來控制軟的程度:較小的 C 會導(dǎo)致更大的 “間隔”,但更多的“間隔”違規(guī)。
實現(xiàn):鳶尾花( Iris) 數(shù)據(jù)集, 縮放特征, 并訓(xùn)練一個線性 SVM 模型( 使用 LinearSVC 類, 超參數(shù) C=1 , hinge 損失函數(shù)) 來檢測 Virginica 鳶尾花, 生成的模型。
import numpy as np from sklearn import datasets from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler from sklearn.svm import LinearSVCiris = datasets.load_iris() x = iris["data"][:,(2, 3)] # petal length, petal width y = (iris["target"] == 2).astype(np.float64)svm_clf = Pipeline((("scaler", StandardScaler()),("linear_svc",LinearSVC(C=1, loss="hinge")) )) svm_clf.fit(x, y) predict = svm_clf.predict([[5.5, 1.7]]) print(predict)輸出結(jié)果
[1.]注意:
- SVM分類器不像 Logistic 回歸分類器一樣有 predict_proba() 方法來計算得分(概率),因為SVM只是靠支持向量來構(gòu)建決策線。
- loss函數(shù)一定要記得填 hinge,因為默認(rèn)不是 hinge。
不同實現(xiàn):
- SVC類 svc(kernel="linear", C=1),在較大訓(xùn)練集上慢,不推薦;
- SGDClassifier 類,SGDClassifier(loss="hinge", alpha=1/(m*C)),這種使用隨機(jī)梯度下降方法來訓(xùn)練SVM,雖然沒有LinearSVC收斂快,但是能夠處理數(shù)據(jù)量龐大的訓(xùn)練集,而且能夠在線學(xué)習(xí)。
二、非線性支持向量機(jī)分類
處理非線性數(shù)據(jù)集方法:
- 增加更多的特征(eg:多項式特征,然后采用線性SVM。例如添加 x2、x3x^2、x^3x2、x3 特征)
- 直接采用多項式的kernel,直接進(jìn)行非線性SVM的分類。
注意:
- SVC中的 參數(shù)C 越大,對于訓(xùn)練集來說,其誤差越小,但是很容易發(fā)生過擬合;C 越小,則允許有更多的訓(xùn)練集誤分類,相當(dāng)于soft margin。
- SVC中的 參數(shù)coef0 反映了高階多項式相對于低階多項式對模型的影響,如果發(fā)生了過擬合的現(xiàn)象,則可以減小 coef0;如果發(fā)生了欠擬合的現(xiàn)象,可以試著增大 coef0
1、多項式核(Polynomial Kernel)
from sklearn.datasets import make_moons from sklearn.pipeline import Pipeline from sklearn.preprocessing import PolynomialFeaturespolynomial_svm_clf = Pipeline((# 多項式特征("poly_features", PolynomialFeatures(degree=3)),("scaler", StandardScaler()),("svm_clf", LinearSVC(C=10, loss="hinge")) )) polynomial_svm_clf.fit(X, y)增加多項式特征來進(jìn)行非線性分類。但是如果degree設(shè)置的比較小,則比較難分類比較復(fù)雜的數(shù)據(jù);如果degree設(shè)置的比較大,產(chǎn)生了大量模型,導(dǎo)致訓(xùn)練的非常慢。
解決方法:“核技巧(Kernel Trick)”
使用 3 階( degree=3 )的多項式核訓(xùn)練一個SVM分類器,超參數(shù) coef0 控制I高階多項式與低階多項式對模型的影響。
輸出結(jié)果
==》超參數(shù)優(yōu)化:網(wǎng)格搜素
不同參數(shù)的影響
from sklearn.svm import SVCpoly_kernel_svm_clf = Pipeline([("scaler", StandardScaler()),("svm_clf", SVC(kernel="poly", degree=3, coef0=1, C=0.5)) ]) poly_kernel_svm_clf.fit(x, y) plt.figure(figsize=(9, 3)) plt.subplot(131) plot_dataset(x, y, [-1.5, 2.5, -1, 1.5]) plot_predict(poly_kernel_svm_clf, [-1.5, 2.5, -1, 1.5])poly_kernel_svm_clf = Pipeline([("scaler", StandardScaler()),("svm_clf", SVC(kernel="poly", degree=3, coef0=1, C=10)) ]) poly_kernel_svm_clf.fit(x, y) plt.subplot(132) plot_dataset(x, y, [-1.5, 2.5, -1, 1.5]) plot_predict(poly_kernel_svm_clf, [-1.5, 2.5, -1, 1.5])poly_kernel_svm_clf = Pipeline([("scaler", StandardScaler()),("svm_clf", SVC(kernel="poly", degree=3, coef0=100, C=0.5)) ]) poly_kernel_svm_clf.fit(x, y) plt.subplot(133) plot_dataset(x, y, [-1.5, 2.5, -1, 1.5]) plot_predict(poly_kernel_svm_clf, [-1.5, 2.5, -1, 1.5])plt.show()2、增加相似特征
思路:使用相似函數(shù)(similarity function)計算每個樣本與特定地表(landmark)的相似度。
此處,定義相似函數(shù):高斯徑向基函數(shù)(Gaussian Radial Basis Function,RBF),設(shè)置 γ=0.3\gamma=0.3γ=0.3
Gaussian徑向基函數(shù):
Φγ(x,l)=e(?γ∣∣x?l∣∣2)\Phi_\gamma(x,l)=e^{(-\gamma||x-l||^2)}Φγ?(x,l)=e(?γ∣∣x?l∣∣2)
其中,lll 表示地標(biāo),最簡單的地標(biāo)的選擇方法:在數(shù)據(jù)集中的每一個樣本的位置創(chuàng)建地標(biāo),在轉(zhuǎn)換特征之后,需刪除原始特征。缺點:當(dāng)訓(xùn)練集非常大,轉(zhuǎn)換后特征也非常大。
==》解決方法:高斯 RBF 核
當(dāng)數(shù)據(jù)在低維空間中不可分割的時候,可以嘗試將它們映射到高維空間,通過核函數(shù)來進(jìn)行這樣的映射操作。
增大 γ 使鐘型曲線更窄) , 導(dǎo)致每個樣本的影響范圍變得更小: 即判定邊界最終變得更不規(guī)則, 在單個樣本周圍環(huán)繞。 相反的, 較小的 γ 值使鐘型曲線更寬, 樣本有更大的影響范圍, 判定邊界最終則更加平滑。
==》 γ 是可調(diào)整的超參數(shù): 如果模型過擬合, 你應(yīng)該減小 γ 值, 若欠擬合, 則增大 γ ( 與超參數(shù) C 相似) 。
其他核函數(shù):字符串核(String Kernels)、SSK核、編輯距離的核函數(shù)。
核函數(shù)的選擇:一般先嘗試線性核函數(shù)(Linear比SVC(kernel=“l(fā)inear”)要快得多),尤其是訓(xùn)練集很大或有大量特征的情況下。若訓(xùn)練集不太大,則嘗試高斯徑向基核,其對大多數(shù)情況下都很有效。
3、計算復(fù)雜度
LinearSVC 類基于 liblinear 庫,是線性 SVM 的優(yōu)化算法,不支持核技巧,訓(xùn)練時間復(fù)雜度大約為 O(m×n)O(m × n)O(m×n),mmm 為樣本個數(shù),nnn 為特征數(shù)。
SVC 類基于 libsvm 庫,支持核技巧。訓(xùn)練時間復(fù)雜度:介于 O(m2×n)和O(m3×n)O(m^2\times n) 和 O(m^3\times n)O(m2×n)和O(m3×n) 之間。適用于:復(fù)雜但小型或中等數(shù)量的數(shù)據(jù)集。可以對特征數(shù)量進(jìn)行縮放,尤其是稀疏特征(sparse features)。
三、SVM回歸
SVM也可以用于回歸問題,有線性SVM與非線性SVM回歸。
SVM回歸任務(wù)是限制間隔違規(guī)情況下,盡量放置更多的樣本在“間隔(margin)”上,“間隔(margin)”由超參數(shù) ?\epsilon? 控制。在間隔之內(nèi)添加數(shù)據(jù)樣本不會影響模型的預(yù)測,因此這個模型認(rèn)為是不敏感的(??insensitive\epsilon-insensitive??insensitive)
1、線性SVM回歸
np.random.seed(42) m = 50 X = 2 * np.random.rand(m, 1) y = (4 + 3 * X + np.random.randn(m, 1)).ravel()## 找到訓(xùn)練集中所有支持向量的下標(biāo) def find_support_vectors(svm_reg, X, y):y_pred = svm_reg.predict(X)off_margin = np.abs(y - y_pred) >= svm_reg.epsilon## 返回 off_margin 中值為 True 的下標(biāo)return np.argwhere(off_margin)def plot_svm_regression(svm_reg, X, y, axes):x1s = np.linspace(axes[0], axes[1], 100).reshape(-1, 1)y_pred = svm_reg.predict(x1s)plt.plot(x1s, y_pred, "r-", linewidth=2, label="$\hat{y}$")plt.plot(x1s, y_pred - svm_reg.epsilon, "k--")plt.plot(x1s, y_pred + svm_reg.epsilon, "k--")plt.plot(X, y, "bo")plt.scatter(X[svm_reg.support_], y[svm_reg.support_], s=180, facecolors="#FFAAAA")plt.xlabel(r"$x_1$", fontsize=18)plt.legend(loc="upper left", fontsize=18)plt.axis(axes)svm_reg_1 = LinearSVR(epsilon=1.5, random_state=2019) svm_reg_2 = LinearSVR(epsilon=0.5, random_state=2019) svm_reg_1.fit(X, y) svm_reg_2.fit(X, y)svm_reg_1.support_ = find_support_vectors(svm_reg_1, X, y) svm_reg_2.support_ = find_support_vectors(svm_reg_2, X, y)eps_x1 = 1 eps_y_pred = svm_reg_1.predict([[eps_x1]]) plt.figure(figsize=(8, 3)) plt.subplot(121) plot_svm_regression(svm_reg_1, X, y, [0, 2, 3, 11]) plt.title(r"$\epsilon={}$".format(svm_reg_1.epsilon), fontsize=18) plt.ylabel(r"$y$", fontsize=18, rotation=0) plt.annotate('', xy=(eps_x1, eps_y_pred), xycoords='data',xytext=(eps_x1, eps_y_pred - svm_reg_1.epsilon),textcoords='data', arrowprops={'arrowstyle':'<->','linewidth':1.5} ) plt.text(0.9, 5.6, r"$\epsilon$",fontsize=20)plt.subplot(122) plot_svm_regression(svm_reg_2, X, y, [0, 2, 3, 11]) plt.title(r"$\epsilon={}$".format(svm_reg_2.epsilon), fontsize=18) plt.show()2、非線性SVM回歸
多項式回歸,指定SVM的kernel為poly即可
from sklearn.svm import SVRnp.random.seed(42) m = 100 X = 2 * np.random.rand(m, 1) - 1 y = (0.2 + 0.1 * X + 0.5 * X ** 2 + np.random.randn(m, 1)/10).ravel() # svm_poly_reg1 = SVR(kernel="poly", degree=2, C=100, epsilon=0.1) svm_poly_reg2 = SVR(kernel="poly", degree=2, C=0.01, epsilon=0.1) svm_poly_reg1.fit(X, y) svm_poly_reg2.fit(X, y)plt.figure(figsize=(8, 3)) plt.subplot(121) plot_svm_regression(svm_poly_reg1, X, y, [-1, 1, 0, 1]) plt.title(r"$degree={}, C={}, \epsilon={}$".format(svm_poly_reg1.degree, svm_poly_reg1.C, svm_poly_reg1.epsilon), fontsize=18) plt.ylabel(r"$y$", fontsize=18, rotation=0) plt.subplot(122) plot_svm_regression(svm_poly_reg2, X, y, [-1, 1, 0, 1]) plt.title(r"$degree={}, C={}, \epsilon={}$".format(svm_poly_reg2.degree, svm_poly_reg2.C, svm_poly_reg2.epsilon), fontsize=18) plt.show()四、SVM理論
(待補(bǔ)充)
總結(jié)
以上是生活随笔為你收集整理的用Scikit-learn和TensorFlow进行机器学习(五)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用Scikit-learn和Tensor
- 下一篇: 【LeetCode】732. 我的日程安