MLK | 特徵工程系統化乾貨筆記+程式碼了解一下(下)

  • 2019 年 10 月 4 日
  • 筆記

總算是把這本《特徵工程入門與實踐》的筆記?給整理完了,這一篇是最後一篇了,後續我會把3篇文章都匯總到一起,同時數據集和程式碼也會在公眾號後台共享,大家可以回復 」特徵工程「 來獲取唄。

? 目錄

  • ? 特徵理解
  • ? 特徵增強
  • ? 特徵構建
  • ✅ 特徵選擇
  • ? 特徵轉換
  • ? 特徵學習

? 05 特徵轉換

經過了上面幾個環節的「洗禮」,我們來到特徵轉換的環節,也就是使用源數據集的隱藏結構來創建新的列,常用的辦法有2種:PCA和LDA。

✅ PCA:

PCA,即主成分分析(Principal Components Analysis),是比較常見的數據壓縮的辦法,即將多個相關特徵的數據集投影到相關特徵較少的坐標繫上。也就是說,轉換後的特徵,在解釋性上就走不通了,因為你無法解釋這個新變數到底具有什麼業務邏輯了。

PCA的原理這裡就不展開來講了,太多的文章把它講得十分透徹了。這裡主要是復現一下PCA在sklearn上的調用方法,一來繼續熟悉下Pipeline的使用,二來理解一下PCA的使用方法。

# 導入相關庫  from sklearn.datasets import load_iris  import matplotlib.pyplot as plt  %matplotlib inline    from sklearn.decomposition import PCA    # 導入數據集  iris = load_iris()  iris_x, iris_y = iris.data, iris.target    # 實例化方法  pca = PCA(n_components=2)  # 訓練方法  pca.fit(iris_x)  pca.transform(iris_x)[:5,]    # 自定義一個可視化的方法  label_dict = {i:k for i,k in enumerate(iris.target_names)}  def plot(x,y,title,x_label,y_label):      ax = plt.subplot(111)      for label,marker,color in zip(      range(3),('^','s','o'),('blue','red','green')):          plt.scatter(x=x[:,0].real[y == label],                     y = x[:,1].real[y == label],                     color = color,                     alpha = 0.5,                     label = label_dict[label]                     )        plt.xlabel(x_label)      plt.ylabel(y_label)        leg = plt.legend(loc='upper right', fancybox=True)      leg.get_frame().set_alpha(0.5)      plt.title(title)    # 可視化  plot(iris_x, iris_y,"original iris data","sepal length(cm)","sepal width(cm)")  plt.show()    plot(pca.transform(iris_x), iris_y,"Iris: Data projected onto first two PCA components","PCA1","PCA2")

以上是PCA在sklearn上的簡單調用和效果展示,另外,作者提出了一個很有意思的問題:

一般而言,對特徵進行歸一化處理後會對機器學習演算法的效果有比較明顯的幫助,但為什麼在書本的例子卻是相反呢?

給出的解釋是:在對數據進行縮放後,列與列之間的協方差會更加一致,而且每個主成分解釋的方差會變得分散,而不是集中在某一個主成分上。所以,在實際操作的時候,都要對縮放的未縮放的數據進行性能測試才是最穩妥的哦。

✅ LDA:

LDA,即線性判別分析(Linear Discriminant Analysis),它是一個有監督的演算法(哦對了, PCA是無監督的),一般是用於分類流水線的預處理步驟。與PCA類似,LDA也是提取出一個新的坐標軸,將原始的高維數據投影到低維空間去,而區別在於LDA不會去專註數據之間的方差大小,而是直接優化低維空間,以獲得最佳的類別可分性。

# LDA的使用  # 導入相關庫  from sklearn.discriminant_analysis import LinearDiscriminantAnalysis  # 實例化LDA模組  lda = LinearDiscriminantAnalysis(n_components=2)  # 訓練數據  x_lda_iris = lda.fit_transform(iris_x, iris_y)  # 可視化  plot(x_lda_iris, iris_y, "LDA Projection", "LDA1", "LDA2")

? 06 特徵學習

來到最後一章了,這章的主題是「以AI促AI」。看起來還蠻抽象的,反正我是覺得有點奇怪,特徵學習演算法是非參數方法,也就是不依賴數據結構而構建出來的新演算法。

? 數據的參數假設

參數假設指的是演算法對數據形狀的基本假設。比如上一章的PCA,我們是假設:

原始數據的形狀可以被(特徵值)分解,並且可以用單個線性變換(矩陣計算)表示。

