數據挖掘入門系列教程(三)之scikit-learn框架基本使用(以K近鄰算法爲例)

數據挖掘入門系列教程(三)之scikit-learn框架基本使用(以K近鄰算法爲例)

數據挖掘入門系列博客:https://www.cnblogs.com/xiaohuiduan/category/1661541.htmlhtml

項目地址:GitHubpython

在上一篇博客中,咱們使用了簡單的OneR算法對Iris進行分類,在這篇博客中,我將介紹數據挖掘通用框架的搭建以及使用(以scikit-learn框架爲例子),並以K近鄰算法爲例展現過程。git

簡介

在介紹框架以前,有幾個重要的概念以下所示:github

  • 估計器(Estimator):用於分類,聚類和迴歸分析。
  • 轉換器(Transformer):用於數據的預處理和數據轉換。
  • 流水線(Pipeline):組合數據挖掘流程,便於再次使用。

至於這幾個具體是怎麼回事,下面將以具體的例子來進行展現。算法

scikit-learn 估計器

估計器,根據上面概念的解釋,咱們也知道估計器的做用是什麼了,它主要是爲了訓練模型,用於分類任務。主要有兩個主要的函數:數組

  • fit():訓練算法,裏面接受訓練集類別兩個參數。
  • predict():裏面的參數爲測試集,預測測試集的類別,返回預測後的類別數組。

大多數的scikit-learn估計器接收和輸出的數據格式均爲numpy數組或者相似的格式。markdown

下面將介紹使用scikit-learn實現KNN算法,關於KNN算法的一些介紹,能夠去參考一下我上一篇的博客app

加載數據集

其中,在這裏使用的數據集是叫作電離層(Ionosphere)。簡單點來講,經過採集的數據來判斷是否存在自由電子,存在則爲"g",不存在則爲'b'。下圖是一些數據的展現。框架


咱們目標就是創建分類器,自動判斷數據的好壞。dom

數據集在這裏:GitHub,該數據是CSV格式的。每一行數據有35個值,前34個爲採集數據,最後一個表示該數據是否可以判斷自由電子的存在。

接下來展現數據的導入。

import numpy as np

# 採集數據
x = np.zeros((351,34),dtype = "float")
# 類別數據
y = np.zeros((351),dtype = "byte")

# 數據文件名
file_name = "ionosphere.data"

with open(file_name,"r") as input_file:
    reader = csv.reader(input_file)
    for i,row in enumerate(reader):
        # 只遍歷前34個數據
        datas = [float(data) for data in row[:-1]]
        x[i] = datas
        y[i] = row[-1] == 'g'

此時咱們就分別獲得了採集的數據和類別數據。接下來就是建立訓練集和測試集。這一步在前面的博客有詳細說明,就再也不解釋了。

from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test = train_test_split(x,y,random_state = 14)

進行fit訓練

在前面咱們說過,咱們使用KNN算法實現數據的分類,可是須要咱們實現KNN的函數嗎?儘管KNN的實現並非很難,可是scikit-learn幫咱們實現了。

經過下面的代碼,咱們導入了一個K近鄰的分類器,其中裏面默認$K = 5$,咱們能夠本身進行調整K的取值。

from sklearn.neighbors import KNeighborsClassifier
estimator = KNeighborsClassifier()

前面咱們說過estimator有兩個重要的函數fit和predict,這裏就讓咱們來進行訓練吧!

estimator.fit(x_train,y_train)

在上面咱們經過fit函數導入訓練集和訓練類別就完成了KNN算法的訓練,而後咱們就能夠進行預測了。其中使用predict函數,使用測試數據集做爲參數,返回預測的類別。

y_predict = estimator.predict(x_test)
accuracy = np.mean(y_predict == y_test) * 100
print("精準度{0:.2f}%".format(accuracy))

最後的結果以下圖:


上面的結果與train_test_split的隨機數和測試集的大小有關。

