对数据进行预处理,实现K折交叉验证

在深度学习中经常会用到K折交叉验证,本文主要介绍在实际应用中,如何实现图像数据的K折划分,为后面的模型训练与验证做好前期的数据准备工作。

本文主要实现将文件夹中的图像数据进行K折划分,最后将划分好的数据信息以多个子表写入到一个统一的Excel文件中。完整的github代码链接在文章底部。

  • 假设图片已经按照文件夹分好类,文件夹名字的首字母表示类别数字

  •  创建Excel文件,读取图片信息,将图片名称及对应的标签存入到Excel文件中
    def getKFoldData(self):
        imgDataInfo = []    # 统计图像文件名及对应的label,格式:{'img':img1.tif, 'label': 0}
        for category in os.listdir(self.imgRootPath):
            categoryPath = join(self.imgRootPath, category)
            for img in os.listdir(categoryPath):
                imgInfo = {'img':img, 'label': category[0]}
                imgDataInfo.append(imgInfo)
        # 将数据信息写入到excel文件中
        df = pd.DataFrame(imgDataInfo)
        df.to_excel(excelFileSavePath, index=False, sheet_name='originalFile')
  •  分别统计各类别信息,按类别依次进行K折划分,并将划分好的数据写入到上面创建好的Excel文件的不同子表中。
        category_0 = []
        category_1 = []
        category_2 = []
        for dataInfo in imgDataInfo:
            if dataInfo['label'] == '0':
                category_0.append(dataInfo)
            elif dataInfo['label'] == '1':
                category_1.append(dataInfo)
            elif dataInfo['label'] == '2':
                category_2.append(dataInfo)
            else:
                Exception("数据{}的类别异常,为{}:".format(dataInfo["label"], dataInfo["label"]))

        category0_foldSize = int(len(category_0) / self.kFold)
        category1_foldSize = int(len(category_1) / self.kFold)
        category2_foldSize = int(len(category_2) / self.kFold)

       for kthFold in range(self.kFold):
            category_0_fold_train, category_0_fold_valid = self.get_k_fold_index(category_0, category0_foldSize, kthFold)

            category_1_fold_train, category_1_fold_valid = self.get_k_fold_index(category_1, category1_foldSize, kthFold)

            category_2_fold_train, category_2_fold_valid = self.get_k_fold_index(category_2, category2_foldSize, kthFold)


            fold_train = category_0_fold_train + category_1_fold_train + category_2_fold_train
            fold_valid = category_0_fold_valid + category_1_fold_valid + category_2_fold_valid

            train_sheetName = 'train_' + 'fold' + str(kthFold)
            self.createExcelFile(fold_train, train_sheetName)

            valid_sheetName = 'valid_' + 'fold' + str(kthFold)
            self.createExcelFile(fold_valid, valid_sheetName)
  •  K折划分具体实现
    def get_k_fold_index(self, data: List, everyFoldSize: int, kthFold: int) -> List:
        """
        :param foldSize: 每折的数量
        :param kthFold: [0 , self.kFold - 1]
        :return: 返回对应的图片名称
        # 如果 (dataLength % kthFold) != 0,则除不尽多余的数据统一存放到最后一折数据中
        """
        assert kthFold <= self.kFold - 1, "输入的折数:{}超出范围!".format(kthFold)
        dataLength = len(data)
        train = []
        valid = []
        for j in range(self.kFold):
            idx = slice(j * everyFoldSize, (j + 1) * everyFoldSize)
            data_part = data[idx]
            if j == kthFold:
                # 属于验证集的那一折数据
                if kthFold == self.kFold - 1:
                    # 最后一折数据,在(dataLength % kthFold) != 0的情况下,将多余的数据也包含进去
                    index = slice(j * everyFoldSize, dataLength)
                    valid = data[index]
                else:
                    valid = data_part
            elif len(train) == 0:
                train = data_part
            elif j == (self.kFold - 1):
                # 最后一折数据,在(dataLength % kthFold) != 0的情况下,将多余的数据也包含进去
                index = slice(j * everyFoldSize, dataLength)
                data_part = data[index]
                train.extend(data_part)
            else:
                train.extend(data_part)

        return [train, valid]
  •  Excel文件写入具体实现
    def createExcelFile(self, dataInfo: List, sheet_name: str):
        excelData = {'img': [item["img"] for item in dataInfo],
                     'label': [item["label"] for item in dataInfo]}
        df = pd.DataFrame(data=excelData)
        with pd.ExcelWriter(self.excelFileSavePath, mode='a', engine='openpyxl') as writer:
            df.to_excel(writer, sheet_name=sheet_name,  index=False)
        writer.save()
        writer.close()
  •  最后的结果显示

 完整的代码github链接