而特徵學習演算法,就是要去除這個「假設」來解決問題,因為這演算法不會依賴數據的形狀,而是依賴於隨機學習(Stochastic Learning),指的是這些演算法並不是每次輸出相同的結果,而是一次次按輪(epoch)去檢查數據點以找到要提取的最佳特徵,並且可以擬合出一個最優的解決方法。

而在特徵學習領域,有兩種方法是比較常用的,也是下面來講解的內容:受限玻爾茲曼機(RBM)和詞嵌入。

? 受限玻爾茲曼機(RBM)

RBM是一種簡單的深度學習架構,是一組無監督的特徵學習演算法,根據數據的概率模型學習一定數量的新特徵,往往使用RBM之後去用線性模型(線性回歸、邏輯回歸、感知機等)的效果極佳。

從概念上說,RBM是一個淺層(2層)的神經網路,屬於深度信念網路(DBN,deep belief network)演算法的一種。它也是一種無監督演算法,可以學習到的 特徵數量只受限於計算能力,它可能學習到比原始要少或者多的特徵,具體要學習的特徵數量取決於要解決的問題。

「受限」的說法是因為它只允許層與層之間的連接(層間連接),而不允許同一層內的節點連接(層內連接)。

在這裡需要理解一下「重建」(Reconstruction),也就是這個操作,使得在不涉及更深層網路的情況下,可見層(輸入層)和隱含層之間可以存在數次的前向和反向傳播。

在重建階段,RBM會反轉網路,可見層變成了隱含層,隱含層變成了可見層,用相同的權重將激活變數a反向傳遞到可見層,但是偏差不一樣,然後用前向傳導的激活變數重建原始輸入向量。RBM就是用這種方法來進行「自我評估」的,通過將激活資訊進行反向傳導並獲取原始輸入的近似值,該網路可以調整權重,讓近似值更加接近原始輸入。

在訓練開始時,由於權重是隨機初始化的(一般做法),近似值與真實值的差異可能會極大的,接下來就會通過反向傳播的方法來調整權重,最小化原始輸入與近似值的距離,一直重複這個過程,直到近似值儘可能接近原始輸入。(這個過程發生的次數叫 迭代次數 )

大致的原理就是上面的說法了,更加詳細的解釋可以自行百度哦。下面我們來講講RBM在機器學習管道中的應用,我們還是使用MNIST數據集,這個數據集在之前講Keras的時候(傳送門)也用到了,就是一堆數字的像素點數據,然後用來識別數字。

# RBM的使用  # 我們使用MNIST數據集來講解  # 導入相關庫  import numpy as np  import matplotlib.pyplot as plt  %matplotlib inline    from sklearn.linear_model import LogisticRegression  from sklearn.neural_network import BernoulliRBM  from sklearn.pipeline import Pipeline    # 導入數據集  images = np.genfromtxt('./data/mnist_train.csv', delimiter=',')  print(images.shape)  # 劃分數據  images_x, images_y = images[:,1:], images[:,0]    # 縮放特徵到0-1  images_x = images_x/255.    # 用RBM學習新特徵  rbm = BernoulliRBM(random_state=0)  lr = LogisticRegression()    # 設置流水線的參數範圍  params = {'clf__C':[1e-1, 1e0, 1e1],            'rbm__n_components':[100, 200]           }  # 創建流水線  pipeline = Pipeline([('rbm', rbm),                       ('clf', lr)])  # 實例化網格搜索類  grid = GridSearchCV(pipeline, params)  # 擬合數據  grid.fit(images_x, images_y)  # 返回最佳參數  grid.best_params_, grid.best_score_

? 詞嵌入

在NLP領域應用極為廣泛了,它可以將字元串(單詞或短語)投影到n維特徵集中,以便理解上下文和措辭的細節,我們可以使用sklearn中的CountVectorizerTfidfVectorizer 來將這些字元串進行轉為向量,但這只是一些單詞特徵的集合而已,為了理解這些特徵,我們更加要關注一個叫 gensim的包。

常用的詞嵌入方法有兩種:Word2vec和GloVe。

Word2vec: Google發明的一種基於深度學習的演算法。Word2vec也是一個淺層的神經網路,含有輸入層、隱含層和輸出層,其中輸入層和輸出層的節點個數一樣。

GloVe: 來自斯坦福大學的演算法,通過一系列矩陣統計進行學習。

詞嵌入的應用很多,比如資訊檢索,意思是當我們輸入關鍵詞時,搜索引擎可以回憶並準確返回和關鍵詞匹配的文章或者新聞。