xgboost验证用手动拆分功能的数据集拆分实现问题
实现步骤
首先明确认知:你之前对subsample参数的理解有误,该参数是xgboost训练每棵树时对训练样本的随机采样比例,作用是降低过拟合,并不会完成全局的训练集/测试集拆分,这也是你之前生成的分类报告实际是全量数据的训练集表现、而非独立测试集表现的原因。
你可以按照以下步骤完成数据拆分和逻辑改造:
步骤1:读取标签并关联特征路径
首先读取CSV标签文件,把每个样本的标签和对应的特征文件路径做一一关联,避免拆分时出现标签和特征错配的问题:
import pandas as pd import os import numpy as np from sklearn.model_selection import train_test_split import xgboost as xgb from sklearn.metrics import classification_report import time # 替换为你自己的实际路径 LABEL_CSV_PATH = "你的标签文件存储路径.csv" FEATURE_DIR = "你的特征文件存放目录路径" WORKING_DIR = "你的模型存储/运行工作目录路径" # 假设CSV包含两列:sample_id(特征文件的文件名去掉后缀的标识)、label(对应样本标签) label_df = pd.read_csv(LABEL_CSV_PATH) # 拼接每个样本对应的特征文件完整路径,后缀根据你实际的特征文件格式修改,比如.pkl、.png等 label_df['feature_path'] = label_df['sample_id'].apply(lambda x: os.path.join(FEATURE_DIR, f"{x}.npy"))
步骤2:拆分训练/测试集元数据
直接对关联好的元数据表做拆分,保证标签分布一致:
# stratify参数保证训练集、测试集的标签分布和全量数据一致,避免分布偏移导致评估结果失真 train_meta, test_meta = train_test_split(label_df, test_size=0.2, random_state=1, stratify=label_df['label'])
步骤3:编写通用数据加载函数
写函数根据拆分后的元数据批量加载特征和标签:
def load_data(meta_df): X = [] y = [] for _, row in meta_df.iterrows(): # 特征读取逻辑根据你的文件格式调整,比如pkl文件用pickle.load、图像用PIL.Image.open等 feat = np.load(row['feature_path']) X.append(feat) y.append(row['label']) return np.array(X), np.array(y) # 分别加载训练集和测试集 X_train, y_train = load_data(train_meta) X_test, y_test = load_data(test_meta)
步骤4:修改原训练函数,新增独立测试集评估
调整原有train函数的逻辑,训练仅使用80%的训练集,最终分别输出训练集和独立测试集的分类报告:
def train(X_train, y_train, X_test, y_test): os.chdir(WORKING_DIR) start_time = time.time() dtrain = xgb.DMatrix(X_train, label=y_train) dtest = xgb.DMatrix(X_test, label=y_test) try: model = xgb.Booster({'nthread': 4}) model.load_model("model_file.bin") print("已有模型加载完成") except: print('开始训练模型.....') param = {'num_class':4,'objective':'multi:softmax','eval_metric':['merror'],'max_depth':7,'eta':0.04,'subsample':0.8,'min_child_weight':0.5,'max_delta_step':7,'gamma':2,'lambda':10,'colsample_bytree':0.5} # 可选择将测试集加入eval_set,查看训练过程中测试集的指标变化 model = xgb.train(param, dtrain, 420, [(dtrain,'train'), (dtest, 'test')], verbose_eval=20) print('保存模型....') model.save_model('model_file.bin') print('模型保存完成!') print("训练耗时 :", time.time() - start_time) # 输出训练集分类报告 print('===== 训练集分类报告 =====') train_pred = model.predict(dtrain, ntree_limit=420) print(classification_report(y_train, train_pred)) # 输出独立测试集分类报告 print('===== 独立测试集分类报告 =====') test_pred = model.predict(dtest, ntree_limit=420) print(classification_report(y_test, test_pred)) # 调用函数执行 train(X_train, y_train, X_test, y_test)
注意事项
- 请先确认CSV中的sample_id和特征目录下的文件名是一一对应的,避免出现文件找不到的报错
- 原有
subsample=0.8参数可正常保留,该参数的随机采样逻辑仅作用于训练过程,不会影响全局的训练/测试拆分结果 - 如果你的特征维度较高、样本量较大,可以考虑提前把所有特征加载后再做拆分,减少重复IO耗时
内容的提问来源于stack exchange,提问作者user2129623
相关产品推荐
相关产品推荐

