Python Pandas - 使用for循环编辑多个数据框

5
考虑以下两个含有三个字典和三个空数据框的列表。
dict0={'actual': {'2013-02-20 13:30:00': 0.93}}
dict1={'actual': {'2013-02-20 13:30:00': 0.85}}
dict2={'actual': {'2013-02-20 13:30:00': 0.98}}
dicts=[dict0, dict1, dict2]

df0=pd.DataFrame()
df1=pd.DataFrame()
df2=pd.DataFrame()
dfs=[df0, df1, df2]

我希望在循环中使用以下代码对3个数据框进行递归修改:

for df, dikt in zip(dfs, dicts):
    df = df.from_dict(dikt, orient='columns', dtype=None)

然而,当尝试在循环外检索df的第1个实例时,它仍然为空。
print (df0)

将返回

Empty DataFrame
Columns: []
Index: []

当在for循环中打印df时,我们可以看到数据被正确地追加了。

如何使循环能够在循环外打印具有更改的3个dfs?

6个回答

5

在您的循环中,df 只是一个临时值,并不是对应列表元素的引用。如果您想在迭代时修改列表,必须按索引引用列表。您可以使用Python的枚举功能来实现:

for i, (df, dikt) in enumerate(zip(dfs, dicts)):
    dfs[i] = df.from_dict(dikt, orient='columns', dtype=None)

3
这将在原地完成!!!请注意3个感叹号。
一行代码。
[dfs[i].set_value(r, c, v)
 for i, dn in enumerate(dicts)
 for r, dr in dn.items()
 for c, v in dr.items()]; 

更直观一些

for d, df in zip(dicts, dfs):
    temp = pd.DataFrame(d).stack()
    for (r, c), v in temp.iteritems():
        df.set_value(r, c, v)

df0

                     actual
2013-02-20 13:30:00    0.93

等价替代
不使用pd.DataFrame构建

for i, dn in enumerate(dicts):
    for r, dr in dn.items():
        for c, v in dr.items():
            dfs[i].set_value(r, c, v)

这个方法有何不同之处?
到目前为止,所有其他答案都会将新的数据帧重新分配到数据帧列表中的必要位置。它们覆盖了已经存在的数据帧。原始数据帧被保留为空白,而一个新的非空数据帧存储在列表中。

此解决方案直接编辑数据帧以确保原始数据帧能够更新新信息。

根据OP:

但是,在循环外尝试检索例如df的1时,它仍然是空的


时间
这也更快

enter image description here


设置

dict0={'actual': {'2013-02-20 13:30:00': 0.93}}
dict1={'actual': {'2013-02-20 13:30:00': 0.85}}
dict2={'actual': {'2013-02-20 13:30:00': 0.98}}
dicts=[dict0, dict1, dict2]

df0=pd.DataFrame()
df1=pd.DataFrame()
df2=pd.DataFrame()
dfs=[df0, df1, df2]

你的三个for循环解决方案不必要地解构了现有的字典。 - user4322543
@fuzzyhedge 不,它不行,我需要获取那些键和值才能使用 set_value。使用 set_valuepd.DataFrame.atpd.DataFrame.loc 是我能想到的唯一选项来原地编辑数据框。为了获取那些行、列、值组合,我必须进行迭代。我本可以使用数据框构造函数来迭代,但这是不必要的。 - piRSquared

1

您需要保留对df对象的引用,因此可以尝试以下操作:

for idx, dikt in enumerate(dicts):
    dfs[idx] = dfs[idx].from_dict(dikt, orient='columns', dtype=None)

0

你也可以将数据框放入字典中来实现这一点:

dfs = {
    'df0': df0,
    'df1': df1,
    'df2': df2
}

然后在for循环中调用并分配字典的内容。

for dfname, dikt in zip(dfs.keys(), dicts):
    dfs[dfname] = dfs[dfname].from_dict(dikt, orient='columns', dtype=None)

如果您仍然想通过它们的名称调用数据框(而不是列表中的任意索引),那么这将非常有用...

dfs['df0']

0

我没有解释为什么会这样。不过有一个解决方法:

dict0={'actual': {'2013-02-20 13:30:00': 0.93}}
dict1={'actual': {'2013-02-20 13:30:00': 0.85}}
dict2={'actual': {'2013-02-20 13:30:00': 0.98}}
dicts=[dict0, dict1, dict2]

dfs = []

for dikt in dicts:
    df = df.from_dict(dikt, orient='columns', dtype=None)
    dfs.append(df)

现在

dfs[0]

返回

                     actual
2013-02-20 13:30:00    0.93

留下这里,但@Blackecho更好。 - bouletta

0

一行代码。

>>>df_list = [df.from_dict(dikt, orient='columns', dtype=None) for (df, dikt) in zip(dfs, dicts)]

>>>df_list
[                     actual
2013-02-20 13:30:00    0.93,
                      actual
2013-02-20 13:30:00    0.85, 
                      actual
2013-02-20 13:30:00    0.98]

>>>df_list[0]
                     actual
2013-02-20 13:30:00    0.93

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接