Python 训练、验证和测试集中数据帧的分层拆分

Python 训练、验证和测试集中数据帧的分层拆分,python,pandas,dataframe,machine-learning,deep-learning,Python,Pandas,Dataframe,Machine Learning,Deep Learning,以下极度简化的数据框表示包含医疗诊断的更大数据框: medicalData = pd.DataFrame({'diagnosis':['positive','positive','negative','negative','positive','negative','negative','negative','negative','negative']}) medicalData diagnosis 0 positive 1 positive 2 negative 3

以下极度简化的数据框表示包含医疗诊断的更大数据框:

medicalData = pd.DataFrame({'diagnosis':['positive','positive','negative','negative','positive','negative','negative','negative','negative','negative']})
medicalData

    diagnosis
0   positive
1   positive
2   negative
3   negative
4   positive
5   negative
6   negative
7   negative
8   negative
9   negative
对于机器学习,我需要按以下方式将此数据帧随机拆分为三个子帧:

trainingDF, validationDF, testDF = SplitData(medicalData,fractions = [0.6,0.2,0.2])
当分割数组指定进入每个子帧的完整数据的分数时,子帧中的数据需要互斥,并且分割数组需要求和为一。 传统上,每个子集的阳性诊断分数需要大致相同。

建议使用或。但这些解决方案似乎都不能很好地推广到n个拆分,也没有一个提供分层拆分。

np.array\u split
如果您想推广到
n
split,那么
np.array\u split
是您的朋友(它可以很好地处理数据帧)


train\u test\u split
用于分层拆分的多风解决方案

y = df.pop('diagnosis').to_frame()
X = df

其中,
X
是功能的数据框,
y
是标签的单列数据框。

Pure
pandas
解决方案 按70/20/10%的比例分为培训/验证/测试:

train_df = df.sample(frac=0.7, random_state=random_seed)
tmp_df = df.drop(train_df.index)
test_df = tmp_df.sample(frac=0.33333, random_state=random_seed)
valid_df = tmp_df.drop(test_df.index)

assert len(df) == len(train_df) + len(valid_df) + len(test_df), "Dataset sizes don't add up"
del tmp_df

下面是一个Python函数,它使用分层采样将Pandas数据帧拆分为训练、验证和测试数据帧。它通过调用scikit learn的函数
train\u test\u split()
两次来执行此拆分

将熊猫作为pd导入
从sklearn.model\u选择导入列车\u测试\u拆分
def将分层分为列值测试(df输入,分层colname='y',
压裂系列=0.6,压裂数值=0.15,压裂试验=0.25,
随机状态=无):
'''
将数据帧拆分为三个子集(train、val和test)
以下是用户提供的分数比率,其中每个子集
按特定列中的值分层(即,每个子集具有
列中值的相同相对频率)。它实现了这一点
通过运行两次列车\u测试\u split()进行拆分。
参数
----------
df_输入:数据帧
输入要拆分的数据帧。
分层名称:str
将用于分层的列的名称。通常
此列将用于标签。
压裂车:浮子
分形:浮点数
压裂试验:浮球
将数据帧拆分为train、val和val的比率
测试数据。这些值应表示为浮点数,并应
总和为1.0。
随机状态:int、None或RandomStateInstance
要传递给列车测试分割()的值。
退换商品
-------
测向列、测向值、测向测试:
包含三个拆分的数据帧。
'''
如果压裂液系列+压裂液+压裂液测试!=1.0:
raise VALUERROR('分数%f,%f,%f加起来不等于1.0'%\
(压裂系列、压裂价值、压裂测试)
如果分层_colname不在df_input.columns中:
raise VALUERROR(“%s”不是数据帧“%”(分层\u colname)中的列)
X=df_输入#包含所有列。
y=df_输入[[stratify_colname]]#仅用于分层的列的数据帧。
#将原始数据帧拆分为列车和临时数据帧。
df_系列,df_温度,y_系列,y_温度=系列测试_分割(X,
Y
分层=y,
试验尺寸=(1.0-压裂机组),
随机状态=随机状态)
#将临时数据帧拆分为val和测试数据帧。
相对压裂试验=压裂试验/(压裂试验值+压裂试验)
df_val,df_test,y_val,y_test=列车试验分割(df_temp,
y_temp,
分层=y_温度,
测试尺寸=相对压裂测试,
随机状态=随机状态)
断言len(df_输入)==len(df_序列)+len(df_值)+len(df_测试)
返回测向列,测向值,测向测试
下面是一个完整的工作示例

考虑一个数据集,该数据集具有一个要在其上执行分层的标签。此标签在原始数据集中有自己的分布,例如75%
foo
、15%
bar
和10%
baz
。现在,让我们使用60/20/20比率将数据集拆分为训练、验证和测试子集,其中每个拆分保留相同的标签分布。请参见下图:

以下是示例数据集:

df=pd.DataFrame({'A':列表(范围(01000)),
“B”:列表(范围(100,0,-1)),
‘标签’:['foo']*75+['bar']*15+['baz']*10})
df.head()
#标签
#0 100 foo
#1199富
#298富
#397富
#4 96富
形状
# (100, 3)
df.label.value_counts()
#富75
#酒吧15
#巴兹10
#名称:label,数据类型:int64
现在,让我们从上面调用
split\u to\u train\u val\u test()
函数,以获得60/20/20比率的训练、验证和测试数据帧

df_序列、df_值、df_测试=\
将分层分为分层测试(df,分层colname='label',分形测试=0.60,分形测试=0.20,分形测试=0.20)
三个数据帧
df_train
df_val
df_test
包含所有原始行,但其大小将遵循上述比率

df_train.shape
#(60, 3)
df_val.shape
#(20, 3)
df_测试形状
#(20, 3)
此外,三个分割中的每一个将具有相同的标签分布,即75%
foo
,15%
barX_train, X_test, y_train, y_test = train_test_split(
        X, y,stratify=y, test_size=0.4)

X_test, X_val, y_test, y_val = train_test_split(
        X_test, y_test, stratify=y_test, test_size=0.5)
train_df = df.sample(frac=0.7, random_state=random_seed)
tmp_df = df.drop(train_df.index)
test_df = tmp_df.sample(frac=0.33333, random_state=random_seed)
valid_df = tmp_df.drop(test_df.index)

assert len(df) == len(train_df) + len(valid_df) + len(test_df), "Dataset sizes don't add up"
del tmp_df