拋開測試集的大小不談,經過改變隨機數,咱們發現,精準度會隨着隨機數的改變而發生較大的變化。下圖是隨機種子爲2的時候的精準度。


這個時候就會有一個疑問,若是個人運氣很差,隨機分割的訓練集沒有給好,即便再好的分類算法豈不是會獲得一個很差的分類結果?對,臉黑的話的確會有這種狀況。


那怎麼解決呢?若是咱們多進行幾回切分,並在在切分訓練集和測試集的時候每一次都與上一次不同就行了,而且每一條數據都被用來測試一次就更好了。算法描述以下。

  • 將整個大數據集分爲幾個部分。
  • 循環執行如下操做:
    • 將其中一部分做爲當前測試集
    • 用剩餘部分訓練算法
    • 在當前測試集上測試算法
  • 記錄每次得分,而後獲得平均分。
  • 每條數據只在訓練集出現一次。

以上的說法叫作交叉驗證。emm,夢想是好的,現實中更是好的,scikit-learn提供了一些交叉驗證的方法。咱們導入便可:

# 進行交叉驗證
from sklearn.model_selection import cross_val_score

cross_val_score默認使用Stratified K Fold方法切分數據集,它大致上保
證切分後獲得的子數據集中類別分佈相同,以免某些子數據集出現類別分佈失衡的狀況。這個默認作法很不錯,現階段就再也不把它搞複雜了。

cross_val_score裏面傳入估計器,數據集,類別集以及scoring。

這裏簡單的說一下scoring的做用。簡單來講他是一個計分器,來決定計分的規則。而傳入accuracy表明預測的結果要徹底的匹配測試集中的類別。官方的解釋以下圖。


scores = cross_val_score(estimator, x, y, scoring='accuracy') 
average_accuracy = np.mean(scores) * 100 
print("平均的精準度爲{0:.2f}%".format(average_accuracy))

最終的結果以下圖:


設置參數

前面咱們說過,默認的KNN估計器中$K = 5$,那麼他是否是最好的呢?不必定!!K太小時,分類結果容易收到干擾,過大時,又會減弱近鄰的影響。所以咱們但願設置一個合理的K,這個時候,咱們可使用一個for循環,遍歷K的取值,來選擇一個比較好的取值。

# 保存每一次的平均分數
avg_scores = []
# 遍歷k的取值從1到25
for i in range(1,25):
    estimator = KNeighborsClassifier(i)
    scores = cross_val_score(estimator, x, y, scoring='accuracy') * 100
    avg_scores.append(np.mean(scores))

爲了更加的形象化,選擇使用matplotlib 進行畫圖。

from matplotlib import pyplot as plt
x_len = list(range(1,len(avg_scores)+1))
plt.plot(x_len,avg_scores, '-x',color = "r")

最後的結果以下圖所示:


總的來講,隨着$K$值的增長,準確度逐漸下降。

預處理

數據挖掘的路不可能一路順風,極可能咱們就被第一波數據集的浪潮給拍死在岸邊上。由於咱們的數據集極可能中間的某一些數據有問題,或者說有可能特徵的取值千差萬別,也有可能某些特徵沒有區分度等等緣由。這個時候咱們就須要對數據集進行預處理。

選擇具備區分度,建立新的特徵,對數據進行清洗……這些都屬於預處理的範疇。在scikit-learn中,預處理工具叫作轉換器(Transformer),它接受原始數據集,返回轉換後的數據集。轉換器主要有如下三個函數:

  • fit():訓練算法,設置內部參數。
  • transform():數據轉換。
  • fit_transform():合併fit和transform兩個方法。

任然以上面的Ionosphere爲例子,讓咱們來對數據集進行一些破壞,而後進行訓練。

x_broken = np.array(x)
# 對numpy數組進行切片,對於每一列,每隔2個單位除以10
x_broken[:,::2] /= 10

estimator = KNeighborsClassifier()
scores = cross_val_score(estimator, x_broken, y, scoring='accuracy') 
average_accuracy = np.mean(scores) * 100 
print("平均的精準度{0:.2f}%".format(average_accuracy))


