因某次誤打誤撞闖入成大數據分析的圈子,在完全沒有底子的狀態下,完全無法吸收內容,只是簡單吸收了一些 KeyWord,當時聽到的包含 Kaggle、CNN,當下聽到 CNN 還以為是管媒體的那個單位,經過簡單的講解也才初步了解演算法,以及演算法目的,不過今天文章要寫的無關 CNN,而是分群演算法,以及預測 Kaggle 上的一到題目 Digit Recognizer。
前言
由於網路上已經有太多 Kaggle 的介紹文了,所以本篇僅會簡單帶過,並且使用前幾篇起手式的概念完成 Kaggle 上的一到題目 Digit Recognizer。
[Python] 跌入數據分析的坑 – 談談機器學習入門 (三)
[Python] 跌入數據分析的坑 – 談談起手式 Pandas (二)
[Python] 跌入數據分析的坑 – 談談起手式 NumPy (一)
Kaggle
Kaggle 就如同 ITSA、ACM 等等的程式競賽一般,但 Kaggle 是專門針對數據建模和數據分析的競賽平台,從練習的題目、競賽,到企業徵才都有相當的規模,新手也可以在 Kaggle 討論區上,透過閱讀別人分享的分析方法及經驗學習。
Digit Recognizer
Digit Recognizer 是一到圖形識別的題目,以 MNIST 手寫資料集抽樣改編後做為訓練、測試資料,透過演算法對訓練資料機器學習之後,並且預測測試資料的真實數字為何。
kNN 近鄰演算法
kNN 全名為 K Nearest Neighbor,關於 kNN 可以參考文章「kNN算法的原理與實現」,內文寫得很清楚,雖然文中有實作 Knn 演算法,但本篇文章所採用的是 Scikit-learn 套件中的 neighbors.KNeighborsClassifier 來實作 kNN。
開始預測
題目 Digit Recognizer 提供三個檔案,分別為提交範例資料:「sample_submission.csv」、測試資料:「test.csv」、訓練資料:「train.csv」。
起手式
如同之前的起手式文章一樣,先把必要的函式庫讀取進來。
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
載入演算法套件
關於 train_test_split
在先前起手式系列文章中已經有介紹過了,另外的 KNeighborsClassifier
也就是本次要用來預測的演算法 kNN 套件。
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
讀取相關資料
接著要將訓練資料、測試資料一一讀進來。
train = pd.read_csv("train.csv")
test = pd.read_csv("test.csv")
透過 shape 可以看出 train
有 42000 列、785 欄,其中第一欄為所有訓練資料集的對應數字,也就是訓練資料的答案。
資料前處理
上頭讀取資料已經說明,第一欄所代表的資料為訓練資料的對應數字,所以要先將其分割出來,並且將測試資料從 DataFrame
轉為 numpy.Array
。
O_X_train = train.values[0:,1:]
O_y_train = train.values[0:,0]
test = test.values
為了讓預測結果可以更接近現實,所以將資料在各別複製一份出來,並且做 Nomalizing,非 0 即 1 的處理。
import copy
nomalizing_X_train = copy.deepcopy(O_X_train)
nomalizing_y_train = copy.deepcopy(O_y_train)
nomalizing_X_train[nomalizing_X_train > 0] = 1
nomalizing_y_train[nomalizing_y_train > 0] = 1
效果可以參考下圖。
接著將 Nomalizing 的資料與原本的訓練資料集做整合,使用 concatencate
方法,要注意到的是僅使用到第一個 argv,所以使用小括號把第一個 argv 框住。
O_X_train = np.concatenate((O_X_train, nomalizing_X_train))
O_y_train = np.concatenate((O_y_train, nomalizing_y_train))
之後就是從訓練資料、測試資料中,在切分成「訓練資料:X_train」、「訓練資料答案:y_train」、「測試資料:X_test」、「測試資料答案:y_test」,train_test_split
的相關用法也有在前幾篇起手式的文中提過,本次取樣比為 8:2
。
X_train, X_test, y_train, y_test = train_test_split(O_X_train,
O_y_train,
test_size = 0.2,
random_state = 87)
使用 kNN 演算法預測
在使用 kNN 預測之前,要先得知道最佳的 k 值為何,由於預測會花費大部分的時間,可以透過迴圈,並藉由 accuracy_score
方法,來計算預測的分數,並且建構一個計時器,來計算預測一次 k 值的時間。
from sklearn.metrics import accuracy_score
import time
解釋以下程式碼,首先宣告 k_score
來紀錄每一次計算結果的成績,test_range
為測試的範圍,由於全部資料有 48000 筆,抽樣 8:2 之後,也有 33600 筆資料,如果要全測的話,會相當耗時,所以將 test_range
調整為 10000,接著計算 1 到 6 的 k 值。
k_score = []
test_range = 10000
for k in range(1, 6 + 1):
print("k = {} Training.".format(k))
start = time.time()
knn = KNeighborsClassifier(n_neighbors = k)
knn.fit(X_train, y_train)
predict_result = knn.predict(X_test[:test_range])
predict_score = accuracy_score(y_test[:test_range], predict_result)
k_score.append(predict_score)
end = time.time()
print("Score: {}.".format(predict_score))
print("Complete time: {} Secs.".format(end - start))
print(k_score)
以下為輸出結果:
k = 1 Training.
Score: 0.9803.
Complete time: 911.3254759311676 Secs.
k = 2 Training.
Score: 0.9779.
Complete time: 908.3969151973724 Secs.
k = 3 Training.
Score: 0.9814.
Complete time: 911.6351885795593 Secs.
k = 4 Training.
Score: 0.9803.
Complete time: 910.7894451618195 Secs.
k = 5 Training.
Score: 0.9807.
Complete time: 908.5058484077454 Secs.
k = 6 Training.
Score: 0.9805.
Complete time: 910.5136153697968 Secs.
[0.9803, 0.9779, 0.9814, 0.9803, 0.9807, 0.9805]
也可以將,輸出的結果以 plt
繪製出來,程式碼如下:
print (k_score)
plt.plot(range(1, 6 + 1), k_score)
plt.xlabel('k')
plt.ylabel('k_score')
plt.show()
觀察輸出的圖形,可以筆單純看數字結果來得清楚,可以清楚得知 k = 3
的時候分數最高。
所以採用 k = 3
來當作預測基準,並用來預測 test.csv
的資料,首先將所有測試資料與訓練資料(包括 Nomalizing 的資料),程式碼如下:
k = 3
print("k = {} Training.".format(k))
start = time.time()
knn = KNeighborsClassifier(n_neighbors = k)
knn.fit(O_X_train, O_y_train)
predict_result = knn.predict(test)
end = time.time()
print("Complete time: {} Secs.".format(end - start))
輸出訓練時間為 1602.5 Secs
相當於 26 分鐘:
k = 3 Training.
Complete time: 1602.5110640525818 Secs.
要將預測結果資料打包成範例 sample_submission.csv
的形式,可以藉由 pandas
套件來處理,首先有 ImageId
與 Label
兩個欄位,ImageId
列的值為測試資料的總數 28000,Label
則存放我們的預測結果,程式碼如下:
pd.DataFrame(
{
"ImageId": list(range(1,len(predict_result)+1)),
"Label": predict_result
}
).to_csv('Digit_Recogniser_Result_Double.csv', index=False, header=True)
將答案送出之後,預測結果為 0.96814
,。
由於會顯示 Your submission scored 0.21514, which is not an improvement of your best score. Keep trying!
是因為站長最後一次送的時候,是將 test 的資料也做 Nomalizing,顯然效果不彰,但 0.96814 的結果仍為本次文章中的預測方法。
結論
第一次參與這種競賽,拿到預測率高達九成六的成績也已經心滿意足了,至於要如何做資料的前處理、採用什麼演算法,多多少少都會影響預測的結果,這就是此領域的學習精華,關於該題目 Digit Recognizer
,討論區有不少人直接使用 MNIST
的資料集來進行訓練,也得到了很高,甚至預測精準度 1.0 的結果,但有違該題目的精神。
如果有網友們剛踏入此領域,希望這篇文章能夠幫助到你們,同時也歡迎各位一同討論、學習,互相成長。