如何避免继承过程中 init 中的代码重复?扩展 xgb.XGBClassifier 来处理功能名称



我在扩展类时有具体问题xgb.XGBClassifier但它可以框定为一般的OOP问题。

我的实现基于: https://github.com/dmlc/xgboost/blob/master/python-package/xgboost/sklearn.py

基本上,我希望在提供的数据在熊猫数据帧中时添加功能名称处理。

几点意见:

  • XGBClassifierN__init__中具有与基类xgb.XGBClassifier相同的参数,
  • 还有一个附加属性self.feature_names由后面的fit方法设置。
  • 其余的可以通过混入来完成。

它有效。

困扰我的是__init__中的这堵代码墙。它是通过复制粘贴默认值完成的,每次xgb.Classifier更改时都必须更新它。

有没有办法简洁地表达子类XGBClassifierN具有与父类相同的参数和默认值的想法xgb.XGBClassifier并执行稍后的操作,例如clf = XGBClassifierN(n_jobs=-1)

我尝试只使用**kwargs但没有成功(解释器开始抱怨没有missing参数(没有双关语(,要使其工作基本上你需要设置更多参数(。

import xgboost as xgb
class XGBClassifierN(xgb.XGBClassifier):
def __init__(self, base_score=0.5, booster='gbtree', colsample_bylevel=1,
colsample_bynode=1, colsample_bytree=1, gamma=0,
learning_rate=0.1, max_delta_step=0, max_depth=3,
min_child_weight=1, missing=None, n_estimators=100, n_jobs=1,
nthread=None, objective='binary:logistic', random_state=0,
reg_alpha=0, reg_lambda=1, scale_pos_weight=1, seed=None,
silent=None, subsample=1, verbosity=1, **kwargs): 
super().__init__(base_score=base_score, booster=booster, colsample_bylevel=colsample_bylevel,
colsample_bynode=colsample_bynode, colsample_bytree=colsample_bytree, gamma=gamma,
learning_rate=learning_rate, max_delta_step=max_delta_step, max_depth=max_depth,
min_child_weight=min_child_weight, missing=missing, n_estimators=n_estimators, n_jobs=n_jobs,
nthread=nthread, objective=objective, random_state=random_state,
reg_alpha=reg_alpha, reg_lambda=reg_lambda, scale_pos_weight=scale_pos_weight, seed=seed,
silent=silent, subsample=subsample, verbosity=verbosity, **kwargs)
self.feature_names = None
def fit(self, X, y=None):
self.feature_names = list(X.columns)
return super().fit(X, y)
def get_feature_names(self):
if not isinstance(self.feature_names, list):
raise ValueError('Must fit data first!')
else:
return self.feature_names
def get_feature_importances(self):
return dict(zip(self.get_feature_names(), self.feature_importances_))

我尝试只使用**kwargs,但没有成功。

"不起作用"是对问题的最无用的描述。相反,您应该准确记录所有相关详细信息的情况。

话虽如此,如果您的问题是"如何避免重新键入完整的父方法签名等",那么您实际上与**kwargs非常接近,只是缺少位置参数部分*args

def __init__(self, *args, **kwargs): 
super().__init__(*args, **kwargs)
self.feature_names = None

请注意,这使得签名对检查毫无用处(pydoc,内置help()函数,IDE自动完成等(。

编辑:实际上,可能有一种方法 - 至少,根据这个答案,functools.wraps()可以保留装饰函数的签名。还有Michele Simionato的"装饰器"库提供相同的服务,所以你应该能够重用这段代码来吃你的蛋糕!-(

最新更新