<think>好的,用户想在鸢尾花数据集上实现K交叉验证,用Python机器学习的方法。首先我需要回顾一下K交叉验证的基本概念和步骤。K交叉验证是将数据集分成K个子集,每次用K-1个子集训练,剩下的一个子集测试,重复K次,最后取平均结果。这有助于更准确地评估模型性能。 接下来,我需要考虑用户可能使用的库。通常,在Python中,scikit-learn是常用的机器学习库,里面包含了鸢尾花数据集和KFold等交叉验证的工具。用户可能对scikit-learn有一定了解,但需要具体的代码示例和步骤说明。 然后,我需要查看用户提供的引用内容。引用[1]和[2]提到了KFold和分层KFold的使用,以及交叉验证的精细控制。引用[3]和[4]则具体提到了鸢尾花数据集的应用实例。这说明用户可能希望结合这些信息,给出一个完整的示例,包括数据加载、预处理、模型训练、交叉验证和结果分析。 我需要确保代码正确无误,并且符合最佳实践。例如,使用分层KFold来处理分类问题,保持每个中的类别分布一致。同,要展示如何计算每的准确率,并汇总平均结果。此外,可能需要提到如何选择最优参数,比如KNN中的K值,但用户的问题主要是实现交叉验证本身,所以可能不需要深入调参。 还要注意用户的系统级指令,比如数学公式的格式要求。但在这个问题中,可能涉及数学公式的地方不多,不过如果有的话,比如准确率的计算,可能需要用行内公式,例如准确率$Acc = \frac{正确分类数}{总样本数}$。 然后,我需要组织步骤:加载数据、划分数据(或者不划分,直接交叉验证整个数据集)、初始化模型、设置KFold参数、循环训练和评估、输出结果。同,要解释每一步的作用,确保用户能够理解。 可能还需要考虑错误处理或常见问题,比如数据是否需要标准化,鸢尾花数据集的特征是否需要缩放。例如,KNN对特征缩放敏感,所以应该在交叉验证过程中进行标准化,但为了避免数据泄漏,应该在每一的训练集上拟合缩放器,然后应用到测试集。不过,用户的问题可能希望简化步骤,所以是否需要包括这个可能需要判断。根据引用中的例子,比如引用[3]中的实例,可能没有进行特征缩放,所以可能在此示例中也不包含,或者可以提到这一点作为优化建议。 另外,用户提供的示例中,快速排序的代码用了Python,所以这里的代码示例也需要用Python,并且正确使用scikit-learn的API。例如,使用cross_val_score函数可以更简洁地实现交叉验证,但用户可能希望手动实现循环过程以便更详细地记录结果,如引用[1]中的代码所示。 需要比较手动实现和使用cross_val_score的两种方法,让用户了解不同的实现方式。引用[2]提到可以使用交叉验证分类器作为cv参数,这可能涉及到更高级的用法,但基础示例可能需要先展示KFold的基本用法。 最后,确保回答结构清晰,分步骤说明,代码正确,并生成相关问题。根据用户提供的示例,相关问题应该与K交叉验证相关,比如如何选择K值,分层KFold的优点,与其他交叉验证方法的比较,以及在交叉验证中调参的方法等。</think>在鸢尾花数据集上实现K交叉验证可分为以下步骤: ### 一、实现步骤 1. **加载数据集** ```python from sklearn.datasets import load_iris iris = load_iris() X, y = iris.data, iris.target ``` 2. **创建K划分器** ```python from sklearn.model_selection import KFold kf = KFold(n_splits=5, shuffle=True, random_state=42) ``` 3. **选择机器学习模型** ```python from sklearn.neighbors import KNeighborsClassifier model = KNeighborsClassifier(n_neighbors=3) ``` 4. **执行交叉验证** ```python scores = [] for train_index, test_index in kf.split(X): X_train, X_test = X[train_index], X[test_index] y_train, y_test = y[train_index], y[test_index] model.fit(X_train, y_train) scores.append(model.score(X_test, y_test)) ``` 5. **结果分析** ```python print(f"五准确率: {scores}") print(f"平均准确率: {sum(scores)/5:.3f}") ``` ### 二、优化方案 - 使用**分层K**更适用于分类问题,保持每类别分布一致: ```python from sklearn.model_selection import StratifiedKFold skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42) ``` - 使用**pipeline**集成数据预处理: ```python from sklearn.pipeline import make_pipeline from sklearn.preprocessing import StandardScaler pipeline = make_pipeline(StandardScaler(), KNeighborsClassifier()) ``` - 直接调用**cross_val_score**简化流程: ```python from sklearn.model_selection import cross_val_score scores = cross_val_score(pipeline, X, y, cv=5) ``` ### 三、代码解析 - `KFold.split()`生成数据索引,保证训练/测试集不重叠 - 分层划分能避免某些类别样本缺失的问题[^2] - 管道(pipeline)确保每次划分都独立进行标准化,避免数据泄漏 - 交叉验证平均准确率$Acc_{avg} = \frac{1}{k}\sum_{i=1}^k Acc_i$反映模型泛化能力 ### 四、输出示例 ``` 五准确率: [0.9667, 1.0, 0.9667, 0.9667, 1.0] 平均准确率: 0.980 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值