Udacity機器學習入門——交叉驗證(cross-validation)
測試資料可以讓你評估你的分類器或迴歸在獨立資料集上的效能,還能幫助你避免過度擬合
在sklearn中訓練/測試分離
載入資料集以適應線性SVM:
from sklearn import datasets
from sklearn.svm import SVC
iris = datasets.load_iris()
features = iris.data
labels = iris.target
快速地取樣一個訓練集,同時支援40%的資料來測試(評估)我們的分類器:#將資料集拆分為訓練和測試集 from sklearn.model_selection import train_test_split features_train, features_test, labels_train, labels_test = cross_validation.train_test_split(iris.data,iris.target,test_size = 0.4,random_state=0) clf = SVC(kernel="linear", C=1.) clf.fit(features_train, labels_train) print clf.score(features_test, labels_test)
何處使用訓練資料,何處使用測試資料
流程:首先將全部資料分為訓練資料集和測試資料集,接下來使用PCA一種特徵轉換選出一些主成分,將其放入支援向量機一種分類方法svc
1. pca.fit(training_features)在訓練特徵中找到主成分
2. pca.transform(training_features)使用發現的fit將資料實際轉化為新的主成分表示
3. svc.train(training_features) 訓練支援向量機分類器
4. pca.transform(test_features)
因為沒有再次呼叫pca.fit,因此將使用在訓練資料中發現的主成分表示我的測試特徵,如果此時使用測試特徵重新擬合PCA,是不正確的
5. svc.predict(test_features)
支援向量機對測試資料集進行預測
練習:K折交叉驗證
兩個集合最大化——儘可能多的訓練集資料點以獲得最佳學習效果,儘可能多的測試集資料項來獲得最佳驗證,此時為了尋找折中點涉及到交叉驗證
基本要點:將訓練資料評分到相同大小的k個容器內,例如200個訓練資料點,10個容器,則每個容器20個訓練資料點,在k折交叉驗證中,你將執行k此單獨的學習試驗,在每次實驗中,你將從這k個子集中挑選一個作為驗證集,剩下k-1個容器放在一起作為訓練集,然後訓練你的機器學習演算法,再再驗證集上驗證效能,交叉驗證中的要點是這個操作會執行k次,然後將k次試驗的測試結果取平均值
>>> import numpy as np
>>> from sklearn.model_selection import KFold
>>> X = ["a", "b", "c", "d"]
>>> kf = KFold(n_splits=2)
>>> for train, test in kf.split(X):
... print("%s %s" % (train, test))
[2 3] [0 1]
[0 1] [2 3]
train=訓練集中使用的所有資料點的索引值的集合,test=測試集使用的所有索引值
sklearn中的K折CV
#!/usr/bin/python
import sys
from time import time
from sklearn.cross_validation import KFold
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_selection import SelectPercentile,f_classif
from sklearn.naive_bayes import GaussianNB
from sklearn.metrics import accuracy_score
sys.path.append("../tools/")
from email_preprocess_kfold import preprocess
clf = GaussianNB()
t0 = time()
authors,word_data = preprocess()
kf = KFold(len(authors),2)
for train_indices,test_indices in kf:
#make training and testing datasets
features_train = [word_data[ii] for ii in train_indices]
features_test = [word_data[ii] for ii in test_indices]
author_train = [authors[ii] for ii in train_indices]
author_test = [authors[ii] for ii in test_indices]
#TFIDF and feature selection
vectorizer = TfidfVectorizer(sublinear_tf=True,max_df=0.5,stop_words='english')
features_train_transformed = vectorizer.fit_transform(features_train)
features_test_transformed = vectorizer.transform(features_test)
selector = SelectPercentile(f_classif,percentile=10)
selector.fit(features_train_transformed,author_train)
features_train_transformed = selector.transform(features_train_transformed).toarray()
features_test_transformed = selector.transform(features_test_transformed).toarray()
clf.fit(features_train_transformed, author_train)
print "training time:", round(time()-t0, 3), "s"
t0 = time()
pred = clf.predict(features_train_transformed)
print "predicting time:", round(time()-t0, 3), "s"
acc = accuracy_score(pred, author_test)
print 'accuracy:',round(acc,3)
從中可以看出精確度出現了嚴重問題,為了查詢問題,輸入幾個print語句
for train_indices,test_indices in kf: #make training and testing datasets -snip- author_test = [authors[ii] for ii in test_indices] print train_indices print authors_train print authors_test -snip-
print train_indices
檢視訓練資料集中的所有事件指數是否存在 所有某一特定的事件型別最後都屬於訓練資料集,而所有另一特定的事件型別最後都屬於測試資料集 這種情況,如果存在這種情況,針對一種型別事件的訓練不會對另一事件進行分類有幫助
print authors_train
打印出訓練資料集中所有事件的標籤
print authors_test
打印出測試資料集中的作者,來檢視訓練資料集和測試資料集中的事件是否有某些重要的區別
事件順序並沒有打亂,只是從中間切割成兩部分,導致用屬於所有某一特定的事件型別做訓練集訓練,去分類屬於另一特定事件型別的測試集
sklearn KFold的工作原理將資料劃分為大小相同的K部分,不會對事件進行任何型別的亂排序。因此如果你的資料裡的表現方式是,尤其是類別上存在某些模式,然後這些模式會反映在大量的特定的標籤中,最終會體現在驗證的特定折上
通過一些引數的調整即可獲得最佳效能的,使用某種猜測然後檢驗的方法調整這些引數,可以使用交叉驗證自動執行很多這類測試,並選擇可以實現最佳效能的引數調整方式。如下
sklearn中的GridSearchCV
GridSearchCV 用於系統地遍歷多種引數組合,通過交叉驗證確定最佳效果引數。它的好處是,只需增加幾行程式碼,就能遍歷多種組合。
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC
parameters = {'kernel':('linear', 'rbf'), 'C':[1, 10]}
svr = svm.SVC()
clf = grid_search.GridSearchCV(svr, parameters)
clf.fit(iris.data, iris.target)
逐行進行說明。
parameters = {'kernel':('linear', 'rbf'), 'C':[1, 10]}
引數字典以及他們可取的值。在這種情況下,他們在嘗試找到 kernel(可能的選擇為 'linear' 和 'rbf' )和 C(可能的選擇為1和10)的最佳組合。
這時,會自動生成一個不同(kernel、C)引數值組成的“網格”:
('rbf', 1) | ('rbf', 10) |
---|---|
('linear', 1) | ('linear', 10) |
各組合均用於訓練 SVM,並使用交叉驗證對錶現進行評估。
svr = svm.SVC()
與建立分類器有點類似,但是請注意,“clf” 到下一行才會生成—這兒僅僅是在說採用哪種演算法。另一種思考方法是,“分類器”在這種情況下不僅僅是一個演算法,而是演算法加引數值。請注意,這裡不需對 kernel 或 C 做各種嘗試;下一行才處理這個問題。
clf = grid_search.GridSearchCV(svr, parameters)
分類器建立。 傳達演算法 (svr) 和引數 (parameters) 字典來嘗試,它生成一個網格的引數組合進行嘗試。
clf.fit(iris.data, iris.target)
擬合函式現在嘗試了所有的引數組合,並返回一個合適的分類器,自動調整至最佳引數組合。現在您便可通過 clf.best_params_
來獲得引數值。
練習:請參考特徵臉方法程式碼。使用 GridSearchCV 調整了 SVM 的哪些引數?C、gamma
param_grid = {'C': [1e3, 5e3, 1e4, 5e4, 1e5],
'gamma': [0.0001, 0.0005, 0.001, 0.005, 0.01, 0.1], }
迷你專案:
第一部分:
你將先開始構建想象得到的最簡單(未經過驗證的)POI 識別符。 本節課的初始程式碼 (validation/validate_poi.py) 相當直白——它的作用就是讀入資料,並將資料格式化為標籤和特徵的列表。 建立決策樹分類器(僅使用預設引數),在所有資料(你將在下一部分中修復這個問題!)上訓練它,並打印出準確率。 這是一顆過擬合樹。
0.989473684211
from sklearn.tree import DecisionTreeClassifier
clf = DecisionTreeClassifier()
clf.fit(features,labels)
print clf.score(features,labels)
第二部分
現在,你將新增訓練和測試,以便獲得一個可靠的準確率數字。 使用 sklearn.cross_validation 中的 train_test_split 驗證; 將 30% 的資料用於測試,並設定 random_state 引數為 42(random_state 控制哪些點進入訓練集,哪些點用於測試;將其設定為 42 意味著我們確切地知道哪些事件在哪個集中; 並且可以檢查你得到的結果)。更新後的準確率是多少?
0.724137931034
#!/usr/bin/python
import pickle
import sys
sys.path.append("../tools/")
from feature_format import featureFormat, targetFeatureSplit
data_dict = pickle.load(open("../final_project/final_project_dataset.pkl", "r") )
### first element is our labels, any added elements are predictor
### features. Keep this the same for the mini-project, but you'll
### have a different feature list when you do the final project.
features_list = ["poi", "salary"]
data = featureFormat(data_dict, features_list)
labels, features = targetFeatureSplit(data)
from sklearn.model_selection import train_test_split
features_train, features_test, labels_train, labels_test = train_test_split(features,labels,test_size=0.3,random_state=42)
### it's all yours from here forward!
from sklearn.tree import DecisionTreeClassifier
clf = DecisionTreeClassifier()
clf.fit(features_train,labels_train)
result = clf.predict(features_test)
from sklearn.metrics import accuracy_score
print accuracy_score(labels_test,result)
#print clf.score(features_test,labels_test)