文章目錄
- K折交叉驗證有什么用?
- 如何實現K折交叉驗證?
- K折交叉驗證的要點:(文字版)
- 如何實現K折交叉驗證(圖片版)
- 如何實現K折交叉驗證(matlab版)
- 為啥我們需要分層K折交叉驗證?
- 如何實現分層k折交叉驗證
- 如何實現分層k折交叉驗證(文字版)
- 如何實現分層k折交叉驗證(圖片版)
- 如何實現分層K折交叉驗證(matlab版)
很多論文都會用到K折交叉驗證,但是我以前實驗一直沒有做這個步驟,最近整理了一下關于這個方面的資料,其實就是把看到的文字資料整理一下,有些文字自己進行了突出和調整,感謝所有博主,最后是我的matlab版的分層交叉驗證,通過這一段的學習,最大的感受就是 python 好,python好,python 好,真是令人憂傷啊。。。
分層K折交叉驗證是K折交叉驗證的一個變種,
適用于不平衡的數據集,所以先介紹K折交叉驗證,之后再介紹分層K折交叉驗證。
K折交叉驗證有什么用?
用法1:常用的精度測試方法主要是交叉驗證,例如10折交叉驗證(10-fold cross validation,CV),將數據集分成平均分成互斥的十份,輪流將其中9份做訓練1份做驗證,10次的結果的均值作為對算法精度的估計,一般還需要進行多次10折交叉驗證求均值,例如:10次10折交叉驗證,以求更精確一點。
來源——參考博客1: https://blog.csdn.net/Dream_angel_Z/article/details/47110077?utm_medium=distribute.pc_relevant.none-task-blog-OPENSEARCH-6.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-6.channel_param
用法2:一般情況將K折交叉驗證用于模型調優,找到使得模型泛化性能最優的超參值。找到后,在全部訓練集上重新訓練模型,并使用獨立測試集對模型性能做出最終評價。
來源——參考博客2:https://blog.csdn.net/ChenVast/article/details/79257097?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160249987519725222451761%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=160249987519725222451761&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_v2~rank_blog_v1-1-79257097.pc_v2_rank_blog_v1&utm_term=k%E6%8A%98&spm=1018.2118.3001.4187
關于這兩種用法,我目前看到的論文中,幾乎都是第1種,我也是為了精度測試方法來學習k折交叉驗證的,第2種用法沒怎么看到過,所以記錄一下啊,僅供參考。
如何實現K折交叉驗證?
K折交叉驗證的要點:(文字版)
1:數據集劃分為K個相同大小的互斥子集。
2:每次用K-1個集合訓練,剩下的1個做測試集,得到結果。
3:循環K次,得到K個結果,至此1次完整的K折交叉驗證結束
來源——參考博客3(有改動):https://baijiahao.baidu.com/s?id=1677821446173455536&wfr=spider&for=pc
這個是博主:桔子的算法之路寫的,,但是我覺得他原文比較像是分層K折交叉驗證,所以我就改了一點點
如何實現K折交叉驗證(圖片版)
圖片比文字直觀,下面的圖很清楚地告訴我們,大小相同、互斥、以及具體的過程,圖片來源,依舊是參考博客2:https://blog.csdn.net/ChenVast/article/details/79257097?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160249987519725222451761%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=160249987519725222451761&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_v2~rank_blog_v1-1-79257097.pc_v2_rank_blog_v1&utm_term=k%E6%8A%98&spm=1018.2118.3001.4187
如何實現K折交叉驗證(matlab版)
這個之前有特地整理過了,代碼來自博主:野狗汪汪汪,這里再貼一下mattlab代碼,博客地址:https://blog.csdn.net/weixin_41274837/article/details/90169268
data=double(xtrain');
label=double(ytrain'); %要求數據集每一行代表一個樣本 ;label每行為標簽[M,N]=size(data); % M:總樣本量; N:一個樣本的元素總數
indices=crossvalind('Kfold',data(1:M,N),5); %進行隨機分包for k=1:5 %交叉驗證k=10,10個包輪流作為測試集test = (indices == k); %獲得test集元素在數據集中對應的單元編號train = ~test; %train集元素的編號為非test元素的編號train_data=data(train,:);%從數據集中劃分出train樣本的數據train_label=label(train,:);test_data=data(test,:); %test樣本集test_label=label(test,:);
end
這個代碼的具體原理可以參考這個博客,來源——參考博客7:https://blog.csdn.net/IT_flying625/article/details/102995537
至此,k折交叉驗證的內容全部介紹完畢,下面是分層交叉驗證的內容
為啥我們需要分層K折交叉驗證?
K折交叉驗證和分層k折交叉驗證的區別,字面上看就是多了個分層,那么為啥要分層呢,前面有說到,分層k折交叉驗證是適用于不平衡的數據集的,依然是參考博客2寫道:
K折交叉驗證改進成的分層K折交叉驗證:
獲得偏差和方差都低的評估結果,特別是類別比例相差較大時。
那么為什么類別比例相差比較大的時候(就是數據集不平衡時),不分層的k折交叉驗證得到的結果不準確呢?請參考這個回答http://sofasofa.io/forum_main_post.php?postid=1000505&:
對于非平衡分類,stratified CV(這里指分層的k折交叉驗證)的優點就更加明顯了。如果二元分類中分類A只占有0.01%,分類B占有99.99%,當你使用常規的交叉驗證的時候,可能你的訓練集里甚至都沒有足夠的A來訓練,或者測試集里A的數量極少,嚴重影響了驗證結果的可靠性。
怎么理解這個影響可靠性,換句話來說,假設整個數據集100張圖,進行5折交叉驗證,那么一折就有20張圖,假設兩個類A和B比例是1:9,運氣非常差的情況下,某一折的過程中,所有的A(10個樣本)全部分為測試集,訓練集中一張都沒有A,那么相當于老師講課沒有說這個類型題(訓練),考試(測試)還考到了,考的差(評估結果差)就說你水平(這個模型效果不好),這個說法一看就知道不對勁。而越是不平衡的數據集,越有可能出現這種情況,所以我們要通過分層,來讓每一折的——不管是訓練集還是測試集——每個類的比例都盡量和原來的數據集保持一樣,這就類似于,老師平時講的多的東西,考試占的分也多,然后我們考很多次試,取評分,這個才能比較客觀地體現出你的能力,如果是一個平衡的數據集,如果你某一次考試考的特別好或者特別差,這都不是你的真實水平,K折交叉驗證通過讓你考很多次,取平均分可以避免這種情況,但是不平衡的數據集,K折交叉就好像你參加的考試本身就有些問題,考很多次也不能體現你的真實水平,而分層K折交叉驗證就可以解決這個問題。
如何實現分層k折交叉驗證
如何實現分層k折交叉驗證(文字版)
分層交叉驗證(Stratified k-fold cross validation):首先它屬于交叉驗證類型,分層的意思是說在每一折中都保持著原始數據中各個類別的比例關系,比如說:原始數據有3類,比例為1:2:1,采用3折分層交叉驗證,那么劃分的3折中,每一折中的數據類別保持著1:2:1的比例,這樣的驗證結果更加可信。
來源——參考博客5:https://www.cnblogs.com/ysugyl/p/8707887.html
如何實現分層k折交叉驗證(圖片版)
這張圖可以直觀感受一下啥叫分層k折交叉驗證,這是我找到的最好的一張圖了,只看下面那個部分就好了,圖片來源——參考博客4:https://blog.csdn.net/ssswill/article/details/85267864
因此正如原博客所說的:分層保證了每個折中類別之間的比例與整個數據集中的比例相同。
如何實現分層K折交叉驗證(matlab版)
看了一圈,好像程序都是python的,難過,以后要自學python啊!!!感覺python開源,資料比較豐富,matlab閉源再加上之前哈工大那個新聞,哎,好麻煩啊…
我沒找到分層k折交叉驗證的代碼,所以自己改了一下,基礎代碼就是之前那個很工整但是沒跑過的代碼,轉載的時候沒跑過,但是現在跑過了,果然很漂亮啊,和他的程序比起來,我的這個程序一點也不智能,類別數還要自己寫,而且也沒有抽象成函數,但是記錄一下吧,畢竟這個地方卡了這么久。
思路就是用上面的k折交叉驗證把每個類單獨分成k份,然后再合并在一起。Data有兩種,一個是特征,一個是標簽,兩種都進行類似的操作。
下面這個是程序,我的是8分類,在k折交叉驗證的基礎上改的,原來的代碼來源——參考博客6:https://blog.csdn.net/u010513327/article/details/80560750?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param
人家寫得好工整啊,為啥我的就顯得很亂呢…
程序中有一個num_in_class,我的是8分類問題,所以是這樣一個東西,這個變量代表了每一類有多少個樣本,前提是你的樣本數據集要同一個類都放在一起,然后第1類,第2類,第3類這樣一直排下去。
%需要先載入特征和標簽,沒有對應的mat文件的話會報錯,所以要根據自己的情況改
clc
clear all
tic
load features1%第一種特征
load features2%第2種特征
load Labels
features=[features1,features2];%把兩個矩陣橫向拼起來起來,注意中間是逗號,不是分號
num_in_class=[713,1343,1165,728,1217,713,1378,795];%說明第一類有713張圖片,第2類有1343張圖片,以此類推,需要改成自己的數據。classnums=length(num_in_class);%類別數為classnums,這一步是為了把每一類都取出來,注釋掉的是手動的,下面是自動的,功能一樣,我覺得我的自動的沒有錯...但是不敢打包票....
% features_lei1=features(1:713,:);%這個步驟不是自動化的,是自己把num_in_class的東西用excel累計求和,features矩陣第一行到第713行的所有數據數據是類別1
% features_lei2=features(713+1:2056,:);%features矩陣第713+1行到第2056行的所有數據數據是類別2,2026=713+1343
% features_lei3=features(2056+1:3221,:);
% features_lei4=features(3221+1:3949,:);
% features_lei5=features(3949+1:5166,:);
% features_lei6=features(5166+1:5879,:);
% features_lei7=features(5879+1:7257,:);
% features_lei8=features(7257+1:8052,:);features_lei1=features(1:num_in_class(1),:);%這個步驟是自動化的,其實是確定上面的沒問題后,改出來的lei2_end=num_in_class(1)+num_in_class(2);features_lei2=features(num_in_class(1)+1:lei2_end,:);lei3_end=lei2_end+num_in_class(3);features_lei3=features(lei2_end+1:lei3_end,:);lei4_end=lei3_end+num_in_class(4);features_lei4=features(lei3_end+1:lei4_end,:);lei5_end=lei4_end+num_in_class(5);features_lei5=features(lei4_end+1:lei5_end,:);lei6_end=lei5_end+num_in_class(6);features_lei6=features(lei5_end+1:lei6_end,:);lei7_end=lei6_end+num_in_class(7);features_lei7=features(lei6_end+1:lei7_end,:);lei8_end=lei7_end+num_in_class(8);features_lei8=features(lei7_end+1:lei8_end,:);% Labels_lei1=Labels(1:713,:);%這個步驟不是自動化的,是自己把num_in_class的東西用excel累計求和
% Labels_lei2=Labels(713+1:2056,:);
% Labels_lei3=Labels(2056+1:3221,:);
% Labels_lei4=Labels(3221+1:3949,:);
% Labels_lei5=Labels(3949+1:5166,:);
% Labels_lei6=Labels(5166+1:5879,:);
% Labels_lei7=Labels(5879+1:7257,:);
% Labels_lei8=Labels(7257+1:8052,:);Labels_lei1=Labels(1:num_in_class(1),:);%這個步驟是自動化的,其實是確定上面的沒問題后,改出來的Labels_lei2=Labels(num_in_class(1)+1:lei2_end,:);Labels_lei3=Labels(lei2_end+1:lei3_end,:);Labels_lei4=Labels(lei3_end+1:lei4_end,:);Labels_lei5=Labels(lei4_end+1:lei5_end,:);Labels_lei6=Labels(lei5_end+1:lei6_end,:);Labels_lei7=Labels(lei6_end+1:lei7_end,:);Labels_lei8=Labels(lei7_end+1:lei8_end,:);
%% k折交叉驗證
%交叉驗證
k =5;%預將數據分成5份
sum_accuracy_svm = 0;
%% 類別1
[m,n] = size(features_lei1);
%交叉驗證,使用k折交叉驗證 Kfold
%indices為 m 行一列數據,表示每個訓練樣本屬于k份數據的哪一份
indices_1 = crossvalind('Kfold',m,k);
%% 類別2
[m,n] = size(features_lei2);
%交叉驗證,使用k折交叉驗證 Kfold
%indices為 m 行一列數據,表示每個訓練樣本屬于k份數據的哪一份
indices_2 = crossvalind('Kfold',m,k);
%% 類別3
[m,n] = size(features_lei3);
%交叉驗證,使用k折交叉驗證 Kfold
%indices為 m 行一列數據,表示每個訓練樣本屬于k份數據的哪一份
indices_3 = crossvalind('Kfold',m,k);
%% 類別4
[m,n] = size(features_lei4);
%交叉驗證,使用k折交叉驗證 Kfold
%indices為 m 行一列數據,表示每個訓練樣本屬于k份數據的哪一份
indices_4 = crossvalind('Kfold',m,k);
%% 類別5
[m,n] = size(features_lei5);
%交叉驗證,使用k折交叉驗證 Kfold
%indices為 m 行一列數據,表示每個訓練樣本屬于k份數據的哪一份
indices_5 = crossvalind('Kfold',m,k);
%% 類別6
[m,n] = size(features_lei6);
%交叉驗證,使用k折交叉驗證 Kfold
%indices為 m 行一列數據,表示每個訓練樣本屬于k份數據的哪一份
indices_6 = crossvalind('Kfold',m,k);
%% 類別7
[m,n] = size(features_lei7);
%交叉驗證,使用k折交叉驗證 Kfold
%indices為 m 行一列數據,表示每個訓練樣本屬于k份數據的哪一份
indices_7 = crossvalind('Kfold',m,k);
%% 類別8
[m,n] = size(features_lei8);
%交叉驗證,使用k折交叉驗證 Kfold
%indices為 m 行一列數據,表示每個訓練樣本屬于k份數據的哪一份
indices_8 = crossvalind('Kfold',m,k);for i = 1:k% 針對第1類劃分訓練集和測試集test_indic_1 = (indices_1 == i);train_indic_1 = ~test_indic_1;train_datas_1 = features_lei1(train_indic_1,:);%找出訓練數據與標簽train_labels_1 = Labels_lei1(train_indic_1,:);test_datas_1 = features_lei1(test_indic_1,:);%找出測試數據與標簽test_labels_1 = Labels_lei1(test_indic_1,:);% 針對第2類劃分訓練集和測試集test_indic_2 = (indices_2 == i);train_indic_2 = ~test_indic_2;train_datas_2 = features_lei2(train_indic_2,:);%找出訓練數據與標簽train_labels_2 = Labels_lei2(train_indic_2,:);test_datas_2 = features_lei2(test_indic_2,:);%找出測試數據與標簽test_labels_2 = Labels_lei2(test_indic_2,:);% 針對第3類劃分訓練集和測試集test_indic_3 = (indices_3 == i);train_indic_3 = ~test_indic_3;train_datas_3 = features_lei3(train_indic_3,:);%找出訓練數據與標簽train_labels_3 = Labels_lei3(train_indic_3,:);test_datas_3 = features_lei3(test_indic_3,:);%找出測試數據與標簽test_labels_3 = Labels_lei3(test_indic_3,:);% 針對第4類劃分訓練集和測試集test_indic_4 = (indices_4 == i);train_indic_4 = ~test_indic_4;train_datas_4 = features_lei4(train_indic_4,:);%找出訓練數據與標簽train_labels_4 = Labels_lei4(train_indic_4,:);test_datas_4 = features_lei4(test_indic_4,:);%找出測試數據與標簽test_labels_4 = Labels_lei4(test_indic_4,:);% 針對第5類劃分訓練集和測試集test_indic_5 = (indices_5 == i);train_indic_5 = ~test_indic_5;train_datas_5 = features_lei5(train_indic_5,:);%找出訓練數據與標簽train_labels_5 = Labels_lei5(train_indic_5,:);test_datas_5 = features_lei5(test_indic_5,:);%找出測試數據與標簽test_labels_5 = Labels_lei5(test_indic_5,:);% 針對第6類劃分訓練集和測試集test_indic_6 = (indices_6 == i);train_indic_6 = ~test_indic_6;train_datas_6 = features_lei6(train_indic_6,:);%找出訓練數據與標簽train_labels_6 = Labels_lei6(train_indic_6,:);test_datas_6 = features_lei6(test_indic_6,:);%找出測試數據與標簽test_labels_6 = Labels_lei6(test_indic_6,:);% 針對第7類劃分訓練集和測試集test_indic_7 = (indices_7 == i);train_indic_7 = ~test_indic_7;train_datas_7 = features_lei7(train_indic_7,:);%找出訓練數據與標簽train_labels_7 = Labels_lei7(train_indic_7,:);test_datas_7 = features_lei7(test_indic_7,:);%找出測試數據與標簽test_labels_7 = Labels_lei7(test_indic_7,:);% 針對第8類劃分訓練集和測試集test_indic_8 = (indices_8 == i);train_indic_8 = ~test_indic_8;train_datas_8 = features_lei8(train_indic_8,:);%找出訓練數據與標簽train_labels_8 = Labels_lei8(train_indic_8,:);test_datas_8 = features_lei8(test_indic_8,:);%找出測試數據與標簽test_labels_8 = Labels_lei8(test_indic_8,:);% 合并train_datas = [train_datas_1;train_datas_2;train_datas_3;train_datas_4;train_datas_5;train_datas_6;train_datas_7;train_datas_8];train_labels =[train_labels_1;train_labels_2;train_labels_3;train_labels_4;train_labels_5;train_labels_6;train_labels_7;train_labels_8];test_datas = [test_datas_1;test_datas_2;test_datas_3;test_datas_4;test_datas_5;test_datas_6;test_datas_7;test_datas_8];test_labels =[test_labels_1;test_labels_2;test_labels_3;test_labels_4;test_labels_5;test_labels_6;test_labels_7;test_labels_8];% 開始svm多分類訓練,fitcsvm用于二分類,fitcecoc用于多分類, classifer = fitcecoc(train_datas,train_labels);%訓練模型predict_label = predict(classifer, test_datas);%測試fprintf('第%d折\n',i)disp('分類正確率:'); accuracy_svm = length(find(predict_label == test_labels))/length(test_labels)%正確率sum_accuracy_svm = sum_accuracy_svm + accuracy_svm;endmean_accuracy_svm = sum_accuracy_svm / k;disp('平均準確率:'); disp( mean_accuracy_svm);
toc
再次感謝以上所有的博主們!!!
總結
以上是生活随笔為你收集整理的matlab-K折交叉验证与分层K折交叉验证的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。