Python 什么';这里怎么了?意外引用现有实例而不是创建新实例

Python 什么';这里怎么了?意外引用现有实例而不是创建新实例,python,class,python-3.x,scikit-learn,instance,Python,Class,Python 3.x,Scikit Learn,Instance,我希望能更自如地使用Python。我编写了一种迷你API,可以很容易地比较适合同一数据的不同统计模型,这样我就可以预先设置所有模型超参数,然后迭代不同的模型以适合它们 这就是我想做的本质: 围绕Scikit学习构建包装类分类器,然后基于Scikit学习的一个内置估计器构建,例如 创建这些未安装的分类器的字典,以及要循环的不同参数字典 迭代两个字典,让每个未安装的分类器生成基础管道的新实例,使用其[Pipeline.fit][1]方法对其进行安装,并将新安装的管道保存在不同的字典中 然而,在每次迭

我希望能更自如地使用Python。我编写了一种迷你API,可以很容易地比较适合同一数据的不同统计模型,这样我就可以预先设置所有模型超参数,然后迭代不同的模型以适合它们

这就是我想做的本质:

  • 围绕Scikit学习构建包装类
    分类器
    ,然后基于Scikit学习的一个内置估计器构建,例如
  • 创建这些未安装的
    分类器的字典,以及要循环的不同参数字典
  • 迭代两个字典,让每个未安装的
    分类器
    生成基础管道的新实例,使用其
    [Pipeline.fit][1]
    方法对其进行安装,并将新安装的管道保存在不同的字典中
  • 然而,在每次迭代中,似乎不是生成管道的新实例,而是重新调整管道的同一实例(或者可能是基础估计器)。这是一个问题,因为
    Pipeline.fit
    方法修改了管道(和基础估计器),因此先前迭代的拟合结果都会被最终迭代的拟合结果覆盖

    问题是,我不知道这个“父实例”是在哪里创建的,以及它是如何被引用的

    这个问题的一个可复制的例子的基本设置是(在这里复制粘贴有点太长)。我在最后添加了一份打印声明来说明这个问题


    对不起,如果这是一个有点模糊,但我不容易描述它。希望从示例中可以清楚地看到问题。

    问题在于
    结果['0']['rf']
    结果['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)
    
    您正在重新安装一条已安装的管道,丢失了以前的工作

    要解决这个问题,您需要在每次安装时创建一个新的
    分类器实例。一种可能的方法是将
    分类器
    字典从包含
    分类器
    实例的字典更改为包含创建
    分类器所需的参数的字典:

    classifiers = {
        'rf': (RandomForestClassifier, n_estimators=100, oob_score=True, bootstrap=True),
        'ab': (AdaBoostClassifier, n_estimators=50)
    }
    
    现在,在循环中,您应该使用一种称为“tuple unpacking”的Python习惯用法来解压参数,并为每个组合创建一个单独的
    分类器
    实例

    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)
    

    请注意,要迭代字典中的键,只需为dct中的键编写
    ,而不是为dct中的键编写
    。keys()

    这就是我认为我正在做的事情。这是
    make_pipe
    函数的作用,顺便说一句,我知道这是你的意思,但实际上是
    results['0']['rf'].steps[2][1]
    id(results['1']['rf'].steps[2][1]
    相同:
    打印(id(results['0']['rf'].steps[2][1]),id(results['1']['rf 1'].steps[2][1]),sep=\n']
    打印(id(结果['0']['rf'])、id(结果['1']['rf'])、sep='\n')
    @ssdecontrol啊,我看我看错了你的代码。我以为
    fit
    是在修改
    分类器
    ,但实际上它调用了
    make_pipe
    ,它创建了一个新的管道对象,然后拟合该管道并返回它。所以你是对的。真正的问题是你正在创建一个
    RandomFores的实例tClassifier
    AdaBoostClassifier
    当您初始化
    分类器时,每次使用
    make\u pipe
    创建新管道时都会使用相同的实例。当然,您可以通过将创建分类器的代码从
    \uu init\uuuuu
    移动到
    make\u pipe
    来解决这个问题。是的这正是我所做的。谢谢!这是我在R中开发的功能,但还没有找到令人满意的解决方案。