提起筆來寫這篇博客,忽然有點愧疚和尷尬。愧疚的是,工做瑣事多,加之懶癌嚴重,致使這個系列一直沒有更新,向關注該系列的同窗們道個歉。尷尬的是,按理說,機器學習介紹與算法一覽應該放在最前面寫,詳細的應用建議應該在講完機器學習經常使用算法以後寫,忽然莫名奇妙在中間插播這麼一篇,好像有點打亂主線。
老話說『亡羊補牢,爲時未晚』,前面開頭忘講的東西,咱在這塊兒補上。咱們先帶着你們過一遍傳統機器學習算法,基本思想和用途。把問題解決思路和方法應用建議提早到這裏的想法也很簡單,但願能提早給你們一些小建議,對於某些容易出錯的地方也先給你們打個預防針,這樣在理解後續相應機器學習算法以後,使用起來也有必定的章法。html
按照不一樣的分類標準,能夠把機器學習的算法作不一樣的分類。python
咱們先從機器學習問題自己分類的角度來看,咱們能夠分紅下列類型的算法:git
機器學習中有一大部分的問題屬於『監督學習』
的範疇,簡單口語化地說明,這類問題中,給定的訓練樣本中,每一個樣本的輸入xx都對應一個肯定的結果yy,咱們須要訓練出一個模型(數學上看是一個x→yx→y的映射關係ff),在未知的樣本x′x′給定後,咱們能對結果y′y′作出預測。算法
這裏的預測結果若是是離散值(不少時候是類別類型,好比郵件分類問題中的垃圾郵件/普通郵件,好比用戶會/不會購買某商品),那麼咱們把它叫作分類問題(classification problem);若是預測結果是連續值(好比房價,股票價格等等),那麼咱們把它叫作迴歸問題(regression problem)。markdown
有一系列的機器學習算法是用以解決監督學習問題的,好比最經典的用於分類問題的樸素貝葉斯、邏輯迴歸、支持向量機等等;好比說用於迴歸問題的線性迴歸等等。網絡
有另一類問題,給咱們的樣本並無給出『標籤/標準答案』,就是一系列的樣本。而咱們須要作的事情是,在一些樣本中抽取出通用的規則。這叫作『無監督學習』
。包括關聯規則和聚類算法在內的一系列機器學習算法都屬於這個範疇。數據結構
這類問題給出的訓練數據,有一部分有標籤,有一部分沒有標籤。咱們想學習出數據組織結構的同時,也能作相應的預測。此類問題相對應的機器學習算法有自訓練(Self-Training)、直推學習(Transductive Learning)、生成式模型(Generative Model)等。app
整體說來,最多見是前兩類問題,而對應前兩類問題的一些機器學習算法以下:dom
咱們也能夠從算法的共性(好比功能,運做方式)角度對機器學習算法分類。下面咱們根據算法的共性去對它們歸個類。不過須要注意的是,咱們下面的歸類方法可能對分類和迴歸有比較強的傾向性,而這兩類問題也是最常遇到的。機器學習
scikit-learn做爲一個豐富的python機器學習庫,實現了絕大多數機器學習的算法,有至關多的人在使用,因而我這裏很無恥地把machine learning cheat sheet for sklearn搬過來了,原文能夠看這裏。哈哈,既然講機器學習,咱們就用機器學習的語言來解釋一下,這是針對實際應用場景的各類條件限制,對scikit-learn裏完成的算法構建的一顆決策樹,每一組條件都是對應一條路徑,能找到相對較爲合適的一些解決方法,具體以下:
首先樣本量若是很是少的話,其實全部的機器學習算法都沒有辦法從裏面『學到』通用的規則和模式,so多弄點數據是王道。而後根據問題是有/無監督學習和連續值/離散值預測,分紅了分類
、聚類
、迴歸
和維度約減
四個方法類,每一個類里根據具體狀況的不一樣,又有不一樣的處理方法。
上面帶着代價蜻蜓點水過了一遍機器學習的若干算法,下面咱們試着總結總結在拿到一個實際問題的時候,若是着手使用機器學習算法去解決問題,其中的一些注意點以及核心思路。主要包括如下內容:
多說一句,這裏寫的這個小教程,主要是做爲一個通用的建議和指導方案,你不必定要嚴格按照這個流程解決機器學習問題。
咱們先使用scikit-learn的make_classification函數來生產一份分類數據,而後模擬一下拿到實際數據後咱們須要作的事情。
#numpy科學計算工具箱 import numpy as np #使用make_classification構造1000個樣本,每一個樣本有20個feature from sklearn.datasets import make_classification X, y = make_classification(1000, n_features=20, n_informative=2, n_redundant=2, n_classes=2, random_state=0) #存爲dataframe格式 from pandas import DataFrame df = DataFrame(np.hstack((X, y[:, None])),columns = range(20) + ["class"])
咱們生成了一份包含1000個分類數據樣本的數據集,每一個樣本有20個數值特徵。同時咱們把數據存儲至pandas中的DataFrame
數據結構中。咱們取前幾行的數據看一眼:
不幸的是,肉眼看數據,尤爲是維度稍微高點的時候,頗有可能看花了也看不出看不出任何線索。幸運的是,咱們對於圖像的理解力,比數字好太多,而又有至關多的工具能夠幫助咱們『可視化』數據分佈。
咱們在處理任何數據相關的問題時,瞭解數據都是頗有必要的,而可視化能夠幫助咱們更好地直觀理解數據的分佈和特性
數據的可視化有不少工具包能夠用,好比下面咱們用來作數據可視化的工具包Seaborn。最簡單的可視化就是數據散列分佈圖和柱狀圖,這個能夠用Seanborn的pairplot
來完成。如下圖中2種顏色表示2種不一樣的類,由於20維的可視化沒有辦法在平面表示,咱們取出了一部分維度,兩兩組成pair看數據在這2個維度平面上的分佈情況,代碼和結果以下:
import matplotlib.pyplot as plt import seaborn as sns #使用pairplot去看不一樣特徵維度pair下數據的空間分佈情況 _ = sns.pairplot(df[:50], vars=[8, 11, 12, 14, 19], hue="class", size=1.5) plt.show()
咱們從散列圖和柱狀圖上能夠看出,確實有些維度的特徵相對其餘維度,有更好的區分度,好比第11維和14維看起來頗有區分度。這兩個維度上看,數據點是近似線性可分的。而12維和19維彷佛呈現出了很高的負相關性。接下來咱們用Seanborn中的corrplot
來計算計算各維度特徵之間(以及最後的類別)的相關性。代碼和結果圖以下:
import matplotlib.pyplot as plt plt.figure(figsize=(12, 10)) _ = sns.corrplot(df, annot=False) plt.show()
相關性圖很好地印證了咱們以前的想法,能夠看到第11維特徵和第14維特徵和類別有極強的相關性,同時它們倆之間也有極高的相關性。而第12維特徵和第19維特徵卻呈現出極強的負相關性。強相關的特徵其實包含了一些冗餘的特徵,而除掉上圖中顏色較深的特徵,其他特徵包含的信息量就沒有這麼大了,它們和最後的類別相關度不高,甚至各自之間也沒什麼先慣性。
插一句,這裏的維度只有20,因此這個相關度計算並不費太大力氣,然而實際情形中,你徹底有可能有遠高於這個數字的特徵維度,同時樣本量也可能多不少,那種情形下咱們可能要先作一些處理,再來實現可視化了。彆着急,一下子咱們會講到。
數據的狀況咱們大體看了一眼,肯定一些特徵維度以後,咱們能夠考慮先選用機器學習算法作一個baseline的系統出來了。這裏咱們繼續參照上面提到過的機器學習算法使用圖譜。
咱們只有1000個數據樣本,是分類問題,同時是一個有監督學習,所以咱們根據圖譜裏教的方法,使用LinearSVC
(support vector classification with linear kernel)試試。注意,LinearSVC
須要選擇正則化方法以緩解過擬合問題;咱們這裏選擇使用最多的L2正則化,並把懲罰係數C設爲10。咱們改寫一下sklearn中的學習曲線繪製函數,畫出訓練集和交叉驗證集上的得分:
from sklearn.svm import LinearSVC from sklearn.learning_curve import learning_curve #繪製學習曲線,以肯定模型的情況 def plot_learning_curve(estimator, title, X, y, ylim=None, cv=None, train_sizes=np.linspace(.1, 1.0, 5)): """ 畫出data在某模型上的learning curve. 參數解釋 ---------- estimator : 你用的分類器。 title : 表格的標題。 X : 輸入的feature,numpy類型 y : 輸入的target vector ylim : tuple格式的(ymin, ymax), 設定圖像中縱座標的最低點和最高點 cv : 作cross-validation的時候,數據分紅的份數,其中一份做爲cv集,其他n-1份做爲training(默認爲3份) """ plt.figure() train_sizes, train_scores, test_scores = learning_curve( estimator, X, y, cv=5, n_jobs=1, train_sizes=train_sizes) train_scores_mean = np.mean(train_scores, axis=1) train_scores_std = np.std(train_scores, axis=1) test_scores_mean = np.mean(test_scores, axis=1) test_scores_std = np.std(test_scores, axis=1) plt.fill_between(train_sizes, train_scores_mean - train_scores_std, train_scores_mean + train_scores_std, alpha=0.1, color="r") plt.fill_between(train_sizes, test_scores_mean - test_scores_std, test_scores_mean + test_scores_std, alpha=0.1, color="g") plt.plot(train_sizes, train_scores_mean, 'o-', color="r", label="Training score") plt.plot(train_sizes, test_scores_mean, 'o-', color="g", label="Cross-validation score") plt.xlabel("Training examples") plt.ylabel("Score") plt.legend(loc="best") plt.grid("on") if ylim: plt.ylim(ylim) plt.title(title) plt.show() #少樣本的狀況狀況下繪出學習曲線 plot_learning_curve(LinearSVC(C=10.0), "LinearSVC(C=10.0)", X, y, ylim=(0.8, 1.01), train_sizes=np.linspace(.05, 0.2, 5))
這幅圖上,咱們發現隨着樣本量的增長,訓練集上的得分有必定程度的降低,交叉驗證集上的得分有必定程度的上升,但整體說來,二者之間有很大的差距,訓練集上的準確度遠高於交叉驗證集。這其實意味着咱們的模型處於過擬合的狀態,也即模型太努力地刻畫訓練集,一不當心把不少噪聲的分佈也擬合上了,致使在新數據上的泛化能力變差了。
問題來了,過擬合咋辦?
針對過擬合,有幾種辦法能夠處理:
這個比較好理解吧,過擬合的主要緣由是模型太努力地去記住訓練樣本的分佈情況,而加大樣本量,可使得訓練集的分佈更加具有普適性,噪聲對總體的影響降低。恩,咱們提升點樣本量試試:
#增大一些樣本量 plot_learning_curve(LinearSVC(C=10.0), "LinearSVC(C=10.0)", X, y, ylim=(0.8, 1.1), train_sizes=np.linspace(.1, 1.0, 5))
是否是發現問題好了不少?隨着咱們增大訓練樣本量,咱們發現訓練集和交叉驗證集上的得分差距在減小,最後它們已經很是接近了。增大樣本量,最直接的方法固然是想辦法去採集相同場景下的新數據,若是實在作不到,也能夠試試在已有數據的基礎上作一些人工的處理生成新數據(好比圖像識別中,咱們可能能夠對圖片作鏡像變換、旋轉等等),固然,這樣作必定要謹慎,強烈建議想辦法採集真實數據。
好比在這個例子中,咱們以前的數據可視化和分析的結果代表,第11和14維特徵包含的信息對識別類別很是有用,咱們能夠只用它們。
plot_learning_curve(LinearSVC(C=10.0), "LinearSVC(C=10.0) Features: 11&14", X[:, [11, 14]], y, ylim=(0.8, 1.0), train_sizes=np.linspace(.05, 0.2, 5))
從上圖上能夠看出,過擬合問題也獲得必定程度的緩解。不過咱們這是本身觀察後,手動選出11和14維特徵。那能不能自動進行特徵組合和選擇呢,其實咱們固然能夠遍歷特徵的組合樣式,而後再進行特徵選擇(前提依舊是這裏特徵的維度不高,若是高的話,遍歷全部的組合是一個很是很是很是耗時的過程!!):
from sklearn.pipeline import Pipeline from sklearn.feature_selection import SelectKBest, f_classif # SelectKBest(f_classif, k=2) 會根據Anova F-value選出 最好的k=2個特徵 plot_learning_curve(Pipeline([("fs", SelectKBest(f_classif, k=2)), # select two features ("svc", LinearSVC(C=10.0))]), "SelectKBest(f_classif, k=2) + LinearSVC(C=10.0)", X, y, ylim=(0.8, 1.0), train_sizes=np.linspace(.05, 0.2, 5))
若是你本身跑一下程序,會發如今咱們本身手造的這份數據集上,這個特徵篩選的過程超級順利,但依舊像咱們以前提過的同樣,這是由於特徵的維度不過高。
從另一個角度看,咱們之因此作特徵選擇,是想下降模型的複雜度,而更不容易刻畫到噪聲數據的分佈。從這個角度出發,咱們還能夠有(1)多項式你和模型中下降多項式次數 (2)神經網絡中減小神經網絡的層數和每層的結點數 (c)SVM中增長RBF-kernel的bandwidth等方式來下降模型的複雜度。
話說回來,即便以上提到的辦法下降模型複雜度後,好像能在必定程度上緩解過擬合,可是咱們通常仍是不建議一遇到過擬合,就用這些方法處理,優先用下面的方法:
plot_learning_curve(LinearSVC(C=0.1), "LinearSVC(C=0.1)", X, y, ylim=(0.8, 1.0), train_sizes=np.linspace(.05, 0.2, 5))
調整正則化係數後,發現確實過擬合現象有必定程度的緩解,但依舊是那個問題,咱們如今的係數是本身敲定的,有沒有辦法能夠自動選擇最佳的這個參數呢?能夠。咱們能夠在交叉驗證集上作grid-search查找最好的正則化係數(對於大數據樣本,咱們依舊須要考慮時間問題,這個過程可能會比較慢):
from sklearn.grid_search import GridSearchCV estm = GridSearchCV(LinearSVC(), param_grid={"C": [0.001, 0.01, 0.1, 1.0, 10.0]}) plot_learning_curve(estm, "LinearSVC(C=AUTO)", X, y, ylim=(0.8, 1.0), train_sizes=np.linspace(.05, 0.2, 5)) print "Chosen parameter on 100 datapoints: %s" % estm.fit(X[:500], y[:500]).best_params_
在500個點獲得的結果是:{‘C’: 0.01}
使用新的C參數,咱們再看看學習曲線:
對於特徵選擇的部分,我打算多說幾句,咱們剛纔看過了用sklearn.feature_selection中的SelectKBest來選擇特徵的過程,也提到了在高維特徵的狀況下,這個過程可能會很是很是慢。那咱們有別的辦法能夠進行特徵選擇嗎?好比說,咱們的分類器本身可否甄別那些特徵是對最後的結果有益的?這裏有個實際工做中用到的小技巧。
咱們知道:
那基於這個理論,咱們能夠把SVC中的正則化替換成l1正則化,讓其自動甄別哪些特徵應該留下權重。
plot_learning_curve(LinearSVC(C=0.1, penalty='l1', dual=False), "LinearSVC(C=0.1, penalty='l1')", X, y, ylim=(0.8, 1.0), train_sizes=np.linspace(.05, 0.2, 5))
好了,咱們一塊兒來看看最後特徵得到的權重:
estm = LinearSVC(C=0.1, penalty='l1', dual=False) estm.fit(X[:450], y[:450]) # 用450個點來訓練 print "Coefficients learned: %s" % est.coef_ print "Non-zero coefficients: %s" % np.nonzero(estm.coef_)[1]
獲得結果:
Coefficients learned: [[ 0. 0. 0. 0. 0. 0.01857999 0. 0. 0. 0.004135 0. 1.05241369 0.01971419 0. 0. 0. 0. -0.05665314 0.14106505 0. ]] Non-zero coefficients: [5 9 11 12 17 18]
你看,5 9 11 12 17 18這些維度的特徵得到了權重,而第11維權重最大,也說明了它影響程度最大。
咱們再隨機生成一份數據[1000*20]的數據(可是分佈和以前有變化),從新使用LinearSVC來作分類。
#構造一份環形數據 from sklearn.datasets import make_circles X, y = make_circles(n_samples=1000, random_state=2) #繪出學習曲線 plot_learning_curve(LinearSVC(C=0.25),"LinearSVC(C=0.25)",X, y, ylim=(0.5, 1.0),train_sizes=np.linspace(.1, 1.0, 5))
簡直爛出翔了有木有,二分類問題,咱們作隨機猜想,準確率都有0.5,這比隨機猜想都高不了多少!!!怎麼辦?
不要盲目動手收集更多資料,或者調整正則化參數。咱們從學習曲線上其實能夠看出來,訓練集上的準確度和交叉驗證集上的準確度都很低,這其實就對應了咱們說的『欠擬合』狀態。別急,咱們回到咱們的數據,仍是可視化看看:
f = DataFrame(np.hstack((X, y[:, None])), columns = range(2) + ["class"]) _ = sns.pairplot(df, vars=[0, 1], hue="class", size=3.5)
你發現什麼了,數據根本就沒辦法線性分割!!!,因此你再找更多的數據,或者調整正則化參數,都是無濟於事的!!!
那咱們又怎麼解決欠擬合問題呢?一般有下面一些方法:
# 加入原始特徵的平方項做爲新特徵 X_extra = np.hstack((X, X[:, [0]]**2 + X[:, [1]]**2)) plot_learning_curve(LinearSVC(C=0.25), "LinearSVC(C=0.25) + distance feature", X_extra, y, ylim=(0.5, 1.0), train_sizes=np.linspace(.1, 1.0, 5))
from sklearn.svm import SVC # note: we use the original X without the extra feature plot_learning_curve(SVC(C=2.5, kernel="rbf", gamma=1.0), "SVC(C=2.5, kernel='rbf', gamma=1.0)",X, y, ylim=(0.5, 1.0), train_sizes=np.linspace(.1, 1.0, 5))
你看,效果依舊很贊。
咱們在小樣本的toy dataset上,怎麼搗鼓都有好的方法。可是當數據量和特徵樣本空間膨脹很是厲害時,不少東西就沒有那麼好使了,至少是一個很耗時的過程。舉個例子說,咱們如今從新生成一份數據集,可是此次,咱們生成更多的數據,更高的特徵維度,而分類的類別也提升到5。
在上面提到的那樣一份數據上,咱們用LinearSVC可能就會有點慢了,咱們注意到機器學習算法使用圖譜推薦咱們使用SGDClassifier
。其實本質上說,這個模型也是一個線性核函數的模型,不一樣的地方是,它使用了隨機梯度降低作訓練,因此每次並無使用所有的樣本,收斂速度會快不少。再多提一點,SGDClassifier
對於特徵的幅度很是敏感,也就是說,咱們在把數據灌給它以前,應該先對特徵作幅度調整,固然,用sklearn的StandardScaler
能夠很方便地完成這一點。
SGDClassifier
每次只使用一部分(mini-batch)作訓練,在這種狀況下,咱們使用交叉驗證(cross-validation)並非很合適,咱們會使用相對應的progressive validation:簡單解釋一下,estimator每次只會拿下一個待訓練batch在本次作評估,而後訓練完以後,再在這個batch上作一次評估,看看是否有優化。
#生成大樣本,高緯度特徵數據 X, y = make_classification(200000, n_features=200, n_informative=25, n_redundant=0, n_classes=10, class_sep=2, random_state=0) #用SGDClassifier作訓練,並畫出batch在訓練先後的得分差 from sklearn.linear_model import SGDClassifier est = SGDClassifier(penalty="l2", alpha=0.001) progressive_validation_score = [] train_score = [] for datapoint in range(0, 199000, 1000): X_batch = X[datapoint:datapoint+1000] y_batch = y[datapoint:datapoint+1000] if datapoint > 0: progressive_validation_score.append(est.score(X_batch, y_batch)) est.partial_fit(X_batch, y_batch, classes=range(10)) if datapoint > 0: train_score.append(est.score(X_batch, y_batch)) plt.plot(train_score, label="train score") plt.plot(progressive_validation_score, label="progressive validation score") plt.xlabel("Mini-batch") plt.ylabel("Score") plt.legend(loc='best') plt.show()
獲得以下的結果:
從這個圖上的得分,咱們能夠看出在50個mini-batch迭代以後,數據上的得分就已經變化不大了。可是好像得分都不過高,因此咱們猜想一下,這個時候咱們的數據,處於欠擬合狀態。咱們剛纔在小樣本集合上提到了,若是欠擬合,咱們可使用更復雜的模型,好比把核函數設置爲非線性的,但遺憾的是像rbf核函數是沒有辦法和SGDClassifier
兼容的。所以咱們只能想別的辦法了,好比這裏,咱們能夠把SGDClassifier
整個替換掉了,用多層感知神經網
來完成這個任務,咱們之因此會想到多層感知神經網
,是由於它也是一個用隨機梯度降低訓練的算法,同時也是一個非線性的模型。固然根據機器學習算法使用圖譜,也可使用核估計(kernel-approximation)來完成這個事情。
大樣本數據的可視化是一個相對比較麻煩的事情,通常狀況下咱們都要用到降維的方法先處理特徵。咱們找一個例子來看看,能夠怎麼作,好比咱們數據集取經典的『手寫數字集』,首先找個方法看一眼這個圖片數據集。
#直接從sklearn中load數據集 from sklearn.datasets import load_digits digits = load_digits(n_class=6) X = digits.data y = digits.target n_samples, n_features = X.shape print "Dataset consist of %d samples with %d features each" % (n_samples, n_features) # 繪製數字示意圖 n_img_per_row = 20 img = np.zeros((10 * n_img_per_row, 10 * n_img_per_row)) for i in range(n_img_per_row): ix = 10 * i + 1 for j in range(n_img_per_row): iy = 10 * j + 1 img[ix:ix + 8, iy:iy + 8] = X[i * n_img_per_row + j].reshape((8, 8)) plt.imshow(img, cmap=plt.cm.binary) plt.xticks([]) plt.yticks([]) _ = plt.title('A selection from the 8*8=64-dimensional digits dataset') plt.show()
咱們總共有1083個訓練樣本,包含手寫數字(0,1,2,3,4,5),每一個樣本圖片中的像素點平鋪開都是64位,這個維度顯然是沒辦法直接可視化的。下面咱們基於scikit-learn的示例教程對特徵用各類方法作降維處理,再可視化。
隨機投射
咱們先看看,把數據隨機投射到兩個維度上的結果:
#import所需的package from sklearn import (manifold, decomposition, random_projection) rp = random_projection.SparseRandomProjection(n_components=2, random_state=42) #定義繪圖函數 from matplotlib import offsetbox def plot_embedding(X, title=None): x_min, x_max = np.min(X, 0), np.max(X, 0) X = (X - x_min) / (x_max - x_min) plt.figure(figsize=(10, 10)) ax = plt.subplot(111) for i in range(X.shape[0]): plt.text(X[i, 0], X[i, 1], str(digits.target[i]), color=plt.cm.Set1(y[i] / 10.), fontdict={'weight': 'bold', 'size': 12}) if hasattr(offsetbox, 'AnnotationBbox'): # only print thumbnails with matplotlib > 1.0 shown_images = np.array([[1., 1.]]) # just something big for i in range(digits.data.shape[0]): dist = np.sum((X[i] - shown_images) ** 2, 1) if np.min(dist) < 4e-3: # don't show points that are too close continue shown_images = np.r_[shown_images, [X[i]]] imagebox = offsetbox.AnnotationBbox( offsetbox.OffsetImage(digits.images[i], cmap=plt.cm.gray_r), X[i]) ax.add_artist(imagebox) plt.xticks([]), plt.yticks([]) if title is not None: plt.title(title) #記錄開始時間 start_time = time.time() X_projected = rp.fit_transform(X) plot_embedding(X_projected, "Random Projection of the digits (time: %.3fs)" % (time.time() - start_time))
結果以下:
PCA降維
在維度約減/降維領域有一個很是強大的算法叫作PCA(Principal Component Analysis,主成分分析),它能將原始的絕大多數信息用維度遠低於原始維度的幾個主成分表示出來。PCA在咱們如今的數據集上效果還不錯,咱們來看看用PCA對原始特徵降維至2維後,原始樣本在空間的分佈情況:
from sklearn import (manifold, decomposition, random_projection) #TruncatedSVD 是 PCA的一種實現 X_pca = decomposition.TruncatedSVD(n_components=2).fit_transform(X) #記錄時間 start_time = time.time() plot_embedding(X_pca,"Principal Components projection of the digits (time: %.3fs)" % (time.time() - start_time))
獲得的結果以下:
咱們能夠看出,效果還不錯,不一樣的手寫數字在2維平面上,顯示出了區域集中性。即便它們之間有必定的重疊區域。
若是咱們用一些非線性的變換來作降維操做,從原始的64維降到2維空間,效果更好,好比這裏咱們用到一個技術叫作t-SNE,sklearn的manifold對其進行了實現:
from sklearn import (manifold, decomposition, random_projection) #降維 tsne = manifold.TSNE(n_components=2, init='pca', random_state=0) start_time = time.time() X_tsne = tsne.fit_transform(X) #繪圖 plot_embedding(X_tsne, "t-SNE embedding of the digits (time: %.3fs)" % (time.time() - start_time))
咱們發現結果很是的驚人,彷佛這個非線性變換降維事後,僅僅2維的特徵,就能夠將原始數據的不一樣類別,在平面上很好地劃分開。不過t-SNE也有它的缺點,通常說來,相對於線性變換的降維,它須要更多的計算時間。也不太適合在大數據集上全集使用。
損失函數的選擇對於問題的解決和優化,很是重要。咱們先來看一眼各類不一樣的損失函數:
import numpy as np import matplotlib.plot as plt # 改自http://scikit-learn.org/stable/auto_examples/linear_model/plot_sgd_loss_functions.html xmin, xmax = -4, 4 xx = np.linspace(xmin, xmax, 100) plt.plot([xmin, 0, 0, xmax], [1, 1, 0, 0], 'k-', label="Zero-one loss") plt.plot(xx, np.where(xx < 1, 1 - xx, 0), 'g-', label="Hinge loss") plt.plot(xx, np.log2(1 + np.exp(-xx)), 'r-', label="Log loss") plt.plot(xx, np.exp(-xx), 'c-', label="Exponential loss") plt.plot(xx, -np.minimum(xx, 0), 'm-', label="Perceptron loss") plt.ylim((0, 8)) plt.legend(loc="upper right") plt.xlabel(r"Decision function $f(x)$") plt.ylabel("$L(y, f(x))$") plt.show()
獲得結果圖像以下:
不一樣的損失函數有不一樣的優缺點:
全文到此就結束了。先蜻蜓點水看了一遍機器學習的算法,而後給出了對應scikit-learn的『祕密武器』機器學習算法使用圖譜,緊接着從瞭解數據(可視化)、選擇機器學習算法、定位過/欠擬合及解決方法、大量極的數據可視化和損失函數優缺點與選擇等方面介紹了實際機器學習問題中的一些思路和方法。本文和文章機器學習系列(3)_邏輯迴歸應用之Kaggle泰坦尼克之災都說起了一些處理實際機器學習問題的思路和方法,有類似和互補之處,歡迎你們參照着看。