2016-02-18 50 views
2

我有一個數據框,我初始化了一個本地方法的範圍。我想做如下:如果爲空,則附加到DataFrame時出現問題

def outer_method(): 
    ... do outer scope stuff here 
    df = pd.DataFrame(columns=['A','B','C','D']) 
    def recursive_method(arg): 
     ... do local stuff here 
     # func returns a data frame to be appended to empty data frame 
     results_df = func(args) 
     df.append(results_df, ignore_index=True) 
     return results 
recursive_method(arg) 
return df 

但是,這是行不通的。如果我這樣追加它,df總是空的。

我在這裏找到了我的問題的答案:appending-to-an-empty-data-frame-in-pandas ...這工作,如果空的DataFrame對象在方法的範圍內,但不適合我的情況。按@ DSM的評論「但追加不就地發生,所以你必須要存儲輸出,如果你想的那樣:」

IOW,我需要有類似:

df = df.append(results_df, ignore_index=True) 

在我的本地方法,但這並不能幫助我訪問我的外部作用域變量df附加到它。

有沒有辦法讓這種情況發生?這適用於擴展列表對象的內容的Python extend方法(我意識到DataFrames不是列表,但是...)。有沒有類似的方式來做到這一點與DataFrame對象,而不必處理我的範圍問題df

順便說一下,熊貓concat方法也適用,但我遇到了變量範圍的問題。

+0

對不起,你說'df = df.append(df_join_out,ignore_index = True)'不起作用? – EdChum

+0

右側的'df'然後作爲未解決的參考給出。 –

回答

3

在Python3,您可以使用外地關鍵字

def outer_method(): 
    ... do outer scope stuff here 
    df = pd.DataFrame(columns=['A','B','C','D']) 
    def recursive_method(arg): 
     nonlocal df 
     ... do local stuff here 
     # func returns a data frame to be appended to empty data frame 
     results_df = func(args) 
     df = df.append(results_df, ignore_index=True) 
     return results 

return df 

但要注意,調用df.append返回一個新的數據幀每次,因此需要複製所有舊的數據到新的數據幀。如果你在一個循環內進行N次,你最終會得到1 + 2 + 3 + ... + N = O(N^2)副本 - 對性能非常不利。


如果您不需要dfrecursive_method比 追加其他任何目的,這是更好地附加到一個列表,然後構建 數據框(通過調用pd.concat一次recursive_method完成後:

df = pd.DataFrame(columns=['A','B','C','D']) 
data = [df] 
def recursive_method(arg, data): 
    ... do stuff here 
    # func returns a data frame to be appended to empty data frame 
    results_df = func(args) 
    data.append(df_join_out) 
    return results 
recursive_method(arg, data) 
df = pd.concat(data, ignore_index=True) 

這是最好的解決辦法如果你需要做的就是收集數據內 recursive_method並且可以在 recursive_method完成後等待構建新的df


在Python2,如果必須使用dfrecursive_method,那麼你可以df作爲參數傳遞給recursive_method,並返回df

df = pd.DataFrame(columns=['A','B','C','D']) 
def recursive_method(arg, df): 
    ... do stuff here 
    results, df = recursive_method(arg, df) 
    # func returns a data frame to be appended to empty data frame 
    results_df = func(args) 
    df = df.append(results_df, ignore_index=True) 
    return results, df 
results, df = recursive_method(arg, df) 

但要注意,你會付出沉重的代價,進行上述O(N^2)複製 。


爲什麼DataFrames 不能 不應被附加到就地

在一個數據幀中的相關數據被存儲在NumPy的陣列。 NumPy數組中的數據來自連續的內存塊。有時候,即使內存可用,也沒有足夠的空間將NumPy陣列調整爲較大的連續內存塊 - 想象一下陣列夾在 之間的其他數據結構。在這種情況下,爲了調整陣列大小,必須在其他地方分配新的更大的內存塊,並且必須將來自 原始陣列的所有數據複製到新塊。一般來說, 不能在原地完成。

DataFrames確實有私有方法,_update_inplace,可能是 用於將DataFrame的基礎數據重定向到新數據。這只是一個 僞操作,因爲新數據(認爲NumPy數組)必須首先分配爲 (所有伴隨複製)。所以使用_update_inplace對它的兩次打擊:它使用私有方法(在理論上)在將來版本的熊貓中可能不會有 ,並且會導致O(N^2)拷貝懲罰。

In [231]: df = pd.DataFrame([[0,1,2]]) 

In [232]: df 
Out[232]: 
    0 1 2 
0 0 1 2 

In [233]: df._update_inplace(df.append([[3,4,5]])) 

In [234]: df 
Out[234]: 
    0 1 2 
0 0 1 2 
0 3 4 5 
+0

感謝您的解釋。這說得通。我肯定不希望將'df'作爲參數傳遞給我的遞歸方法(或者使用** nonlocal關鍵字**)。另外,我** HAD **一直在使用一個列表,但我在列表和數據框之間來回切換,這在性能上代價很高,因爲我使用數據框來進行集合操作,所以我想我會繞過去在這兩種對象類型之間來回切換,直到結束,當我通過JSON返回最終結果時。但是,我認爲你使用'concat'列表的建議是一個很好的折衷方案。 –