1.留出法可用sklearn包ShuffleSplittrain_test_split实现

2.ShuffleSplit可以实现多次随机划分,train_test_split只能实现一次

3.random_state相同时,ShuffleSplit的首次切分结果与train_test_split完全一致

4.交叉验证法可用KFold、StratifiedKFold实现,逻辑一致,后者针对分类问题实现分层抽样

5.sklearn建模与调参的包cross_validateGridSearchCV的数据集划分逻辑一致

6.如果是分类问题,cross_validate采取StratifiedKFold划分方法,其他都是采取KFold方法

小编在文章 机器学习之模型评估 介绍了数据集划分的方法,本文从就专门针对数据集划分的sklearn实现做一个详细介绍。

注:sklearn的函数包实在太多,有纰漏的地方还望指正

1.留出法

sklearn实现留出法的主要有两个包:ShuffleSplit和train_test_split。先给结论:

1.train_test_split实行单次数据集划分,通过参数random_state选定种子数

2.对于分类问题,train_test_split通过stratify参数实现分层抽样.

2.ShuffleSplit实行多次随机切分,默认10次,如果random_state参数与train_test_split相同,则第一次的切分方式与train_test_split完全一致

3.ShuffleSplit每一次的测试集训练集样本选取都是随机的

train_test_split是用得最多的数据集划分包,它的参数有五个:

  • *arrays:要切分的数据集,通过传入两个,X数据集和目标y

  • test_size:测试集样本大小

  • random_state:随机种子数

  • shuffle:是否要对数据集随机打乱

  • stratify:可以理解为分层抽样的设置值,通过针对分类问题的目标y

from sklearn.model_selection import train_test_split

X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.3)
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.3,stratify=y) #按y比例分层抽样,通过用于分类问题

但train_test_split一次只对数据集切分一次,而单次使用留出法得到的估计结果往往不够稳定可靠,一般采用若干次随机划分、重复进行实验评估后取平均值作为留出法的评估效果。

如果要进行若干次随机划分,那么要使用train_test_split若干次,每次设置不同的random_state即可。也可以通过ShuffleSplit实现。

ShuffleSplit分两部分组成,第一部分Shuffle,是指对数据集进行随机打乱;第二部分Split,就是切分的意思。也就是对数据集打乱并且切分。它的参数有四个:

  • n_splits:随机划分多少次,默认是10

  • test_size:每一折的测试集样本多大

  • train_size:每一折的训练集样本多大,一般设置测试集即可

  • random_state:随机种子数,通常情况选定一个数就行

比如下面这个例子:

rs = ShuffleSplit(n_splits=10,test_size=0.3,random_state=1)
for index in rs.split(df):
    X_train = df.loc[index[0],X.columns]
    y_train = df.loc[index[0],'y']
    X_test = df.loc[index[1],X.columns]
    y_test = df.loc[index[1],'y']

df是数据集,包含X的所有变量和目标变量y。这里是进行10次随机划分,每次测试集的比例是0.3.在对数据集df切分时,返回的是df的索引数组(训练集索引+测试集索引)。用语句for进行循环,一共有10次(因为10次随机划分),每一次用index接收,它是元组,里面有两个元素,每个元素是一个数组,分别对应每次划分的训练集和测试集索引

注:这里需要说明的一点是,如果ShuffleSplit和train_test_split设置的随机种子相同,也就是random_state一样,那么ShuffleSplit的第一次切分方式与train_test_split完全一致

2.交叉验证法

sklearn实现交叉验证的主要有四个包:

from sklearn.model_selection import KFold
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import cross_validate
from sklearn.model_selection import GridSearchCV

第三、第四个包主要是在训练模型过程中内置的划分方法,也就是不用事先切分数据集,直接把数据集传进去后,训练模型前会自动进行交叉验证了。

同样先给结论:

1.KFold把数据集分为互斥的n折,每次循环取一折作为测试集

2.StratifiedKFold原理与KFold一致,唯一的不同是实现对目标y的分层抽样

3.cross_validate与GridSearchCV划分数据集逻辑是完全一致的

4.如果是分类问题,cross_validate采取StratifiedKFold划分方法,其他都是采取KFold方法

KFold的参数有三个:

  • n_splits:划分多少折

  • shuffle:是否打乱原始数据集的顺序,默认为False

  • random_state:随机种子数,只有在shuffle为True的时候起作用

KFold通过参数n_splits是把数据集划分为互斥的n份,如果shuffle是False,那么程序会按照原始数据集按索引顺序划分,这一点需要注意!!!

用一个例子说明:

df只有10个样本的数据集,这里不进行打乱顺序划分5折。可以看到,每一折的测试集上的index索引从0-9.

StratifiedKFold的参数跟KFold是一样的,但是它的功能是实现分层抽样,源代码给出了解释:

因为要实现分层,所以必须传入要指定分层的变量

skf = StratifiedKFold(n_splits=3,random_state=None)

for index in skf.split(X,y): #因为是3等分,即3折交叉,一共循环3次
    X_train = X.loc[index[0],:]
    y_train = y[index[0]]
    X_test = X.loc[index[1],:]
    y_test = y[index[1]]

