自定义仿lazypredict的K折验证模型对比类,重复运行时数据框追加行问题
问题分析与解决方案
问题现象
实现了支持K折交叉验证的Compare_Models类,可返回模型平均评分的DataFrame,但重复运行时,新的模型评分会追加到原有DataFrame中,无法生成全新的结果。
问题根源
代码中f1_list、name_list等存储评分的列表是类属性,所有Compare_Models的实例会共享这些列表。每次创建实例时,不会清空旧数据,而是继续追加新的模型评分,导致重复运行时结果累加。
修复方案
将这些共享的类属性改为实例属性,在__init__方法中初始化空列表,确保每个实例拥有独立的数据存储,每次创建新实例时都会从头开始收集数据。
修改后的完整代码
import time from typing import List import numpy as np import pandas as pd pd.set_option("display.precision", 4) from sklearn.model_selection import train_test_split from sklearn.model_selection import cross_validate from sklearn.metrics import classification_report from sklearn.metrics import ConfusionMatrixDisplay from tqdm.notebook import tqdm class Compare_Models: scoring = [ "accuracy", "balanced_accuracy", "roc_auc", "precision_weighted", "recall_weighted", "f1_weighted", ] def __init__( self, X: pd.DataFrame, y: pd.DataFrame, models: List, should_print_report: bool = False, ) -> None: self.X = X self.y = y # 初始化实例专属的空列表,替代原类属性 self.f1_list = [] self.name_list = [] self.recall_list = [] self.roc_auc_list = [] self.accuracy_list = [] self.fit_time_list = [] self.precision_list = [] self.score_time_list = [] self.balanced_accuracy_list = [] self.X_train, self.X_test, self.y_train, self.y_test = train_test_split( X, y, random_state=0 ) for model in tqdm(models): name = model.__class__.__name__ if should_print_report: self.__single_run(name, model) self.__cv_run(name, model) def __single_run(self, name, model): start = time.time() clf = model.fit(self.X_train, self.y_train) fit_time = time.time() - start start = time.time() y_pred = clf.predict(self.X_test) predict_time = time.time() - start report = classification_report(self.y_test, y_pred) print(name) print("Fit Time:", fit_time) print("Predict Time:", predict_time) print(report) ConfusionMatrixDisplay.from_predictions( self.y_test, y_pred, normalize="pred", ) def __cv_run(self, name, model): cv_results = cross_validate(model, self.X, self.y, scoring=self.scoring) fit_time = np.mean(cv_results["fit_time"]) f1 = np.mean(cv_results["test_f1_weighted"]) roc_auc = np.mean(cv_results["test_roc_auc"]) score_time = np.mean(cv_results["score_time"]) accuracy = np.mean(cv_results["test_accuracy"]) recall = np.mean(cv_results["test_recall_weighted"]) precision = np.mean(cv_results["test_precision_weighted"]) balanced_accuracy = np.mean(cv_results["test_balanced_accuracy"]) self.f1_list.append(f1) self.name_list.append(name) self.recall_list.append(recall) self.roc_auc_list.append(roc_auc) self.accuracy_list.append(accuracy) self.fit_time_list.append(fit_time) self.precision_list.append(precision) self.score_time_list.append(score_time) self.balanced_accuracy_list.append(balanced_accuracy) def get_scores(self): scores = pd.DataFrame( { "Model": self.name_list, "Accuracy": self.accuracy_list, "Balanced Accuracy": self.balanced_accuracy_list, "ROC AUC": self.roc_auc_list, "Precision Weighted": self.precision_list, "Recall Weighted": self.recall_list, "F1 Weighted": self.f1_list, "Fit Time": self.fit_time_list, "Score Time": self.score_time_list, } ) scores = scores.sort_values(["Fit Time", "Balanced Accuracy"]) return scores
修改说明
- 移除了类定义中的
f1_list、name_list等类属性 - 在
__init__方法中添加这些列表的实例化代码,每个实例都会创建独立的空列表 - 其余逻辑保持不变,确保每次创建
Compare_Models实例时,都会从头开始收集模型评分,不会与之前的实例共享数据
内容的提问来源于stack exchange,提问作者Burhan Khanzada
相关产品推荐
相关产品推荐

