You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

XGBoost外部内存实现报错:特征名称不唯一问题求助

使用XGBoost外部内存加载器时遇到「特征名称不唯一」错误

我想用XGBoost处理超出内存的数据集,官方支持自定义数据加载器,我照着逻辑实现了基于生成器的分块读取代码,但调用DMatrix构造函数时一直报「特征名称不唯一」错误——反复检查特征名、甚至只传入单个特征都无法解决问题。

XGBoost官方示例代码

import os
from typing import List, Callable
import xgboost
from sklearn.datasets import load_svmlight_file

class Iterator(xgboost.DataIter):
  def __init__(self, svm_file_paths: List[str]):
    self._file_paths = svm_file_paths
    self._it = 0
    # XGBoost会在当前目录生成前缀为"cache"的缓存文件
    super().__init__(cache_prefix=os.path.join(".", "cache"))

  def next(self, input_data: Callable):
    """迭代前进1步并将数据传递给XGBoost,此方法在DMatrix构建时被调用"""
    if self._it == len(self._file_paths):
      # 返回0告知XGBoost迭代结束
      return 0

    # input_data是XGBoost传入的函数,签名与DMatrix一致
    X, y = load_svmlight_file(self._file_paths[self._it])
    input_data(X, y)
    self._it += 1
    # 返回1告知XGBoost还有未处理的文件
    return 1

  def reset(self):
    """重置迭代器到初始状态"""
    self._it = 0

it = Iterator(["file_0.svm", "file_1.svm", "file_2.svm"])
Xy = xgboost.DMatrix(it)

# 其他树方法如hist、gpu_hist也可用,但有一些注意事项(详见官方文档)
booster = xgboost.train({"tree_method": "approx"}, Xy)

我的实现代码

class data_loader(xgb.DataIter):
    def __init__(self) -> None:
        super().__init__()
        self.chunks = self.generate_data()
    
    def generate_data(self):
        for FILE in Path(DIR).glob('*csv'):
            for df in pd.read_csv(FILE,chunksize=100000):
                x = df[conf["simple_dims"]].values
                y = df[conf["metrics"]].values
                yield x,y

    def reset(self):
        self.chunks = self.generate_data()

    def next(self,input_data:callable):
        try:
            x,y = self.chunks.__next__()
            input_data(x,y)
        except:
            pass
        return 1 if any(self.chunks) else 0

问题解决思路

  1. 修复生成器迭代判断逻辑
    你用any(self.chunks)判断生成器是否还有数据是错误的——any()会提前耗尽生成器,导致后续迭代异常。正确做法是捕获StopIteration异常来判断迭代结束:

    def next(self, input_data: callable):
        try:
            x, y = self.chunks.__next__()
            input_data(x, y)
            return 1  # 还有数据,返回1
        except StopIteration:
            return 0  # 迭代结束,返回0
    
  2. 显式传递特征名称
    你传入的是numpy数组(.values),没有携带特征名称,XGBoost会自动生成默认名称,多次分块传入时可能出现命名冲突。可以两种方式解决:

    • 直接传入DataFrame(保留原有特征名):
      x = df[conf["simple_dims"]]  # 不要用.values转成numpy数组
      y = df[conf["metrics"]].values
      input_data(x, y)
      
    • 传入numpy数组时显式指定特征名:
      feature_names = conf["simple_dims"]
      input_data(x, y, feature_names=feature_names)
      
  3. 添加缓存前缀
    官方示例指定了cache_prefix,你的代码未设置,可能导致缓存文件异常。初始化时加上缓存路径:

    def __init__(self) -> None:
        super().__init__(cache_prefix="./xgboost_cache")
        self.chunks = self.generate_data()
    

内容的提问来源于stack exchange,提问作者meowmeow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 09:01:00