訓(xùn)練數(shù)據(jù)集與測(cè)試數(shù)據(jù)集
當(dāng)我們拿到一組數(shù)據(jù)之后梳星,通常我們需要把數(shù)據(jù)分割成兩部分,即訓(xùn)練數(shù)據(jù)集和測(cè)試數(shù)據(jù)集慈俯。
訓(xùn)練數(shù)據(jù)集被用于建立數(shù)學(xué)模型归苍,而測(cè)試數(shù)據(jù)集被用于檢驗(yàn)我們建立的模型的準(zhǔn)確度。
要封裝一個(gè)我們的kNN算法麸恍,我們先要實(shí)現(xiàn)對(duì)數(shù)據(jù)的自動(dòng)分割灵巧。代碼實(shí)現(xiàn)如下:
import numpy as np
def train_test_split(X, y, test_ratio=0.2, seed=None):
"""將數(shù)據(jù) X 和 y 按照test_ratio分割成X_train, X_test, y_train, y_test"""
assert X.shape[0] == y.shape[0], \
"the size of X must be equal to the size of y"
assert 0.0 <= test_ratio <= 1.0, \
"test_ration must be valid"
if seed:
np.random.seed(seed)
shuffled_indexes = np.random.permutation(len(X))
test_size = int(len(X) * test_ratio)
test_indexes = shuffled_indexes[:test_size]
train_indexes = shuffled_indexes[test_size:]
X_train = X[train_indexes]
y_train = y[train_indexes]
X_test = X[test_indexes]
y_test = y[test_indexes]
return X_train, X_test, y_train, y_test
我們來(lái)講解一下這個(gè)代碼。
第一步抹沪,導(dǎo)入我們需要用到的numpy庫(kù)刻肄。
第二步,定義train_test_split函數(shù)融欧。函數(shù)有四個(gè)返回值:
- X和y是我們的原數(shù)據(jù)(這里提一點(diǎn)敏弃,大寫(xiě)X是指這是一個(gè)矩陣,小寫(xiě)y是指這是一個(gè)向量)噪馏;
- test_radio是我們的分割比例麦到,我這里給的是0.2,即80%的訓(xùn)練數(shù)據(jù)欠肾,20%的測(cè)試數(shù)據(jù)瓶颠;
- seed種子的引入是應(yīng)為我們需要使用隨機(jī)數(shù), 計(jì)算機(jī)并不能產(chǎn)生真正的隨機(jī)數(shù)刺桃,如果你不設(shè)種子步清,計(jì)算機(jī)會(huì)用系統(tǒng)時(shí)鐘來(lái)作為種子,如果你要模擬什么的話虏肾,每次的隨機(jī)數(shù)都是不一樣的,這樣就不方便你研究欢搜,如果你事先設(shè)置了種子封豪,這樣每次的隨機(jī)數(shù)都是一樣的,便于重現(xiàn)你的研究炒瘟,也便于其他人檢驗(yàn)?zāi)愕姆治鼋Y(jié)果吹埠。
第三步是添加斷言。應(yīng)為我們傳入的數(shù)據(jù)X和y實(shí)際上都是經(jīng)過(guò)處理的數(shù)據(jù)疮装。其中:
- X是一個(gè)m*n的矩陣缘琅,其中m是指總共有m條數(shù)據(jù)(矩陣的行),n則是指每條數(shù)據(jù)有n個(gè)特征數(shù)據(jù)(矩陣的列)廓推;
- 而y則是一個(gè)有m個(gè)元素的向量刷袍,記錄了X中每一條數(shù)據(jù)的狀態(tài)。
例如在上一篇引入kNN概念的簡(jiǎn)書(shū)中我們提到的乳腺癌數(shù)據(jù)樊展,X是一個(gè)10*2的矩陣呻纹,代表它有10條數(shù)據(jù)堆生,每條數(shù)據(jù)有2個(gè)記錄特征的元素,分別是發(fā)現(xiàn)腫瘤的時(shí)間和腫瘤的大小雷酪。y中元素(10個(gè)元素)則與X的每一條數(shù)據(jù)(10條數(shù)據(jù))一一對(duì)應(yīng)淑仆,表示前五條數(shù)據(jù)狀態(tài)為0(良性),后五條數(shù)據(jù)狀態(tài)為1(惡性)哥力。
raw_data_X = [[2.393533211, 2.331273381],
[3.110073483, 1.781539638],
[1.343808831, 3.368360954],
[3.882294042, 2.979179110],
[2.280362439, 2.866990263],
[7.423436942, 4.696522875],
[5.745051997, 3.033989803],
[9.172168622, 2.511101045],
[7.792783481, 3.424088941],
[5.839820817, 2.791637231]
]
raw_data_y = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]
理解了我們傳入的數(shù)據(jù)之后再來(lái)說(shuō)這兩句斷言蔗怠,第一句斷言要求傳入的X的行數(shù)與y中元素個(gè)數(shù)相同,保證傳入的數(shù)據(jù)是有效的吩跋。
第二句斷言要求test_radio在0-1之間寞射。
第四步,我們要打亂傳入的數(shù)據(jù)钞澳。應(yīng)為經(jīng)過(guò)處理的數(shù)據(jù)送到我們手中怠惶,數(shù)據(jù)中的y通常是按照一定的規(guī)律進(jìn)行了排序。比如上一節(jié)使用的乳腺癌數(shù)據(jù)轧粟,前5個(gè)為0策治,后5個(gè)為1。我們使用的是numpy中的permutation函數(shù)兰吟,打亂索引通惫。
第五步就是實(shí)現(xiàn)分割,這一部分代碼簡(jiǎn)單明了混蔼,就不解釋了履腋。最后我們來(lái)看下效果。為了能直觀感受到效果惭嚣,我們引入sklearn中一個(gè)經(jīng)典的鳶尾花數(shù)據(jù)集遵湖。
整個(gè)代碼實(shí)現(xiàn)如下:
from sklearn import datasets
from playKNN import model_selection
iris = datasets.load_iris() # 從sklearn中導(dǎo)入鳶尾花數(shù)據(jù)集
X = iris.data
y = iris.target
print(X.shape)
print(y.shape)
print(y[:10])
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y)
print(X_train.shape)
print(y_train.shape)
print(X_test.shape)
print(y_test.shape)
print(y_test[:10])
# 輸出結(jié)果
(150, 4)
(150,)
[0 0 0 0 0 0 0 0 0 0]
(120, 4)
(120,)
(30, 4)
(30,)
[2 1 2 2 1 0 0 1 2 1]
首先從sklearn中導(dǎo)入datasets,我們的鳶尾花數(shù)據(jù)集就保存在里面晚吞。
然后我把我們的數(shù)據(jù)分割放在一個(gè)叫playKNN的包里面延旧,我們從其中引入我們封裝的model_selection。
導(dǎo)入datasets中的數(shù)據(jù)庫(kù)使用的是load槽地,然后pycharm會(huì)跳出提示你需要導(dǎo)入哪些庫(kù)迁沫,選擇load_iris。
用numpy的shape查看我們的數(shù)據(jù)捌蚊,可以知道鳶尾花數(shù)據(jù)集中X的150*4的矩陣集畅,y是有150個(gè)元素的向量。
我們看下y的前十個(gè)10據(jù)缅糟,[0 0 0 0 0 0 0 0 0 0]挺智,印證了我們的猜測(cè),處理好的數(shù)據(jù)通常會(huì)按照一定的規(guī)律進(jìn)行排序窗宦!
之后使用我們封裝的model_selection逃贝,得到X_train,y_train,X_test,y_test谣辞。分別用shape方法查看,(120, 4)沐扳,(120,)泥从,(30, 4),(30,)沪摄。
最后查看下y_test的前10條信息躯嫉,[2 1 2 2 1 0 0 1 2 1],鳶尾花數(shù)據(jù)集共有0杨拐,1祈餐,2三種狀態(tài)值,代表三個(gè)品種的鳶尾花哄陶,都出現(xiàn)在了y_test的前10條信息中帆阳,說(shuō)明我們的數(shù)據(jù)分割是有效的。