2017-02-21 60 views
0

我的情景是,一个函数应该能够修改pandas.DataFrame中的值。但我不想将整个DataFrame暴露给函数,只是需要修改的部分。这种透明度的一个原因是,该功能将更具有通用性,能够指定从外部修改DataFrame的哪一部分。成像我可以编写一个函数mult(df_view, a),将视图中的所有值乘以a。请注意,我不希望创建新的DataFrame。价值变化应该是就地Python Pandas:如何将DataFrames的“视图”传递给函数?

这是我的尝试:

df = pd.DataFrame([[1,1],[1,1]]) 

def mult(df_view, a): 
    df_view *= a 

mult(df.loc[1,1], 2) 

print(df) 

这是(不需要)输出:

0 1 
0 1 1 
1 1 1 

预期输出是:

0 1 
0 1 1 
1 1 2 

注意到,如果我们做的分配直接(即没有功能),它的工作原理:

df = pd.DataFrame([[1,1],[1,1]]) 

df.loc[1,1] *= 2 

print(df) 

...给:

0 1 
0 1 1 
1 1 2 

因此,通过该视图通过函数调用时,显然我搞乱了的东西。我读过这个blog post from Jeff Knupp,我想我明白python的名称 - 对象绑定是如何工作的。我对DataFrames的理解是,当我呼叫df.loc[1,1]时,它会生成一个代理对象,该对象指向原始DataFrame w/[1,1]窗口,以便进一步的操作(例如分配)只转到窗口内的元素。现在,当我通过函数调用传递df.loc[1,1]时,该函数将名称df_view绑定到代理对象。因此,在我的理论中,任何变化(即df_view *= a)都应该应用于视图,并因此应用于原始DataFrame中的元素。从结果中,很明显这没有发生,看起来DataFrame在进程中被复制(我不确定在哪里),因为一些值在原始DataFrame之外被更改了。

回答

0

只是检查

>>> type(df.loc[1, 1]) 
numpy.int64 

所以很显然,这是行不通的 - 你正在传递一个不变的int,它没有绑定到外部数据帧。

如果你用简单的索引(可变构造)传递实际视图,那么很可能是的工作。

>>> mult(df.loc[:, 1], 2) 
>>> df 
    0 1 
0 1 2 
1 1 2 

但是其他一些操作不起作用。

>>> mult(df.loc[:, :1], 2) 
>>> df 
    0 1 
0 1 2 
1 1 2 

总而言之,我认为这个控制流程是一个坏主意 - 一个更好的选择是因为你的作品表现出对指数直接操作。如果可能的话坚持不变,大熊猫往往更友好(恕我直言)。

+0

是'numpy.int64'并不意味着在数据帧中值的数据不能被分配至。实际上它在'df.loc [1,1] * = 2'的情况下。正如你所指出的那样,何时/为什么传递一个“视图”到'mult()'函数的逻辑会有点不清楚。这不是一个明确的答案(尽管你指出了一些成功的和失败的案例有帮助)。 – Roy

+0

@Roy Python通过赋值传递,当你直接使用'df.loc [1,1] * = 2'时,你仍然分配给DataFrame的_element_,而不是传递给函数的实际值。 [这是一个很好的阅读](http://nedbatchelder.com/text/names.html)。 – miradulo

0

这个问题在某些情况下有时候会产生difficult to detect的数据副本。

您可以在功能得到全面的难度由索引:

def mult(df,i,j,a): 
    df.loc[i,j]*=a 

mult(df,1,1,2) 
mult(df,1,slice(0,2),6) 
print(df) 

0 1 
0 1 1 
1 6 12 
+0

尽管您的建议应该可行,但正是我的问题试图避免(即将视图坐标传递到函数并且函数仅访问DataFrame的指定部分)的协议。因此我不能将这个标记为答案。 – Roy