本文主要介紹了scikit-learn estimators、Nearest neighbors、Distance metrics、pipeline等數據分析中經常用到的知識 。
本文是小編根據課程教材及網絡收集的資料結合自己所學所思翻譯整理,糾錯指正、深入探討,咱們評論區見。
01
scikit-learn estimators
estimators,允許算法的標準化實現和測試一個通用的、輕量級的接口,供分類器遵循。通過使用這個接口,我們可以將這些工具應用於任意分類器,而不需要擔心算法如何工作。
可以簡單的理解為這個估算器就是scikit-learn這個強大的工具包中的各個小工具的統稱。
estimators 必須具備以下兩個重要的函數:
fit():該函數執行算法的訓練--設置內部參數值。這個函數執行算法的訓練--設置內部參數的值。fit()需要兩個輸入,即訓練樣本數據集和這些樣本對應的類。predict():這裡我們提供的測試樣本作為唯一的輸入。這個函數返回一個NumPy數組,裡面有每個輸入測試樣本的預測值。 大多數scikit-learn估計器都使用NumPy數組或相關格式作為輸入和輸出。然而這是慣例,並不是使用接口的必要條件。scikit-learn中實現了很多估計器,其他開源項目中也有更多的估計器使用相同的接口。例如(SVM)、隨機森林。後面的章節將會提到這些算法。在本章將使用最近鄰算法。
02
Nearest neighbors
其原理是取最相似的樣本,並預測這些附近樣本中的大多數樣本所具有的相同類別。
基於此算法下圖中的星號最可能是紅色橢圓。
最近鄰域幾乎可用於任何數據集。然而計算所有樣本對之間的距離,計算成本很高。例如,如果數據集中有10個樣本,就有45個獨立的距離需要計算。然而,如果有1000個樣本,則有近500,000個樣本。 有各種方法可以提高這個速度,比如使用樹形結構進行距離計算。其中一些算法可能相當複雜,但值得慶幸的是,scikit-learn中已經實現了一個版本,使我們能夠在更大的數據集上進行分類。由於這些樹形結構是scikit-learn中的默認結構,我們不需要配置任何東西就可以使用它。在基於分類的數據集上,最近鄰算法做得很差,有分類特徵的數據集,應該用另一種算法來代替。Nearest Neighbor的問題是由於難以比較分類值的差異,這一點最好留給可以給每個特徵的重要性加權的算法。比較分類特徵可以通過一些距離度量或預處理步驟來完成,比如後面章節中使用的 one hot encoding 。為任務選擇正確的算法是數據挖掘中的難點之一,通常情況下,測試一組算法,看看哪種算法在你的任務上表現最好,是最簡單的選擇方式。
03
Distance metrics
數據挖掘中一個關鍵的基礎概念是距離。如果我們有兩個樣本,我們需要回答這樣的問題:這兩個樣本是否比其他兩個樣本更相似?回答這樣的問題對數據挖掘工作的結果很重要。最常用的是歐氏距離,也就是現實世界中兩個物體之間的距離。如果你要把點繪製在圖上,用尺子測量距離,結果就是歐氏距離。
常見的還有曼哈頓距離和餘弦距離
曼哈頓距離是每個特徵的絕對差異之和(不使用平方距離)。
餘弦距離更適合於一些特徵比其他特徵大,以及數據集中有很多零的情況。
假設有很多特徵,隨機樣本之間的歐氏距離會收斂(由於著名的維度詛咒)。高維度的歐氏距離很難比較樣本,因為距離總是幾乎相同。曼哈頓距離在這種情況下可以更穩定,但如果一些特徵的值非常大,就會蓋過其他特徵的很多相似性。例如,如果特徵A的值在1到2之間,而另一個特徵B的值在1000到2000之間,在這種情況下,特徵A不太可能對結果有任何影響。這個問題可以通過歸一化來解決,這使得曼哈頓(和歐幾裡得)距離在不同特徵下更加可靠,這一點我們將在本章後面看到。最後,Cosine距離是比較具有許多特徵的項目的一個很好的度量,但是它丟棄了一些關於向量長度的信息,這在一些應用中是有用的。由於文本挖掘中固有的大量特徵,我們經常會在文本挖掘中使用Cosine距離。
在本章將繼續使用歐氏距離,在後面的章節中使用其他度量。不過大家可以嘗試將度量設置為曼哈頓,看看這對結果有什麼影響。
04
讀取數據
數據集電離層,天線的目的是確定電離層和高層大氣中是否有結構的區域。我們認為有結構的讀數是好的,而沒有結構的讀數被認為是壞的。本應用的目的是建立一個數據挖掘分類器,可以判斷一個圖像是好還是壞。
首先像前一章那樣新建一個jupyter notebook。
或者選擇一個你喜歡的在線編譯網站新建一個python3項目,首先導入將要用到的應用庫,並導入我們將要處理的數據,我已將所要用到的數據上傳到了自己的GitHub.
import pandas as pd import numpy as npimport csvdata_filename = 'https://raw.githubusercontent.com/neowalter/DA-tour/master/charpter2/ionosphere.data'df = pd.read_csv(data_filename)df.describe
這裡我們可以先用describe功能看一下數據讀取是否成功。
讀取正常
05
標準工作流程
這裡我們通過對數據的屬性來對其進行分類。
這裡我們需要重新將文件下載到本地,再進行讀取操作。下面的文件地址需要修改為自己的文件存放地址
#change this to the location where your file is locateddata_filename = "/content/ionosphere.data"print(data_filename)X = np.zeros((351, 34), dtype='float')y = np.zeros((351,), dtype='bool')with open(data_filename, 'r') as input_file: reader = csv.reader(input_file) for i, row in enumerate(reader):# Get the data, converting each item to a float data = [float(datum) for datum in row[:-1]]# Set the appropriate row in our dataset X[i] = data# 1 if the class is 'g', 0 otherwise y[i] = row[-1] == 'g'
我們在測試集上使用fit()方法訓練算法。我們在測試集上使用predict()方法對其進行評估。
from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(X, y, random_state=14)print("There are {} samples in the training dataset".format(X_train.shape[0]))print("There are {} samples in the testing dataset".format(X_test.shape[0]))print("Each sample has {} features".format(X_train.shape[1]))from sklearn.neighbors import KNeighborsClassifierestimator = KNeighborsClassifier()estimator.fit(X_train, y_train)y_predicted = estimator.predict(X_test)accuracy = np.mean(y_test == y_predicted) * 100print("The accuracy is {0:.1f}%".format(accuracy))
這個模型的準確率達到了86.4%,對於一個默認算法和幾行代碼來說,這是很少見的。
得到這樣的結果會不會是隨機分組的樣本數據集很合適,所以得分才高呢?我們可以測試一下每個樣本的準確率。
from sklearn.model_selection import cross_val_scorescores = cross_val_score(estimator, X, y, scoring='accuracy')average_accuracy = np.mean(scores) * 100print("The average accuracy is {0:.1f}%".format(average_accuracy))
我們的新代碼返回了一個略微溫和的82.3%的結果,但考慮到我們還沒有嘗試設置更好的參數,這個結果還是相當不錯的。
06
設置參數
幾乎所有的參數,用戶都可以設置,讓算法更專注於特定的數據集,而不是只適用於小範圍的特定問題。設置這些參數是相當困難的,因為選擇好的參數值往往高度依賴於數據集的特徵。最近鄰算法有幾個參數,但最重要的一個參數是在預測未見歸屬的類時使用的最近鄰數量。在scikit-learn中,這個參數叫做n_neighbors。在下圖中,我們表明,當這個數字太低時,隨機標記的樣本會導致錯誤。相反,當它過高時,實際最近的鄰居對結果的影響較小。
最近鄰域一個很難解決的問題,因為參數會產生巨大的差異。幸運的是,大多數時候,具體的參數值不會對最終結果產生很大影響,標準值(通常是5或10)往往已經足夠接近。
考慮到這一點,我們可以測試出一個數值範圍,並研究這個參數對性能的影響。如果我們想測試n_neighbors參數的若干值,例如,從1到20的每個值,我們可以通過設置n_neighbors來重新運行實驗很多次,並觀察結果。下面的代碼就是這樣做的,將數值存儲在avg_scores和all_scores變量中。
avg_scores = []all_scores = []parameter_values = list(range(1, 91))for n_neighbors in parameter_values: estimator = KNeighborsClassifier(n_neighbors=n_neighbors) scores = cross_val_score(estimator, X, y, scoring='accuracy') avg_scores.append(np.mean(scores)) all_scores.append(scores)
然後我們可以繪製n_neighbors的值和精度之間的關係。
from matplotlib import pyplot as pltplt.figure(figsize=(22,10))plt.plot(parameter_values, avg_scores, '-o', linewidth=2, markersize=6)
雖然有很多差異,但隨著n_neighbors的增加,該圖顯示出下降的趨勢。
07
數據預處理
對於一個基於數學的算法來說,要比較這些特徵的每一個特徵,尺度、範圍和單位的差異可能很難解釋。如果我們在很多算法中使用上述特徵,由於只有較大的數字,而與特徵的實際效果無關,因此權重可能是影響最大的特徵。其中一種可能的策略是將特徵歸一化,使它們都有相同的範圍,或者將數值變成小、中、大等類別。特徵類型的巨大差異對算法的影響較小,可以使準確率大幅提高。
預處理還可以用來只選擇更有效的特徵,創建新的特徵等。scikit-learn中的預處理是通過Transformer對象來完成的,Transformer對象將一個數據集以一種形式存在,並在對數據進行一定的轉換後返回一個改變後的數據集。這些不一定是數值上的,因為Transformer也是用來提取特徵的。
理論上來說,這對結果的影響應該不是很大。畢竟,這些特徵的數值還是比較相同的。主要的問題是尺度發生了變化,現在奇數特徵比偶數特徵大。我們可以通過計算精度來觀察這個影響。
我們將對這個實驗進行的預處理叫做基於特徵的歸一化,我們使用scikit-learn的MinMaxScaler類來執行。
from sklearn.preprocessing import MinMaxScalerX_transformed = MinMaxScaler().fit_transform(X)estimator = KNeighborsClassifier()transformed_scores = cross_val_score(estimator, X_transformed, y, scoring='accuracy')print("The average accuracy for is {0:.1f}%".format(np.mean(transformed_scores) * 100))
預處理是數據挖掘管道中的一個關鍵步驟,它可能意味著結果之間的巨大差異。
08
Pipeline
隨著實驗的增長,操作的複雜性也在增加。我們可能會拆分數據集,對特徵進行二元化,執行基於特徵的縮放,執行基於樣本的縮放,以及更多的操作。追蹤這些操作可能會變得相當混亂,並可能導致無法複製結果。問題包括忘記了一個步驟,錯誤地應用了一個變換,或者添加了一個不需要的變換。
在後面的章節中,我們將使用更高級的測試方法,而設置管道是確保代碼複雜度不至於不可收拾地增長的好方法。
from sklearn.pipeline import Pipelinescaling_pipeline = Pipeline([('scale', MinMaxScaler()),('predict', KNeighborsClassifier())])scores = cross_val_score(scaling_pipeline, X, y, scoring='accuracy')print("The pipeline scored an average accuracy for is {0:.1f}%".format(np.mean(transformed_scores) * 100))
完整代碼已上傳至github :
https://github.com/neowalter/DA-tour/tree/master/charpter2
END
其他筆記推薦
項目管理學習筆記匯總