这有什么不对?意外引用现有实例而不是创建新实例

时间:2015-06-26 17:34:16

标签: python class python-3.x scikit-learn instance

我是R user希望更熟悉Python。我写了一种迷你API,可以很容易地比较适用于相同数据的不同统计模型,这样我就可以预先设置所有模型超参数,然后迭代不同的模型以适应它们。

这是我想要做的事情的本质:

  1. 围绕Scikit-learn Pipeline构建一个包装类Classifier,然后依据Scikit-learn的内置估算器构建,例如RandomForestClassifier
  2. 创建这些未装配的Classifier的字典,以及要循环的不同参数字典
  3. 对两个字典进行迭代,让每个字符串Classifier生成基础管道的新实例,使用其[Pipeline.fit][1]方法拟合,并保存新的,在不同的字典中安装管道
  4. 然而,似乎不是在每次迭代中生成管道的新实例,而是重新安装管道(或者可能是基础估算器)的相同实例。这是一个问题,因为Pipeline.fit方法修改了Pipeline(和底层估算器),因此前一次迭代的拟合结果都会被最终迭代的拟合结果覆盖。

    问题是我无法弄清楚这个“父实例”的创建位置以及它是如何被引用的。

    问题的可重复示例的基本设置在this Gist(这里复制和粘贴的时间有点太长)。我在最后添加了一份印刷声明来说明问题。

    对不起,如果这有点模糊,但我没有很容易描述它。希望这个例子能清楚地解决这个问题。

1 个答案:

答案 0 :(得分:1)

问题是results['0']['rf']results['1']['rf']实际上是同一个对象。因此,当您在循环中适合管道时:

results = dict()
for k in features.keys():
    results[k] = dict()
    for m in classifiers.keys():
        print(len(features[k]))
        results[k][m] = classifiers[m].fit(features[k], 'species', iris)

您正在重新安装已经适合的管道,失去以前的工作。

要解决此问题,您需要在每次适合时创建Classifier的新实例。一种可能的方法是将classifiers字典从包含Classifier个实例的字典更改为包含创建Classifier所需参数的字典:

classifiers = {
    'rf': (RandomForestClassifier, n_estimators=100, oob_score=True, bootstrap=True),
    'ab': (AdaBoostClassifier, n_estimators=50)
}

现在,在你的循环中你应该使用一个称为“tuple unpacking”的Python习惯来解压参数并为每个组合创建一个单独的Classifier实例

for k in features:
    results[k] = dict()
    for m in classifiers:
        print(len(features[k]))
        classifier = Classifier(*classifiers[m])
        results[k][m] = classifier.fit(features[k], 'species', iris)

请注意,要迭代字典的键,可以简单地写for key in dct:,而不是for key in dct.keys()