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

使用JSON反序列化sklearn模型时,无法为只读属性赋值的问题

解决DecisionTreeRegressor JSON序列化/反序列化的只读属性问题

你遇到的这个问题很典型——pickle和常规属性赋值的逻辑完全不同,这也是它能绕过只读属性限制的核心原因。下面我分两部分给你解释和解决:

Pickle是怎么实现的?

Pickle的工作机制和你用setattr赋值完全不一样:它不会走常规的属性设置流程,而是直接操作对象的底层内存结构和内部字典。具体来说:

  • 当pickle加载对象时,它会先创建一个未初始化的空对象(不会调用类的__init__方法)
  • 然后直接把之前保存的属性数据写入对象的__dict__(实例属性字典)或者对应的内存区域
  • 这种方式完全绕过了属性的访问控制(比如只读属性的setter限制),所以像feature_importances_这类属性能被直接恢复

而你用setattr的时候,是在调用属性的设置逻辑,一旦属性被定义为只读(比如通过@property装饰器且没有setter),就会抛出AttributeError。

如何用JSON实现相同效果?

要解决这个问题,我们需要模仿pickle的思路,绕过setattr的限制,直接操作对象的内部字典。针对你的代码,这里有几个具体的修改方案:

1. 修改_set_params方法,直接操作__dict__

把原来的setattr替换为“先尝试常规赋值,失败则直接写入__dict__”的逻辑,这样就能处理只读属性:

def _set_params(self, obj, **param_dict):
    for k, v in param_dict.items():
        print(k, v)
        # 转换numpy数组
        value = np.array(v) if isinstance(v, list) else v
        try:
            # 先尝试常规赋值
            setattr(obj, k, value)
        except AttributeError:
            # 只读属性直接写入__dict__
            obj.__dict__[k] = value

2. 确保关键属性被正确保存

检查你在save_json里的排除列表,比如list_main_exclude里不要包含feature_importances_,确保这个属性被加入到保存的attrs_main字典中。如果之前不小心排除了,把它从排除列表里移除。

3. 处理Tree对象的特殊属性

对于tree_对象的属性,同样可以用上述逻辑。另外,创建Tree实例时,要确保初始化参数和原模型完全一致,比如n_features、n_classes、n_outputs的类型和值都要匹配。

额外提醒

  • 有些sklearn模型的属性可能存在于__slots__中(而不是__dict__),这种情况可以尝试用object.__setattr__(obj, k, value)来强制赋值,这是最底层的属性设置方法,能绕过几乎所有限制
  • 测试时一定要对比加载后的模型和原模型的预测结果、feature_importances_、tree_的关键属性,确保两者完全一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:22:25