Dưới đây là một hàm Python phân chia một khung dữ liệu Pandas thành các chuỗi dữ liệu huấn luyện, xác nhận và kiểm tra với lấy mẫu phân tầng. Nó thực hiện việc phân tách này bằng cách gọi hàm scikit-learn train_test_split()
hai lần.
import pandas as pd
from sklearn.model_selection import train_test_split
def split_stratified_into_train_val_test(df_input, stratify_colname='y',
frac_train=0.6, frac_val=0.15, frac_test=0.25,
random_state=None):
'''
Splits a Pandas dataframe into three subsets (train, val, and test)
following fractional ratios provided by the user, where each subset is
stratified by the values in a specific column (that is, each subset has
the same relative frequency of the values in the column). It performs this
splitting by running train_test_split() twice.
Parameters
----------
df_input : Pandas dataframe
Input dataframe to be split.
stratify_colname : str
The name of the column that will be used for stratification. Usually
this column would be for the label.
frac_train : float
frac_val : float
frac_test : float
The ratios with which the dataframe will be split into train, val, and
test data. The values should be expressed as float fractions and should
sum to 1.0.
random_state : int, None, or RandomStateInstance
Value to be passed to train_test_split().
Returns
-------
df_train, df_val, df_test :
Dataframes containing the three splits.
'''
if frac_train + frac_val + frac_test != 1.0:
raise ValueError('fractions %f, %f, %f do not add up to 1.0' % \
(frac_train, frac_val, frac_test))
if stratify_colname not in df_input.columns:
raise ValueError('%s is not a column in the dataframe' % (stratify_colname))
X = df_input # Contains all columns.
y = df_input[[stratify_colname]] # Dataframe of just the column on which to stratify.
# Split original dataframe into train and temp dataframes.
df_train, df_temp, y_train, y_temp = train_test_split(X,
y,
stratify=y,
test_size=(1.0 - frac_train),
random_state=random_state)
# Split the temp dataframe into val and test dataframes.
relative_frac_test = frac_test / (frac_val + frac_test)
df_val, df_test, y_val, y_test = train_test_split(df_temp,
y_temp,
stratify=y_temp,
test_size=relative_frac_test,
random_state=random_state)
assert len(df_input) == len(df_train) + len(df_val) + len(df_test)
return df_train, df_val, df_test
Dưới đây là một ví dụ làm việc hoàn chỉnh.
Xem xét một tập dữ liệu có nhãn mà bạn muốn thực hiện phân tầng. Nhãn này có phân phối riêng trong bộ dữ liệu gốc, cho biết 75% foo
, 15% bar
và 10% baz
. Bây giờ, hãy chia dữ liệu thành đào tạo, xác thực và kiểm tra thành các tập hợp con bằng cách sử dụng tỷ lệ 60/20/20, trong đó mỗi phân tách giữ lại phân phối nhãn giống nhau. Xem hình minh họa dưới đây:
Dưới đây là tập dữ liệu mẫu:
df = pd.DataFrame( { 'A': list(range(0, 100)),
'B': list(range(100, 0, -1)),
'label': ['foo'] * 75 + ['bar'] * 15 + ['baz'] * 10 } )
df.head()
# A B label
# 0 0 100 foo
# 1 1 99 foo
# 2 2 98 foo
# 3 3 97 foo
# 4 4 96 foo
df.shape
# (100, 3)
df.label.value_counts()
# foo 75
# bar 15
# baz 10
# Name: label, dtype: int64
Bây giờ, hãy gọi split_stratified_into_train_val_test()
hàm từ phía trên để lấy các tệp dữ liệu đào tạo, xác nhận và kiểm tra theo tỷ lệ 60/20/20.
df_train, df_val, df_test = \
split_stratified_into_train_val_test(df, stratify_colname='label', frac_train=0.60, frac_val=0.20, frac_test=0.20)
Ba datafram df_train
, df_val
và df_test
chứa tất cả các hàng ban đầu nhưng kích thước của chúng sẽ tuân theo tỷ lệ trên.
df_train.shape
#(60, 3)
df_val.shape
#(20, 3)
df_test.shape
#(20, 3)
Hơn nữa, mỗi trong số ba phần tách sẽ có cùng phân phối nhãn, cụ thể là 75% foo
, 15% bar
và 10% baz
.
df_train.label.value_counts()
# foo 45
# bar 9
# baz 6
# Name: label, dtype: int64
df_val.label.value_counts()
# foo 15
# bar 3
# baz 2
# Name: label, dtype: int64
df_test.label.value_counts()
# foo 15
# bar 3
# baz 2
# Name: label, dtype: int64