这里出了什么问题?意外引用现有实例而不是创建新实例
What's wrong here? accidentally referencing an existing instance instead of making a new one
我是一个 R user 的人,希望更适应 Python。我写了一种 mini-API 可以很容易地比较适合相同数据的不同统计模型,这样我就可以预先设置所有模型超参数,然后按顺序迭代不同的模型适合他们。
这就是我要做的事情的本质:
- 围绕 Scikit-learn
Pipeline
, in turn built on one of Scikit-learn's built-in estimators, e.g. RandomForestClassifier
构建包装器 class Classifier
- 创建一个包含这些未拟合的
Classifier
的字典,以及一个不同的参数字典来循环
- 遍历两个字典,让每个未拟合的
Classifier
生成 底层管道的新实例 ,使用其 [Pipeline.fit][1]
方法对其进行拟合,并将新的、适合的管道保存在不同的字典中
但是,似乎在每次迭代中都没有生成新的管道实例,而是重新装配管道的相同实例(或者可能是底层估算器)。这是一个问题,因为 Pipeline.fit
方法修改了 Pipeline(和底层估计器),因此之前迭代的拟合结果都被最后一次迭代的拟合结果覆盖。
问题是我无法弄清楚这个 "parent instance" 是在哪里创建的以及它是如何被引用的。
具有可重现问题示例的基本设置在 this Gist 中(只是复制粘贴到这里有点太长了)。我在最后添加了一个打印语句来说明这个问题。
抱歉,如果这有点含糊,但我很难描述它。希望示例中的问题很清楚。
问题是 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()
。
我是一个 R user 的人,希望更适应 Python。我写了一种 mini-API 可以很容易地比较适合相同数据的不同统计模型,这样我就可以预先设置所有模型超参数,然后按顺序迭代不同的模型适合他们。
这就是我要做的事情的本质:
- 围绕 Scikit-learn
Pipeline
, in turn built on one of Scikit-learn's built-in estimators, e.g.RandomForestClassifier
构建包装器 class - 创建一个包含这些未拟合的
Classifier
的字典,以及一个不同的参数字典来循环 - 遍历两个字典,让每个未拟合的
Classifier
生成 底层管道的新实例 ,使用其[Pipeline.fit][1]
方法对其进行拟合,并将新的、适合的管道保存在不同的字典中
Classifier
但是,似乎在每次迭代中都没有生成新的管道实例,而是重新装配管道的相同实例(或者可能是底层估算器)。这是一个问题,因为 Pipeline.fit
方法修改了 Pipeline(和底层估计器),因此之前迭代的拟合结果都被最后一次迭代的拟合结果覆盖。
问题是我无法弄清楚这个 "parent instance" 是在哪里创建的以及它是如何被引用的。
具有可重现问题示例的基本设置在 this Gist 中(只是复制粘贴到这里有点太长了)。我在最后添加了一个打印语句来说明这个问题。
抱歉,如果这有点含糊,但我很难描述它。希望示例中的问题很清楚。
问题是 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()
。