數據給定&模型給定的前提下,怎麼提高訓練模型的效果?
數據和模型給定之後,我們只有一條路:提高數據的利用效率。方法有兩個:
1)使用train_test_split函數分成訓練集和測試集;
2)通過CrossValidaton (cross_val_score函數) 進一步壓榨訓練集的價值;
1) 一般我們用的方法是:將原始數據集分爲 訓練數據集 & 測試數據集。
優點:思路正確,但僅僅是思路正確。
缺點:思路正確,但是方法不夠高明。
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn import datasets # sklearn 自帶的給學習人員用的數據集
from sklearn import svm
# 首先,引入原始數據集
x, y = datasets.load_iris(return_X_y=True) # iris: 鳶尾花數據集
print(x.shape)
print(y.shape)
"""
結果如下:
(150, 4)
(150,)
"""
# 其次,把數據集按6:4的比例劃分爲訓練數據集和測試數據集
x_train, x_test, y_train, y_test = train_test_split(x, y, train_size=0.6, random_state=0) # random_state的用處見下邊註釋。
print(x_train.shape)
print(x_test.shape)
print(y_train.shape)
print(y_test.shape)
"""
結果如下:
(90, 4)
(60, 4)
(90,)
(60,)
"""
# 最後,用SVC模型測試一下:
clf = svm.SVC(kernel='linear', C=1) # C的作用見下便註釋
clf.fit(x_train, y_train)
score = clf.score(x_test, y_test)
print(score)
"""
0.9666666666666667
"""
註釋:
- train_test_split(random_state=0):一方面,random_state不設定的話,每次函數train_test_split得到的訓練集和測試集都不一樣;另一方面,random_state設定爲INT的話每次得到的訓練集和測試集保持一致(INT可以是0也可以是42,效果一樣)
- svm.SVC(C=1):kernel='linear'時,C用來告訴SVM你有多想把訓練數據正確分好類。對於一個大的C值,分類器選用margin小的超平面,代價是分類器的泛化性會降低;反之亦然,
評價:
一方面,看它的優點:如果原始數據集沒有被劃分爲 訓練數據集&測試數據集兩部分,而是直接給訓練模型的話,結果會是過擬合、泛化能力極低(即模型完美於預測原始數據,完敗於預測原始樣本集之外的任何數據);
另一方面看它的不足:
- 訓練結果更大地依賴於訓練數據集和測試數據集佔原始數據集的比重。
- 用訓練數據集得到算法參數/模型參數的方法不夠好,因爲最終的一組參數其實是從N組參數中對比得來的,這意味着測試
- 數據集的信息會被間接地泄露出來,參數調整得越多、泄露越多,使得測試數據集的意義越低;
2)一個壓榨數據價值更好的方法就是 cross-validation / CV / 交叉檢驗:
以k-fold CV爲例:仍然是把原始數據集分成訓練集和測試集,但是訓練模型的時候不適用測試集。最常見的一個叫做k_fold CV。
- 具體來說就是把訓練集平分爲k個fold,其中每個fold依次作爲測試集、餘下的作爲訓練集,進行k次訓練,得到共計k組參數。取k組參數的均值作爲模型的最終參數。
- 優點:充分壓榨了數據集的價值。在樣本集不夠大的情況下尤其珍貴。
- 缺點:運算起來花時間。
我們用SVM()/support vector machines(支持向量機)中的SVC分類算法爲例:
from sklearn.model_selection import cross_val_score
clf = svm.SVC(kernal='linear', C=1)
scores = cross_val_score(clf, x, y, cv=5)
print(scores)
print(f"Accuracy: {scores.mean():.3f},{scores.std()**2:.3f}")
"""
[0.96666667 1. 0.96666667 0.96666667 1. ]
Accuracy: 0.980,0.000
"""