2017-08-06 59 views
1

假設我有一個數據集象下面這樣: enter image description here爲什麼熊貓允許編輯DataFrames而不是一系列對象

當我試圖覆蓋一個特定的列(Series對象),我得到了下面的代碼錯誤:

mask = bond["Actor"] == "Sean Connery" 
bond[mask]["Actor"] = "Sir Sean Connery" 

但我移動向下一個級別,而是編輯這些行的所有列(完整的數據幀)的那一刻,我成功

mask = bond["Actor"] == "Sean Connery" 
bond[mask] = "Sir Sean Connery" 

這是爲什麼?在第一種情況下,我認爲編輯一個副本和錯誤是不合邏輯的。但是在後一種情況下也應該適用,因爲第二個示例也應該返回原始DataFrame的副本。

+0

在第一個示例中,您鏈接了索引。 'bond [mask]'是DataFrame的一個拷貝,然後你用Actor列進一步索引它。在第二個'mask'只是一個布爾數組。你沒有修改蒙版。 – ayhan

+0

'bond [mask] [「Actor」] =「Sean Connery爵士」和「bond [mask] =」Sean Connery爵士「之間的區別在於,在第一個中,您調用副本的__getitem__然後'__setitem__',但在第二個中只使用'__setitem__',這使得它在視圖上運行。 – ayhan

+0

@ayhan:對不起,還不清楚。爲什麼這兩個案件都有不同的行爲。我期望他們都返回原始DataFrame(行或列)的引用。出於某種原因,顯然第一個返回一個副本,而不是原件。這是什麼原因?其次,根據我對這個鏈接http://pandas.pydata.org/pandas-docs/stable/indexing.html#returning-a-view-versus-a-copy的理解,在答案中共享,'__getitem__'將會在第一種情況下稱爲兩次,而在第二種情況下只調用一次。 –

回答

0

有你需要loc爲避免chained indexing問題:

bond = pd.DataFrame({'Actor':list('abcaef'), 
        'A':list('efghij'), 
        'B':list('aaabbb')}) 

print (bond) 
    A Actor B 
0 e  a a 
1 f  b a 
2 g  c a 
3 h  a b 
4 i  e b 
5 j  f b 

mask = bond["Actor"] == "a" 
bond.loc[mask] = "AAA" 
#for select all columns :, for columns can be omitted 
#bond.loc[mask,:] = "AAA" 

print (bond) 
    A Actor B 
0 AAA AAA AAA 
1 f  b a 
2 g  c a 
3 AAA AAA AAA 
4 i  e b 
5 j  f b 

#one column Actor 
bond.loc[mask, "Actor"] = "AAA" 
print (bond) 
    A Actor B 
0 e AAA a 
1 f  b a 
2 g  c a 
3 h AAA b 
4 i  e b 
5 j  f b 
+1

謝謝。那個頁面幫了我很多。 –

+0

很高興能提供幫助。你認爲接受沒有必要嗎?或者有什麼不對? – jezrael

0

考慮以下單列數據框:

df = pd.DataFrame({'Actor': ['Sean Connery', 'Sean Connery', 
          'Sean Something', 'Sean Something Else']}) 

df 
Out: 
       Actor 
0   Sean Connery 
1   Sean Connery 
2  Sean Something 
3 Sean Something Else 

這是您要的面具用於切片:

現在
mask = df['Actor'] == 'Sean Connery' 

,如果我用df[mask]['Actor'] = 'Sir Sean Connery',這將是執行:

df.__getitem__(mask).__setitem__('Actor', 'Sir Sean Connery') 
__main__:1: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame. 
Try using .loc[row_indexer,col_indexer] = value instead 

見警告文檔中:http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

而且對於這種情況也不會修改原來的DataFrame:

df 
Out: 
       Actor 
0   Sean Connery 
1   Sean Connery 
2  Sean Something 
3 Sean Something Else 

Id did雖然修改了一個DataFrame - 這是由__getitem__方法返回的,但由於它沒有分配給任何東西,所以丟失了。

相反,在你的第二個例子(df[mask] = 'Sir Sean Connery')執行的代碼是:

df.__setitem__(mask, 'Sir Sean Connery') 

由於面膜的你可能認爲它使用__getitem__太多,但事實並非如此。它直接使用__setitem__並將掩碼傳遞給該DataFrame。大熊貓可以確保我們可以確信它將在一個視圖上運行。對於__getitem__的情況來說,它可以是複製或者它可以是一個視圖 - 很難知道。現在

你會看到,原來的DF修改:

df 
Out: 
       Actor 
0  Sir Sean Connery 
1  Sir Sean Connery 
2  Sean Something 
3 Sean Something Else 

這裏有一個陷阱,但。它的工作原因是我們只有一列。如果我們有另一欄,說'年',它會將相應的年份值設置爲'Sir Sean Connery'。爲了避免這一點,我們使用.loc jezrael指出。它還調用__setitem__方法並允許指定哪些列將會更改。

df = pd.DataFrame({'Actor': ['Sean Connery', 'Sean Connery', 
          'Sean Something', 'Sean Something Else'], 
        'Year': [1990, 1990, 1990, 1990]}) 


df.loc.__setitem__((mask, 'Actor'), 'Sir Sean Connery') 

df 
Out: 
       Actor Year 
0  Sir Sean Connery 1990 
1  Sir Sean Connery 1990 
2  Sean Something 1990 
3 Sean Something Else 1990 

結果,最佳實踐是基於集合的口罩和欄姓名(或名稱)是使用.loc

df.loc[mask, 'Actor'] = 'Sir Sean Connery' 

這樣你就不必如果您在操作擔心在副本上。