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
问题解决思路
修复生成器迭代判断逻辑
你用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显式传递特征名称
你传入的是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)
- 直接传入DataFrame(保留原有特征名):
添加缓存前缀
官方示例指定了cache_prefix,你的代码未设置,可能导致缓存文件异常。初始化时加上缓存路径:def __init__(self) -> None: super().__init__(cache_prefix="./xgboost_cache") self.chunks = self.generate_data()
内容的提问来源于stack exchange,提问作者meowmeow
相关产品推荐
相关产品推荐

