2017-02-21 83 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