cross_validateGridSearchCV是训练模型的包,它的参数很多,以后讲到模型训练再专门介绍,这里要注意的是参数cv,也就是交叉验证的划分方式,如果是分类问题,cv采取StratifiedKFold的逻辑,其他情况采取KFold的逻辑,源代码也给出了解释:

下面通过两个例子(分类与回归各一个)来理解。

分类问题

用内置的数据集来建模,先获取数据集

from sklearn.datasets import load_breast_cancer

data1 = pd.DataFrame(load_breast_cancer(return_X_y=True)[0],columns=['X'+str(i) for i in range(1,31)])
data2 = pd.DataFrame(load_breast_cancer(return_X_y=True)[1],columns=['label'])
data = pd.concat([data1,data2],axis=1)
X = data.drop(['label'],axis=1)
y = data['label']
feature_li = list(X.columns)

用三种sklearn方式建模:

#采取accuracy评价指标

#StratifiedKFold建模过程
skf = StratifiedKFold(n_splits=3,random_state=None)
rf = RandomForestClassifier(n_estimators=10,random_state=10)
print('StratifiedKFold结果:')
for index in skf.split(X,y): #因为是3等分,即3折交叉,一共循环3次
    X_train = X.loc[index[0],:]
    y_train = y[index[0]]
    X_test = X.loc[index[1],:]
    y_test = y[index[1]]
    rf.fit(X_train,y_train)
    y_pred = rf.predict(X_test)
    print(rf.score(X_test,y_test))

#利用cross_validate建模
cv_results = cross_validate(RandomForestClassifier(n_estimators=10,random_state=10),
                            X,y,cv=3,scoring='accuracy')
print('cross_validate结果:',cv_results['test_score'])
  
#利用GridSearchCV建模
param_grid = {'n_estimators':[10]}
gs = GridSearchCV(RandomForestClassifier(random_state=10), param_grid,
                  scoring='accuracy', cv=3, n_jobs=-1) #设置参数verbose=1,可以查看训练进程

gs.fit(X,y)
print('GridSearchCV结果:')
pd.DataFrame(gs.cv_results_)[['param_n_estimators','split0_test_score','split1_test_score','split2_test_score']]

来看看结果:

三种方式的cv划分方式一致,用相同算法建模的结果也一致

回归问题

用内置的数据集来建模,先获取数据集

from sklearn.datasets import load_boston

diabetes = load_boston()
X = pd.DataFrame(diabetes.data,columns=diabetes.feature_names)
y = diabetes.target
data = pd.concat([X,pd.DataFrame(y,columns=['y'])],axis=1)
li = list(X.columns)

用三种sklearn方式建模:

#采取r2作为评价指标
f = make_scorer(r2_score)

#KFold建模过程
kf = KFold(n_splits=3,random_state=None)
rf = RandomForestRegressor(n_estimators=10,random_state=10)
print('KFlod结果:')
for index in kf.split(data): #5折交叉,一共循环5次
    X_train = data.loc[index[0],li]
    y_train = data.loc[index[0],'y']
    X_test = data.loc[index[1],li]
    y_test = data.loc[index[1],'y']
    rf.fit(X_train,y_train)
    y_pred = rf.predict(X_test)
    print(r2_score(y_test,y_pred))

#利用cross_validate建模
cv_results = cross_validate(RandomForestRegressor(n_estimators=10,random_state=10),X,y,cv=3,scoring=f)
print('cross_validate结果:',cv_results['test_score'])


#利用GridSearchCV建模
param_grid = {'n_estimators':[10]}
gs = GridSearchCV(RandomForestRegressor(random_state=10), param_grid,
                  scoring=f, cv=3, n_jobs=-1)

gs.fit(X,y)
print('GridSearchCV结果:')
pd.DataFrame(gs.cv_results_)[['param_n_estimators','split0_test_score','split1_test_score','split2_test_score']]

来看看结果:

三种方式的cv划分方式一致,用相同算法建模的结果也一致

3.自助法

数据划分方法还有第三种——自助法,自助法相对简单,一段代码解决

train = df.sample(frac=1.0,replace=True,random_state=0)
cross_vad = df.loc[df.index.difference(train.index)].copy()

注:sklean的随机森林模型内置了自助法,不用单独切分数据集,可通过内置包查看其参数

from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import RandomForestRegressor

4.建模一般切分方式

在实际工作的建模过程中,因为数据样本是有限的,而且我们可能会针对同一课题建立不同的模型,那么在没有更多数据的情况下,我们通常需要预留一部分数据作为模型的unseen data,也就是评估模型好坏。而调参的过程依赖于验证集,且一次切分的样本具有随机性,所以,实际上留出法与交叉验证法的sklearn包我们结合使用。

这里给出数据集的划分图解,以后介绍建模和调参的skearn包再作展开

参考资料:

https://www.cnblogs.com/wj-1314/p/10422159.html

https://scikit-learn.org/stable/user_guide.html

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