การตรวจสอบความถูกต้องข้ามแบบแบ่งชั้น k-fold โดยใช้ python
การสุ่มตัวอย่างแบบแบ่งชั้นคืออะไร?
ในตัวอย่างแบบแบ่งชั้น นักวิจัยแบ่งประชากรออกเป็นประชากรย่อยที่เป็นเนื้อเดียวกันที่เรียกว่า ชั้น ตามลักษณะเฉพาะ (เช่น เชื้อชาติ อัตลักษณ์ทางเพศ สถานที่ ฯลฯ) สมาชิกทุกคนของประชากรที่ศึกษาควรอยู่ในชั้นเดียว
นักวิจัยอาศัยการสุ่มตัวอย่างแบบแบ่งชั้นเมื่อลักษณะของประชากรมีความหลากหลาย และพวกเขาต้องการให้แน่ใจว่าทุกคุณลักษณะจะแสดงอย่างถูกต้องในกลุ่มตัวอย่าง
การตรวจสอบความถูกต้องข้ามแบบแบ่งชั้น k-fold
การตรวจสอบความถูกต้องข้ามแบบแบ่งชั้น k-fold เป็นวิธีการประเมินประสิทธิภาพของโมเดลแมชชีนเลิร์นนิง เป็นรูปแบบหนึ่งของการตรวจสอบความถูกต้องแบบข้าม k-fold ซึ่งเป็นเทคนิคในการประเมินความแม่นยำของแบบจำลองโดยการแบ่งชุดข้อมูลออกเป็นชุดย่อย k (หรือ "folds") และใช้หนึ่งในพับเป็นชุดการตรวจสอบในขณะที่ k ที่เหลือ -ใช้พับ 1 ทบเป็นชุดฝึกซ้อม กระบวนการนี้ทำซ้ำ k ครั้ง เพื่อให้แต่ละพับถูกใช้เป็นชุดการตรวจสอบความถูกต้องหนึ่งครั้ง
ในการตรวจสอบความถูกต้องข้ามแบบแบ่งชั้น k-fold การพับจะถูกสร้างขึ้นในลักษณะที่แต่ละการพับเป็นตัวอย่างที่เป็นตัวแทนของชุดข้อมูล โดยเฉพาะอย่างยิ่ง ข้อมูลจะถูกแบ่งออกเป็น k เท่า โดยแต่ละส่วนจะมีสัดส่วนตัวอย่างจากแต่ละคลาสโดยประมาณเท่ากับชุดข้อมูลดั้งเดิม นี่เป็นสิ่งสำคัญเมื่อต้องรับมือกับชุดข้อมูลที่ไม่สมดุล ซึ่งจำนวนตัวอย่างในแต่ละคลาสไม่เท่ากัน
ข้อได้เปรียบหลักของการตรวจสอบความถูกต้องข้ามแบบแบ่งชั้น k-fold คือ ให้การประมาณประสิทธิภาพของแบบจำลองกับข้อมูลที่มองไม่เห็นได้แม่นยำยิ่งขึ้น โดยเฉพาะอย่างยิ่งเมื่อต้องรับมือกับชุดข้อมูลที่ไม่สมดุล เนื่องจากช่วยให้แน่ใจว่าแต่ละพับเป็นตัวแทนของชุดข้อมูลทั้งหมด และแต่ละคลาสจะถูกนำเสนออย่างเท่าเทียมกันในชุดการฝึกอบรมและการตรวจสอบความถูกต้อง
การตรวจสอบความถูกต้องข้ามแบบแบ่งชั้น k-fold เป็นเทคนิคทั่วไปในแมชชีนเลิร์นนิงและมีการใช้กันอย่างแพร่หลายในการใช้งานที่หลากหลาย รวมถึงการจำแนกประเภทและการถดถอย มักใช้เพื่อปรับแต่งไฮเปอร์พารามิเตอร์ของโมเดลหรือเพื่อเปรียบเทียบประสิทธิภาพของโมเดลต่างๆ บนชุดข้อมูลที่กำหนด
การทดสอบบางอย่าง
คำจำกัดความของชุดข้อมูล สำหรับ sklearn นี้มีฟังก์ชันที่น่าสนใจที่เรียกว่า "make_classification" ซึ่งสามารถใช้เพื่อรับชุดข้อมูลได้
โดยเฉพาะชุดข้อมูลที่ใช้ประกอบด้วยตัวอย่าง 100 ตัวอย่าง มีคุณสมบัติ 10 ประการ หนึ่งป้ายกำกับที่อธิบายประเภทจุดคลาส 4 รายการ น้ำหนักของแต่ละคลาสในชุดข้อมูลนั้นไม่เท่ากันจริงๆ
from sklearn.datasets import make_classification from sklearn.model_selection import KFold, StratifiedKFold import numpy as np X,y = make_classification(n_samples=100, n_features=10, n_informative=4, n_classes=4,weights=[.2,.4,.1,.4]) import pandas as pd dataset = pd.DataFrame(X) dataset = dataset.add_prefix('f') dataset['y'] = y dataset
โปรดทราบว่าเนื่องจากชุดข้อมูลมีน้ำหนักสัมพัทธ์ของคลาสที่แตกต่างกัน จึงไม่พบคะแนนที่เท่ากันของแต่ละคลาส แต่จะพบคะแนนเพิ่มเติมจากคลาส “1” และอีกสองสามคะแนนจากคลาส “2”
dataset['y'].value_counts() 1 40 3 29 0 21 2 10
Kfold
เราเริ่มต้นด้วยการใช้ Kfold แบบคลาสสิกที่ไม่ได้ใช้ตัวเลือก stratified และดูว่าคลาสมีการกระจายอย่างไรโดยการเปรียบเทียบ train fold และ test fold
kfold = KFold(n_splits=3,random_state=11,shuffle=True) splits = kfold.split(dataset, dataset['y']) # each split has a train indexes and test indexes pair print(f'PROPORTION OF TARGET IN THE ORIGINAL DATA\n{dataset["y"].value_counts() / len(dataset)}\n\n') ll = [] for n,(train_index,test_index) in enumerate(splits): print(f'SPLIT NO {n+1}\nTRAINING SET SIZE: {np.round(len(train_index) / (len(train_index)+len(test_index)),2)}'+ f'\tTEST SET SIZE: {np.round(len(test_index) / (len(train_index)+len(test_index)),2)}\nPROPORTION OF TARGET IN THE TRAINING SET\n'+ f'{dataset.iloc[train_index,10].value_counts() / len(dataset.iloc[train_index,10])}\nPROPORTION OF TARGET IN THE TEST SET\n'+ f'{dataset.iloc[test_index,10].value_counts() / len(dataset.iloc[test_index,10])}\n\n') ll.append({'SPLIT NO {}'.format(n+1): { 'train':dataset.iloc[train_index,10].value_counts() / len(dataset.iloc[train_index,10]), 'test': dataset.iloc[test_index,10].value_counts() / len(dataset.iloc[test_index,10]) }})
เราจะเห็นได้ทันทีว่าการกระจายคลาสใน Train และ Test เปลี่ยนแปลงไปอย่างไร แต่เราสามารถเห็นสิ่งนี้ได้ดีขึ้นด้วยการรวมผลลัพธ์ไว้ใน Dataframe
PROPORTION OF TARGET IN THE ORIGINAL DATA 1 0.4 3 0.3 0 0.2 2 0.1 Name: y, dtype: float64 SPLIT NO 1 TRAINING SET SIZE: 0.66 TEST SET SIZE: 0.34 PROPORTION OF TARGET IN THE TRAINING SET 1 0.439394 3 0.272727 0 0.181818 2 0.106061 Name: y, dtype: float64 PROPORTION OF TARGET IN THE TEST SET 3 0.352941 1 0.323529 0 0.235294 2 0.088235 Name: y, dtype: float64 SPLIT NO 2 TRAINING SET SIZE: 0.67 TEST SET SIZE: 0.33 PROPORTION OF TARGET IN THE TRAINING SET 1 0.343284 3 0.328358 0 0.238806 2 0.089552 Name: y, dtype: float64 PROPORTION OF TARGET IN THE TEST SET 1 0.515152 3 0.242424 2 0.121212 0 0.121212 Name: y, dtype: float64 SPLIT NO 3 TRAINING SET SIZE: 0.67 TEST SET SIZE: 0.33 PROPORTION OF TARGET IN THE TRAINING SET 1 0.417910 3 0.298507 0 0.179104 2 0.104478 Name: y, dtype: float64 PROPORTION OF TARGET IN THE TEST SET 1 0.363636 3 0.303030 0 0.242424 2 0.090909 Name: y, dtype: float64 import pandas as pd # extract data from the list data = [] for d in ll: for key, value in d.items(): split_num = key.split()[-1] train_data = value['train'] test_data = value['test'] data.append([split_num, train_data, test_data]) # create a DataFrame for the train data train_df = pd.DataFrame({d[0]: d[1] for d in data}, index=data[0][1].index) train_df = train_df.add_prefix('split_') train_df = train_df.set_index('class_'+ train_df.index.astype(str)) # create a DataFrame for the test data test_df = pd.DataFrame({d[0]: d[2] for d in data}, index=data[0][2].index) test_df = test_df.add_prefix('split_') test_df = test_df.set_index('class_'+ test_df.index.astype(str)) # display the DataFrames train_df.merge(test_df, left_index=True, right_index=True, suffixes=('_train', '_test'))
ในความเป็นจริงจาก dataframe เอฟเฟกต์นั้นชัดเจนมาก ตอนนี้ให้เราลองแสดงสิ่งนี้โดยใช้กราฟแท่งที่จะติดตามคลาสเดียวอย่างชัดเจนและแสดงความแตกต่างระหว่างองค์ประกอบของคลาสใน Train และในการทดสอบในการแยกต่างๆ
import plotly.graph_objects as go # create the bar trace bar_trace = go.Bar(x=train_df.columns, y=train_df.iloc[0]) # create the bar trace bar_trace1 = go.Bar(x=test_df.columns, y=test_df.iloc[0]) # create the layout layout = go.Layout(title='Train vs Test target composition', xaxis_title='Split', yaxis_title='%') # create the figure fig = go.Figure(data=[bar_trace, bar_trace1], layout=layout) # display the figure fig.show()
ผลลัพธ์นั้นชัดเจนมากและไม่น่าพอใจหากเราพยายามตรวจสอบโมเดลของเรา เนื่องจากจะทำให้การตรวจสอบไม่มีสิทธิ์ แน่นอนในตัวอย่างที่ฉันให้ไว้ ฉันแสดงเพียงคลาสเดียว แต่สิ่งทั้งหมดสามารถทำซ้ำร่วมกับคลาสอื่นๆ ทั้งหมดได้
แบ่งชั้น kfold
ทำซ้ำขั้นตอนเดียวกันโดยใช้วิธีแบ่งชั้น โดยพื้นฐานแล้วมีเพียงแถวเดียวเท่านั้นที่ต้องเปลี่ยนคือแถวที่รายงานด้านล่าง
kfold = StratifiedKFold(n_splits=3,shuffle=True,random_state=11) PROPORTION OF TARGET IN THE ORIGINAL DATA 1 0.4 3 0.3 0 0.2 2 0.1 Name: y, dtype: float64 SPLIT NO 1 TRAINING SET SIZE: 0.66 TEST SET SIZE: 0.34 PROPORTION OF TARGET IN THE TRAINING SET 1 0.393939 3 0.303030 0 0.196970 2 0.106061 Name: y, dtype: float64 PROPORTION OF TARGET IN THE TEST SET 1 0.411765 3 0.294118 0 0.205882 2 0.088235 Name: y, dtype: float64 SPLIT NO 2 TRAINING SET SIZE: 0.67 TEST SET SIZE: 0.33 PROPORTION OF TARGET IN THE TRAINING SET 1 0.402985 3 0.298507 0 0.208955 2 0.089552 Name: y, dtype: float64 PROPORTION OF TARGET IN THE TEST SET 1 0.393939 3 0.303030 0 0.181818 2 0.121212 Name: y, dtype: float64 SPLIT NO 3 TRAINING SET SIZE: 0.67 TEST SET SIZE: 0.33 PROPORTION OF TARGET IN THE TRAINING SET 1 0.402985 3 0.298507 0 0.194030 2 0.104478 Name: y, dtype: float64 PROPORTION OF TARGET IN THE TEST SET 1 0.393939 3 0.303030 0 0.212121 2 0.090909 Name: y, dtype: float64
ที่นี่เราสังเกตเห็นความแตกต่างอย่างชัดเจน และตอนนี้ชุดฝึกและชุดทดสอบต่างๆ มีความสอดคล้องกันมากขึ้นอย่างไร
เอฟเฟกต์เหมือนเมื่อก่อนสามารถแสดงบนกราฟแท่งได้ คุณสามารถดูได้ทันทีโดยการคำนวณด้วยกราฟก่อนหน้าว่าแท่งทั้งหมดมีความสูงเท่ากันอย่างไร เพื่อประเมินการแยกแต่ละส่วนอย่างชัดเจน
ข้อสรุป
จากผลลัพธ์ เห็นได้ชัดว่าการใช้แนวทางแบบแบ่งชั้นมีความถูกต้องมากขึ้นหากเราจะตรวจสอบแบบจำลอง จากสิ่งนี้ ฉันหมายความว่าหากโมเดลได้รับการฝึกบน Datum รถไฟจำนวนหนึ่ง ก็คาดว่าจะได้รับการตรวจสอบความถูกต้องบน Datum การตรวจสอบความถูกต้องที่ใกล้เคียงกับ Datum รถไฟมากที่สุด การใช้แนวทางมาตรฐานนี้เป็นไปไม่ได้ ดังนั้นจึงเป็นเรื่องสำคัญที่จะต้องทราบแนวทางการตรวจสอบนี้เช่นกัน เนื่องจากอาจมีประโยชน์