1. 程式人生 > >Udacity機器學習入門——交叉驗證(cross-validation)

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)