一篇文章,带你明确什么是过拟合,欠拟合以及交叉验证
誤差模型:過擬合,交叉驗證,偏差-方差權衡
作者Natasha Latysheva;Charles Ravarani
發表于cambridgecoding
介紹
??在本文中或許你會掌握機器學習中最核心的概念:偏差-方差權衡.其主要想法是,你想創建盡可能預測準確而且仍能適用于新數據的模型(這是泛化).危急的是,你能夠輕松的在你制定的數據中創建過度擬合本地噪音的模型,這樣的模型是沒用的,而且導致弱泛化能力,由于噪聲是隨機的,故而在每一個數據集中是不同的.從本質上講,你希望創建僅捕獲數據集中實用成份的模型.還有一方面,泛化能力很好可是對于產生良好預測過于僵化的模型是還有一個極端(這稱之為欠擬合).
??我們使用k-近鄰算法討論并展示這些概念,k-近鄰帶有一個簡單的參數k,能夠用不同的參數清楚的展示欠擬合。過擬合以及泛化能力的思想.同一時候,平衡欠擬合和過擬合之間的相關概念稱為偏差-方差權衡.這里有一個表格概括了不管是過擬合或者欠擬合模型中一些不同但相同
??我們將解釋這些術語的意思,以及他們怎樣關聯的.相同也會討論交叉驗證,這是評估模型準確率和泛化能力的優秀指標.
??你會在未來的全部博文中遇到這些概念,將涵蓋模型優化,隨機森林,樸素貝葉斯,邏輯回歸以及怎樣將不同模型組合成為集成元模型.
產生數據
??讓我們從建立人工數據集開始.你能夠輕松的使用sklearn.datasets中的make_classification()函數做到這一點.詳細來說,你會生成相對簡單的二元分類問題.為了讓它更有趣一點,讓我們的數據呈現月牙型并加入一些隨機噪聲.這應該能讓其更真實并提高分類觀測的難度.
“`
Creating the dataset
e.g. make_moons generates crescent-shaped data
Check out make_classification, which generates linearly-separable data
from sklearn.datasets import make_moons
X, y = make_moons(
n_samples=500, # the number of observations
random_state=1,
noise=0.3
)
Take a peek
print(X[:10,])
print(y[:10])
“`
[[ 0.50316464 0.11135559]
[ 1.06597837 -0.63035547]
[ 0.95663377 0.58199637]
[ 0.33961202 0.40713937]
[ 2.17952333 -0.08488181]
[ 2.00520942 0.7817976 ]
[ 0.12531776 -0.14925731]
[ 1.06990641 0.36447753]
[-0.76391099 -0.6136396 ]
[ 0.55678871 0.8810501 ]]
[1 1 0 0 1 1 1 0 0 0]
??你剛生成的數據集例如以下圖所看到的:
“`
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColorma
%matplotlib inline # for the plots to appear inline in jupyter notebooks
Plot the first feature against the other, color by class
plt.scatter(X[y == 1, 0], X[y == 1, 1], color=”#EE3D34”, marker=”x”)
plt.scatter(X[y == 0, 0], X[y == 0, 1], color=”#4458A7”, marker=”o”)
“`
<center>
??接下來,讓我們將數據且分為訓練集 和測試集 .訓練集用于開發和優化模型.測試集全然分離,直到最后在此執行完畢的模型.擁有測試集同意你在之前看不到的數據之外,模型執行良好的預計.
“`
from sklearn.cross_validation import train_test_split
Split into training and test sets
XTrain, XTest, yTrain, yTest = train_test_split(X, y, random_state=1, test_size=0.5)
“`
??使用K近鄰(KNN)分類器預測數據集類別.Introduction to Statistical Learning第二章提供了關于KNN理論很好介紹.我是ISLR書的腦殘粉.你相同能夠看看之前文章 how to implement the algorithm from scratch in Python.
介紹KNN中的超參數K
??KNN算法的工作原理是,對新數據點利用K近鄰信息分配類別標簽.僅僅注重于和它最類似數據點的類,并分配這個新數據點到這些近鄰中最常見的類.當使用KNN,你須要設定希望算法使用的K值.
??假設K很高(k=99),模型在對未知數據點類別做決策是會考慮大量近鄰.這意味著模型是相當受限的,由于它分類實例時,考慮了大量信息.換句話說,一個大的k值導致相當”剛性”的模型行為.
??相反,假設k很低(k=1,或k=2),在做分類決策時僅僅考慮少量近鄰,這是很靈活而且很復雜的模型,它能完美擬合數據的精確形式.因此模型預測更依賴于數據的局部趨勢(關鍵的是,包括噪聲).
??讓我們看一看k=99與k=1時KNN算法分類數據的情況.綠色的線是訓練數據的決策邊界(算法中的閾值決定一個數據點是否屬于藍或紅類).
??在本文最后你會學會怎樣生成這些圖像,可是先讓我們先深入理論.
??當k=99(左),看起來模型擬合有點太平滑,對于有點接近的數據能夠忍受.模型具有低靈活性 和低復雜度 .它描繪了一個籠統的決策邊界.它具有比較高的偏差 ,由于對數據建模并不好,模型化數據的底層生成過程太過簡單,而且偏離了事實.可是,假設你扔到還有一個略微不同的數據集,決策邊界可能看起來很類似.這是不會有很大差異的穩定模型–它具有低方差.
??當k=1(右側),你能夠看到模型過度擬合噪聲.從技術上來說,在訓練集生成很完美的預測結果(在右下角的錯誤等于0.0),可是希望你能夠看到這樣的擬合方式對于單獨數據點過于敏感.牢記你在數據集中加入了噪聲.看起來模型擬合對噪聲太過重視而且擬合的很緊密.你能夠說,k=1的模型具有高靈活性 和高復雜度 ,由于它對數據調優很緊密.相同具有低偏差,假設不出意外,決策邊界肯定適合你觀測數據的趨勢.可是,在略微改變的數據上,擬合的邊界會大大改變,這將是很顯著的.K=1的模型具有高方差 .
??可是模型的泛化能力怎樣?
在新數據上表現怎樣?
??眼下你僅僅能看到訓練數據,可是量化訓練誤差沒多大用處.對模型概括剛學習的訓練集性能有多好,你不感興趣.讓我們看看在測試集表現怎樣,由于這會對模型好壞給你一個更直觀的印象.試著使用不同的K值:
from sklearn.neighbors import KNeighborsClassifier from sklearn import metrics knn99 = KNeighborsClassifier(n_neighbors = 99) knn99.fit(XTrain, yTrain) yPredK99 = knn99.predict(XTest) print "Overall Error of k=99 Model:", 1 - round(metrics.accuracy_score(yTest, yPredK99), 2) knn1 = KNeighborsClassifier(n_neighbors = 1) knn1.fit(XTrain, yTrain) yPredK1 = knn1.predict(XTest) print "Overall Error of k=1 Model:", 1 - round(metrics.accuracy_score(yTest, yPredK1), 2)
Overall Error of k=99 Model: 0.15
Overall Error of k=1 Model: 0.15
??實際上,看起來這些模型對測試集表現的大約相同出色.以下是通過訓練集學習到的決策邊界應用于測試集.看是否能找出兩個模型錯誤的預測.
??兩個模型出錯有不同的原因.看起來k=99的模型對捕獲月牙形數據特征方面表現不是很好(這是欠擬合),而k=1的模型是對噪聲嚴重的過擬合.記住,過擬合的特點是良好的訓練表現和糟糕的測試表現,你能在這里觀察到這些.
??或許k在1到99的中間值是你想要的?
knn50 = KNeighborsClassifier(n_neighbors = 50) knn50.fit(XTrain, yTrain) yPredK50 = knn50.predict(XTest) print "Overall Error of k=50 Model:", 1 - round(metrics.accuracy_score(yTest, yPredK50), 2)
Overall Error of k=50 Model: 0.11
??看起來好了點.讓我們檢查k=50時模型的決策邊界.
??不錯!模型擬合類似數據集的實際趨勢,這樣的改善體如今較低的測試誤差.
偏差-方差權衡:結論意見
??希望你如今對模型的欠擬合和過擬合有良好的理解.看如今是否理解本文開頭的全部術語.基本上,發現過擬合和欠擬合之間正確的平衡關系相當于偏差-方差權衡.
??總的來說,當你對一個數據集訓練機器學習算法,關注模型在一個獨立數據模型的表現怎樣.對于訓練集做好分類是不夠的.本質上來講,僅僅關心構建可泛化的模型–對于訓練集獲得100%的準確率并不令人印象深刻,僅僅是過擬合的指標.過擬合是緊密擬合模型,而且調優噪聲而不是信號的情況.
??更清楚的講,你不是建模數據集中的趨勢.而是嘗試建模真實世界過程,引導我們研究數據.你恰好使用的詳細數據集僅僅是基礎事實的一小部分實例,當中包括噪聲和自身的特點.
??下列匯總圖片展示在訓練集和測試集上欠擬合(高偏差,低方差),正確擬合,以及過擬合(低偏差,高方差)模型怎樣表現:
??建立泛化模型這樣的想法背后的動機是切分數據集為為一個訓練集和測試集(在你分析的最后提供模型性能的準確測量).
??可是,它也有可能過擬合測試數據.假設你對測試集嘗試很多不同模型,并為了追求精度不斷改變它們,然后測試集的信息可能不經意地滲入到模型創建階段.你須要一個辦法解決.
使用K折交叉驗證評估模型性能
??輸入K折交叉驗證,這是僅使用訓練集衡量模型性能的一個方便技術.該步驟例如以下:你隨機劃分訓練集為k等份;然后,我們在k-1/k的訓練集上訓練數據;對剩下的一部分評估性能.這給你一些模型性能的指標(如,總體精度).接下來訓練在不同的k-1/k訓練集訓練算法,并在剩下的1部分評估.你反復這個過程k次,得到k個不同的模型性能度量,利用這些值的平均值得到總體性能的度量.繼續樣例,10折交叉驗證背后例如以下:
??你能夠使用k折交叉驗證獲得模型精度的評估,相同能夠利用這些預計調整你的模型直到令你愜意.這使得你不用最后測試數據,因此避免了過擬合的危急.換句話說,交叉驗證提供一種方式模擬比你實際擁有很多其它的數據,因此你不用建模最后才使用測試集.k折交叉驗證以及其變種是很流行而且很實用,尤其你嘗試很多不同的模型(假設你想測試不同參數模型性能怎樣).
比較訓練誤差,交叉驗證誤差和測試誤差
??那么,什么k是最佳的?對訓練數據構建模形式嘗試不同K值,看對訓練集本身和測試集預測類別的結果模型怎樣.最后看K折交叉驗證怎樣支出最好的K.
??注:實踐中,當掃描這樣的參數,使用訓練集測試模型是以個糟糕的主意.相同的方式,你不能使用測試集多次瀏覽一個參數(每一個參數值一次).接下來,你是用這些計算僅僅是作為樣例.實踐中,僅僅有K折交叉驗證是一種安全的方法!
import numpy as np from sklearn.cross_validation import train_test_split, cross_val_score knn = KNeighborsClassifier() # the range of number of neighbors you want to test n_neighbors = np.arange(1, 141, 2) # here you store the models for each dataset used train_scores = list() test_scores = list() cv_scores = list() # loop through possible n_neighbors and try them out for n in n_neighbors: knn.n_neighbors = n knn.fit(XTrain, yTrain) train_scores.append(1 - metrics.accuracy_score(yTrain, knn.predict(XTrain))) # this will over-estimate the accuracy test_scores.append(1 - metrics.accuracy_score(yTest, knn.predict(XTest))) cv_scores.append(1 - cross_val_score(knn, XTrain, yTrain, cv = 10).mean()) # you take the mean of the CV scores
??那么最優的k是多少?當多個相同的預測誤差,你隨便挑一個最小的作為k值.
# what do these different datasets think is the best value of k?print( 'The best values of k are: n' '{} according to the Training Setn' '{} according to the Test Set andn' '{} according to Cross-Validation'.format( min(n_neighbors[train_scores == min(train_scores)]), min(n_neighbors[test_scores == min(test_scores)]), min(n_neighbors[cv_scores == min(cv_scores)]) ) )
最優K是:
1 according to the Training Set
23 according to the Test Set and
11 according to Cross-Validation
??不僅僅是收集最優的k,還須要對一系列測試的K看看預測誤差.
# let's plot the error you get with different values of k plt.figure(figsize=(10,7.5)) plt.plot(n_neighbors, train_scores, c="black", label="Training Set") plt.plot(n_neighbors, test_scores, c="black", linestyle="--", label="Test Set") plt.plot(n_neighbors, cv_scores, c="green", label="Cross-Validation") plt.xlabel('Number of K Nearest Neighbors') plt.ylabel('Classification Error') plt.gca().invert_xaxis() plt.legend(loc = "lower left") plt.show()
??讓我們談談訓練集的分類錯誤.你考慮少量近鄰,訓練集會得到低的預測誤差.這是有道理的,由于在做新的分類是,逼近每一個點僅僅考慮它本身的情況.測試誤差遵循類似的軌跡,可是在某個點后由于過擬合而增長.這樣的現象表明,構建的訓練集模型擬合在指定測試集樣本上建模效果不好.
??在該圖中能夠看到,尤其是對于k的低值。採用k折交叉驗證突出參數空間的區域(即k的很低的值)。這是很easy出現過擬合的。雖然交叉驗證和測試集的評估導致一些不同的最優解。它們都是相當不錯的。而且大致正確。
你也能夠看到。交叉驗證是測試誤差的合理預計。
這樣的類型的情節是好的,以獲得確定參數怎樣影響模型表現的良好感覺。并幫助建立數據集的直覺來學習。
代碼展示
??這是生成以上全部圖片,訓練測試不同kNN算法的代碼.代碼是scikit-learn樣例改編的代碼,主要處理決策邊界的計算并讓圖片好看.
包括機器學習中拆分數據集。算法擬合以及測試的部分。
def detect_plot_dimension(X, h=0.02, b=0.05): x_min, x_max = X[:, 0].min() - b, X[:, 0].max() + b y_min, y_max = X[:, 1].min() - b, X[:, 1].max() + b xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h)) dimension = xx, yy return dimension def detect_decision_boundary(dimension, model): xx, yy = dimension # unpack the dimensions boundary = model.predict(np.c_[xx.ravel(), yy.ravel()]) boundary = boundary.reshape(xx.shape) # Put the result into a color plot return boundary def plot_decision_boundary(panel, dimension, boundary, colors=['#DADDED', '#FBD8D8']): xx, yy = dimension # unpack the dimensions panel.contourf(xx, yy, boundary, cmap=ListedColormap(colors), alpha=1) panel.contour(xx, yy, boundary, colors="g", alpha=1, linewidths=0.5) # the decision boundary in green def plot_dataset(panel, X, y, colors=["#EE3D34", "#4458A7"], markers=["x", "o"]): panel.scatter(X[y == 1, 0], X[y == 1, 1], color=colors[0], marker=markers[0]) panel.scatter(X[y == 0, 0], X[y == 0, 1], color=colors[1], marker=markers[1]) def calculate_prediction_error(model, X, y): yPred = model.predict(X) score = 1 - round(metrics.accuracy_score(y, yPred), 2) return score def plot_prediction_error(panel, dimension, score, b=.3): xx, yy = dimension # unpack the dimensions panel.text(xx.max() - b, yy.min() + b, ('%.2f' % score).lstrip('0'), size=15, horizontalalignment='right') def explore_fitting_boundaries(model, n_neighbors, datasets, width): # determine the height of the plot given the aspect ration of each panel should be equal height = float(width)/len(n_neighbors) * len(datasets.keys()) nrows = len(datasets.keys()) ncols = len(n_neighbors) # set up the plot figure, axes = plt.subplots( nrows, ncols, figsize=(width, height), sharex=True, sharey=True ) dimension = detect_plot_dimension(X, h=0.02) # the dimension each subplot based on the data # Plotting the dataset and decision boundaries i = 0 for n in n_neighbors: model.n_neighbors = n model.fit(datasets["Training Set"][0], datasets["Training Set"][1]) boundary = detect_decision_boundary(dimension, model) j = 0 for d in datasets.keys(): try: panel = axes[j, i] except (TypeError, IndexError): if (nrows * ncols) == 1: panel = axes elif nrows == 1: # if you only have one dataset panel = axes[i] elif ncols == 1: # if you only try one number of neighbors panel = axes[j] plot_decision_boundary(panel, dimension, boundary) # plot the decision boundary plot_dataset(panel, X=datasets[d][0], y=datasets[d][1]) # plot the observations score = calculate_prediction_error(model, X=datasets[d][0], y=datasets[d][1]) plot_prediction_error(panel, dimension, score, b=0.2) # plot the score # make compacted layout panel.set_frame_on(False) panel.set_xticks([]) panel.set_yticks([]) # format the axis labels if i == 0: panel.set_ylabel(d) if j == 0: panel.set_title('k={}'.format(n)) j += 1 i += 1 plt.subplots_adjust(hspace=0, wspace=0) # make compacted layout
??然后,你能夠這樣執行代碼:
# specify the model and settings model = KNeighborsClassifier() n_neighbors = [200, 99, 50, 23, 11, 1] datasets = { "Training Set": [XTrain, yTrain], "Test Set": [XTest, yTest] } width = 20 # explore_fitting_boundaries(model, n_neighbors, datasets, width) explore_fitting_boundaries(model=model, n_neighbors=n_neighbors, datasets=datasets, width=width)
結論
??偏差-方差權衡出如今機器學習的不同領域.全部算法都能夠覺得具有一定彈性,而且不僅僅是KNN.發現描寫敘述良好數據模式而且能夠泛化新數據,這樣靈活的最佳點的目標適用于基本上全部算法.
總結
以上是生活随笔為你收集整理的一篇文章,带你明确什么是过拟合,欠拟合以及交叉验证的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 王者荣耀阿古朵怎么出装 阿古朵最强打野出
- 下一篇: 阴阳师化鲸手中一直捧着答案是什么