預處理有不少種方式,其中有一個方式稱之爲歸一化,也就是說將特徵值規範到01之間,最小值爲0,最大值爲1,其他值介於01之間。

接下來讓咱們對x_broken進行歸一化預處理。在scikit-learn中提供了一系列的預處理器,經過調用預處理器的轉換函數,能夠完成數據集的轉換。

  • sklearn.preprocessing.MinMaxScaler:使數據歸一化

  • sklearn.preprocessing.Normalizer:使每條數據各特徵值的和爲1

  • sklearn.preprocessing.StandardScaler:使各特徵的均值爲0,方差爲1

  • sklearn.preprocessing.Binarizer:使數值型特徵的二值化,大於閾值的爲1,反之爲0

# 歸一化
from sklearn.preprocessing import MinMaxScaler
x_formed = MinMaxScaler().fit_transform(x_broken)

# 而後進行訓練
estimator = KNeighborsClassifier()
scores = cross_val_score(estimator, x_formed, y, scoring='accuracy') 
average_accuracy = np.mean(scores) * 100 
print("平均的精準度{0:.2f}%".format(average_accuracy))

歸一化以後的精準度以下圖:


流水線

在上面咱們看到,進行數據挖掘有不少步驟須要去作:

  • 預處理數據集
  • 對數據集進行切割
  • 尋找最好的參數
  • ……

而隨着數據集的增長以及精準度的要求,實驗的操做複雜度愈來愈大,若是中間某一個步驟出現問題,好比說數據轉換錯誤,拉下一個步驟……

流水線結構能夠解決這個問題。讓咱們來導入它吧:

from sklearn.pipeline import Pipeline

咱們能夠將Pipeline比喻成生產車間的流水線,原材料按順序一個一個的經過步驟加工,而後纔可以造成一個完整的產品。固然此pipeline非此流水線,可是哲學思想倒是差很少的。

首先,讓咱們來看一看Pipeline對象一部分的介紹信:

Pipeline of transforms with a final estimator.

Sequentially apply a list of transforms and a final estimator.Intermediate steps of the pipeline must be transforms, that is, they must implement fit and transform methods.The final estimator only needs to implement fit.The transformers in the pipeline can be cached using memory argument.

The purpose of the pipeline is to assemble several steps that can be cross-validated together while setting different parameters.For this, it enables setting parameters of the various steps using their names and the parameter name separated by a '__', as in the example below. A step's estimator may be replaced entirely by setting the parameter with its name to another estimator, or a transformer removed by setting it to 'passthrough' or None.

簡單點來講,在這條流水線中,前面的步驟是一系列的transform,最後一個步驟必須是estimator。在transform中必須實現fittransform函數,而最後的estimator中必須實現fit函數。具體怎麼使用,讓咱們來看一看吧。

from sklearn.pipeline import Pipeline

mining_pipe = Pipeline(
    [
       ('預處理',MinMaxScaler()),
        ('估計器',KNeighborsClassifier())
    ],
    verbose=True
)

在pipeline中,步驟使用的是元組來表示:(「名稱」,步驟)。名稱只是一個稱呼,all is ok!後面的步驟則就是estimator或者transfrom。verbose表明是否查看每個步驟的使用時間。

運行流水線很簡單:

# 傳入pipeline參數
scores = cross_val_score(mining_pipe, x_broken, y, scoring='accuracy') 

average_accuracy = np.mean(scores) * 100 
print("平均的精準度{0:.2f}%".format(average_accuracy))

結果以下圖:


時間爲0s,這就很尷尬了。估計是數據集過小了,數據還沒反應過來就被處理了。結果是82.90%,與上一步的結果同樣。

結尾

這篇博客主要是介紹scikit-learn的使用流程和使用方法。

GitHub地址:GitHub

參考書籍:Python數據挖掘入門與實踐

相關文章
相關標籤/搜索