本文讨论了评估模型性能时的数据泄露问题以及避免方法。当训练集的数据在模型评估期间进入验证/测试集时,就会发生数据泄漏。这将导致模型在验证/测试集上的性能评估出现偏差。让我们通过使用Scikit-Learn的“波士顿房价”数据集的示例来理解它。该数据集没有缺失值,所以随机引入100个缺失值,以更好地展示数据泄漏。importnumpyasnpimportpandasaspdfromsklearn.datasetsimportload_bostonfromsklearn.preprocessingimportStandardScalerfromsklearn.pipelineimportPipelinefromsklearn.imputeimportSimpleImputerfromsklearn.neighborsimportKNeighborsRegressorfromsklearn.model_selectionimportcross_validate,train_test_splitfromsklearn.metricsimportmean_squared_error#Importingthedatasetdata=pd.DataFrame(load_boston()['data'],columns=load_boston()['feature_names'])data['target']=load_boston()['target']#SplittheinputandtargetfeaturesX=data.iloc[:,:-1].copy()y=data.iloc[:,-1].copy()#Adding100randommissingvaluesnp.random.seed(11)rand_cols=np.random.randint(0,X.shape[1],100)rand_rows=np.random.randint(0,X.shape[0],100)fori,jinzip(rand_rows,rand_cols):X.iloc[i,j]=np.nan#SplittingthedataintotrainingandtestsetsX_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.2,random_state=11)#InitislizingKNNRegressorknn=KNeighborsRegressor()#Initializingmodeimputerimp=SimpleImputer(strat例如='most_frequent')#InitializingStandardScalerstandard_scaler=StandardScaler()#ImputingandscalingX_trainX_train_impute=imp.fit_transform(X_train).copy()X_train_scaled=standard_scaler.fit_transform(X_train_impute).copy()#Running5-foldcross-validationcv=cross_validate(estimator=knn,X=X_train_scaled,y=y_train,cv=5,scoring="neg_root_mean_squared_error",return_train_score=True)#Calculatingmeanofthetrainingscoresofcross-validationprint(f'TrainingRMSE(withdataleakage):{-1*np.mean(cv["train_score"])}')#Calculatingmeanofthevalidationscoresofcross-validationprint(f'validationRMSE(withdataleakage):{-1*np.mean(cv["test_score"])}')#fittingthemodeltothetrainingdatalr.fit(X_train_scaled,y_train)#preprocessingthetestdataX_test_impute=imp.transform(X_test).copy()X_test_scaled=standard_scaler.transform(X_test_impute).copy()#Predictionsandmodelevaluationonunseendatapred=lr.predict(X_test_scaled)print(f'RMSEonunseendata:{np.sqrt(mean_squared_error(y_test,pred))}')在上面的代码中,'Xtrain'是训练集(k-fold交叉验证),'Xtest'用于未见数据的模型评估上面的代码是一个带有示例的模型数据泄漏的模型评估,其中用于估算缺失值的模式(strategy='mostfrequent')是在“Xtrain”上计算的。同样,用于缩放数据的均值和标准差也使用“Xtrain”计算。'Xtrain'的缺失值将被输入,'X_train'在k-fold交叉验证之前被缩放。在k折交叉验证中,“Xtrain”被分成“k”折。在每个k折交叉验证迭代中,其中一个折叠用于验证(我们称之为验证部分),其余折叠用于训练(我们称之为训练部分)。对于使用“Xtrain”计算的模型输入,每次迭代中的训练和验证部分都有缺失值。同样,它们已使用在“Xtrain”上计算的均值和标准差进行了缩放。这种估计和缩放操作导致来自“Xtrain”的信息泄漏到k折交叉验证的训练和验证部分。这种信息泄漏可能导致模型在验证部分的性能估计有偏差。下面的代码显示了一种通过使用管道来避免它的方法。#Preprocessingandregressorpipelinepipeline=Pipeline(steps=[['imputer',imp],['scaler',standard_scaler],['regressor',knn]])#Running5-foldcross-validationusingpipelineasestimatorcv=cross_validate(estimator=pipeline,X=X_train,y=y_train,cv=5,scoring="neg_root_mean_squared_error",return_train_score=True)#Calculatingmeanofthetrainingscoresofcross-validationprint(f'TrainingRMSE(withoutdataleakage):{-1*np.meanoss(cv["train_score"])}')#Calculatingmeanofthecridations-validationprint(f'validationRMSE(withoutdataleakage):{-1*np.mean(cv["test_score"])}')#fittingthepipelinetothetrainingdatapipeline.fit(X_train,y_train)#Predictionsandmodelevaluationonunseendatapred=pipeline.predict(X_test)print(f'RMSEonunseendata:{np.sqrt(mean_squared_error(y_test,pred))}')在上面的代码中,我们在管道中包含了输入器、标量和回归器。在这个例子中,“X_train”被分成5份,在每次迭代中,管道使用训练部分来计算用于在训练和验证部分输入缺失值的模式。同样,用于测量训练和验证部分的均值和标准差也在训练部分计算。这个过程消除了数据泄漏,因为插补模式和缩放的均值和标准差是在k折交叉验证的每次迭代期间在训练部分计算的。在每次k折交叉验证迭代中,这些值用于计算和扩展训练和验证部分。我们可以看到在有和没有数据泄漏的情况下计算的训练和验证RMSE的差异。由于数据集很小,我们只能看到它们之间的微小差异。在大型数据集的情况下,这种差异可能很大。对于看不见的数据,验证RMSE(有数据泄漏)接近RMSE只是偶然的。因此,使用管道进行k折交叉验证可以防止数据泄漏并更好地评估模型在未见数据上的性能。
