我有一个我要分组的pandas数据框,然后使用iterrows
和set_value
更新原始数据框。这似乎不起作用。
这是一个例子。
In [1]: def func(df, n):
...: for i, row in df.iterrows():
...: print("Updating {0} with value {1}".format(i, n))
...: df.set_value(i, 'B', n)
In [2]: df = pd.DataFrame({"A": [1, 2], "B": [0, 0]})
In [3]: df
Out[4]:
A B
0 1 0
1 2 0
In [125]: func(df, 1)
Updating 0 with value 1
Updating 1 with value 1
In [126]: df
Out[126]:
A B
0 1 1
1 2 1
In [127]: df.groupby('A').apply(lambda df: func(df, 2))
Updating 0 with value 2
Updating 0 with value 2
Updating 1 with value 2
In [126]: df
Out[126]:
A B
0 1 1
1 2 1
我希望B
更新为2
。
为什么这不起作用,实现这一结果的最佳方法是什么?
答案 0 :(得分:1)
编写内容的方式,您似乎希望函数func(df, n)
能够修改df
。但是df.groupby('A')
(在某种意义上)创建了另一组数据帧(每组一个),因此使用func()
作为df.groupby('A').apply()
的参数只修改这些新创建的数据帧而不是原始数据帧df
。此外,返回的数据帧是以每个组作为参数调用的func()
输出的串联,这就是返回的数据帧为空的原因。
问题的最短时间解决方法是在return df
结束时func
:
def func(df, n):
for i, row in df.iterrows():
print("Updating {0} with value {1}".format(i, n))
df.set_value(i, 'B', n)
return df
df = df.groupby('A').apply(lambda df: func(df, 2))
我认为这并不是你想到的,因为你可能期望修改一切。如果您想要修改所有内容,则需要使用for
循环和.loc
的组合,但如果您打算使用.loc
修改数据框,则计算成本会很高多次致电.loc
。
我还猜测你设置值的功能取决于更复杂的标准,但通常你可以对事物进行矢量化,避免必须完全使用.iterrows()
。
为避免出现XY问题,我建议您更详细地描述您的功能,因为您可以通过使用.loc
并避免迭代的几行来完成所有工作。通过Python中的每一行。例证:df['B'] = 2
(没有print
声明)是解决问题的单线解决方案。
答案 1 :(得分:0)
这不起作用,因为您正在更改由df
对象的groupby
方法传递的get_group
复制的子集。你正在改变一些事情,而不是你所期待的。
如果这还不够理由,你会注意到你有3个打印声明。那是因为pandas运行第一组一次来测试和推断输出。然后再次实际做的事情。如果您更改了范围之外的内容,最终可能会产生意想不到的后果。
其他人可以提供更好的例子来说明如何做到这一点。我只想解释它为什么不起作用。
答案 2 :(得分:0)
在某些情况下,如果func()
根据索引执行操作,则可以直接修改原始数据框。
代替此:
def func(group, n):
for i, row in group.iterrows():
print("Updating {0} with value {1}".format(i, n))
group.set_value(i, 'B', n)
return group
df.groupby('A').apply(lambda group: func(group, 2))
您可以这样做:
for key, group in df.groupby('A'):
n = 2
for i, row in group.iterrows():
print("Updating {0} with value {1}".format(i, n))
df.set_value(i, 'B', n)