Python scikit学习类实例上的Monkey补丁魔术方法
我试图构建一个名为Python scikit学习类实例上的Monkey补丁魔术方法,python,scikit-learn,monkeypatching,magic-methods,Python,Scikit Learn,Monkeypatching,Magic Methods,我试图构建一个名为SafeModel的工厂类,它的generate方法接受一个scikit学习类的实例,更改它的一些属性,并返回相同的实例。具体地说,对于本例,我想访问返回模型的coef\u属性,在案例1)中,如果基础scikit学习类包含coef\u,则返回该类“coef\u,在案例2中,如果基础scikit学习类包含功能重要性,返回该类“功能\u重要性” 我成功地修补了Python类实例的属性。我在修补Python类实例的神奇方法方面没有那么成功。我的案例需要注意的是:在scikit学习类实
SafeModel
的工厂类,它的generate
方法接受一个scikit学习类的实例,更改它的一些属性,并返回相同的实例。具体地说,对于本例,我想访问返回模型的coef\u
属性,在案例1)中,如果基础scikit学习类包含coef\u
,则返回该类“coef\u
,在案例2中,如果基础scikit学习类包含功能重要性
,返回该类“功能\u重要性”
我成功地修补了Python类实例的属性。我在修补Python类实例的神奇方法方面没有那么成功。我的案例需要注意的是:在scikit学习类实例化时,属性coef\u
和feature\u importances
从未定义过;相反,它们仅在对各自的类调用fit
方法后定义。因此,我无法覆盖属性定义本身
from types import MethodType
class SafeModel:
FALLBACK_ATTRIBUTES = {
'coef_': ['feature_importances_'],
}
@classmethod
def generate(cls, model):
safe_model = cls._secure_attributes(model)
return safe_model
@classmethod
def _secure_attributes(cls, model):
def __secure_getattr__(self, name):
for fallback_attribute in cls.FALLBACK_ATTRIBUTES[name]:
try:
return getattr(self, fallback_attribute)
except:
continue
model.__getattr__ = MethodType(__secure_getattr__, model)
return model
from sklearn.ensemble import RandomForestClassifier
model = SafeModel.generate(RandomForestClassifier())
model.coef_ # AttributeError: 'RandomForestClassifier' object has no attribute 'coef_'
我无法确定你的代码有什么问题。不过,我发现了一种可能适用于您的用例的解决方法。
我使用了一种不同的策略,因为我只是使用了
SafeModel.\uuu getattr\uuuu
作为模型getattr
方法的包装,而不是猴子补丁
from sklearn.utils.validation import NotFittedError
from sklearn.ensemble import RandomForestClassifier
class SafeModel(object):
def __init__(self, model):
self.FALLBACK_ATTRIBUTES = {
'coef_': ['feature_importances_'],
}
self.model = model
def __getattr__(self, name):
try:
return getattr(self.model, name)
except AttributeError:
pass
for fallback_attribute in self.FALLBACK_ATTRIBUTES[name]:
try:
return getattr(self.model, fallback_attribute)
except NotFittedError as e:
# NotFittedError inherits AttributeError.
raise e
except AttributeError:
continue
else:
raise AttributeError(
"{} object has no attribute {}.".format(
self.__class__.__name__, name) +
" Could not retrieve any fallback attribute.")
model = SafeModel(RandomForestClassifier())
model.coef_
输出:
NotFittedError: Estimator not fitted, call `fit` before `feature_importances_`.
请注意,这是正常的行为,正如您所提到的,在适应随机林之前,您无法访问功能\u重要性
诚然,异常捕获在这里相当脆弱(您需要添加一组可能引发的异常),但是如果您在尝试访问属性时不关心引发适当的异常,那么应该可以
如果对你有效,请告诉我。如果你知道你发布的代码是怎么回事,我也会对解释感兴趣 不幸的是,我希望使用SafeModel
作为工厂,比如model=SafeModel.generate(RandomForestClassifier())
,它返回sk learn对象的修改实例。上面,我们只剩下一个SafeModel
的实例。难道你就不能将它用作装饰器吗?然后,您的模型不是SafeModel
实例,而是用\uu getattr\uuu
@cavaunpeu Ok修饰的。仅供参考,我试图将打印语句放在“secure_getattr”中,但它们从未显示。我甚至无法在getattr上应用一个简单的装饰程序。查伦索伊斯:如果你能做到这一点,我很想看到一个解决方案。@user3914041我尝试了同样的方法,但没有效果。我认为Python调用magic方法的方式与调用非magic方法的方式根本不同(通过访问相关实例的dict属性)。@cavaunpeu也许,我能够使用您的代码覆盖fit。但无法让神奇的方法发挥作用。