将 DataFrames 附加到字典中的列表 - 为什么每个新 DataFrame 似乎都在引用该列表?

数据挖掘 Python 熊猫
2022-02-12 14:24:34

对于存储在 SampleGroup/SampleID 数据库中的给定样本,我有一个 DataFrame 将一个或多个标签与样本组和 id 配对:

在此处输入图像描述

有大约 100 个标签。我想创建二进制模型来对每个标签进行分类,然后并行运行这些模型来进行多类分类。为了存储这些模型,我正在创建一个表单字典

{label_1:[df_1, model_object_1],
 label_2:[df_2, model_object_2],
...,
label_n:[df_n, model_object_n]
}

其中每个 df 是上述形式的 DataFrame,除了 'Labels' 列的值被替换为 1 或 0,这取决于字典键 'label_i' 是否在该行的原始标签列表中。这是(应该)这样做的代码,这给我带来了一些麻烦:

models = dict.fromkeys(target_labels, [])

for label in target_labels:
    label_list = []
    for multi_label_list in df['Labels']:
        if label in multi_label_list:
            label_list.append(1)
        else:
            label_list.append(0)

    data = {
        'SampleGroup':df['SampleGroup'].copy(),
        'SampleID':df['SampleID'].copy(), 
        'Labels':label_list
    }

    models[label].append(pd.DataFrame(data=data, index=df.index))
    print(len(models[label]))

当我运行它时,为标签创建的每个新二进制 label_list 都会附加到字典中的每个模型,就好像我正在创建对同一个 label_list 的引用(类似于 df2 = df 如何创建对 df 的引用,而不是副本)。上面代码的输出清楚地说明了这个故事:

[len(models[label]) 随着 append 的每次迭代增加 1。[2]

我设法通过将每个新 DataFrame 分配给键而不是将其附加到键的值列表来解决此问题:

models[label] = (pd.DataFrame(data=data, index=df.index))

我调用 DataFrames(或者可能是原生 Python)的什么属性会导致它正常工作,但附加到一个列表以产生奇怪的行为?

1个回答

问题是当您使用创建字典时modelsmodels = dict.fromkeys(target_labels, [])您实际上只创建了一个空列表,并且所有键都指向该列表。您附加的所有内容都进入同一个列表。

例如,

models = dict.fromkeys('abcd', [])
print(models)
print(models['a'] is models['b'])
models['a'].append(3)
print(models)

将返回

{'d': [], 'a': [], 'b': [], 'c': []}
True
{'d': [3], 'a': [3], 'b': [3], 'c': [3]}

请注意,这models['a'] is models['b']是真的。

您可以创建字典,而不是使用

models = dict([(key, []) for key in 'abcd'])
print(models)
print(models['a'] is models['b'])
models['a'].append(3)
print(models)

现在它回来了

{'d': [], 'a': [], 'b': [], 'c': []}
False
{'d': [], 'a': [3], 'b': [], 'c': []}

注意models['a']不是models['b']