2017-08-28 183 views
1

考慮這個簡單的例子動態訪問熊貓數據幀列

import pandas as pd 

df = pd.DataFrame({'one' : [1,2,3], 
        'two' : [1,0,0]}) 

df 
Out[9]: 
    one two 
0 1 1 
1 2 0 
2 3 0 

我想要寫一個函數,它作爲輸入數據幀一個df和列mycol

現在這個工程:

df.groupby('one').two.sum() 
Out[10]: 
one 
1 1 
2 0 
3 0 
Name: two, dtype: int64 

這個工程太:

def okidoki(df,mycol): 
    return df.groupby('one')[mycol].sum() 

okidoki(df, 'two') 
Out[11]: 
one 
1 1 
2 0 
3 0 
Name: two, dtype: int64 

但這失敗

def megabug(df,mycol): 
    return df.groupby('one').mycol.sum() 

megabug(df, 'two') 
AttributeError: 'DataFrameGroupBy' object has no attribute 'mycol' 

這裏有什麼問題?

我擔心okidoki使用一些鏈接可能會產生一些微妙的錯誤(https://pandas.pydata.org/pandas-docs/stable/indexing.html#why-does-assignment-fail-when-using-chained-indexing)。

我該如何保持語法groupby('one').mycolmycol字符串可以轉換爲可能以這種方式工作的東西嗎? 謝謝!

回答

2

你傳遞一個字符串作爲第二個參數。實際上,您正在嘗試執行如下操作:

df.'two' 

這是無效的語法。如果您嘗試動態訪問列,則需要使用索引表示法[...],因爲點/屬性訪問符表示法不適用於動態訪問。


動態訪問是可能的。例如,你可以使用getattr(但我推薦這個,這是一個反模式):

In [674]: df 
Out[674]: 
    one two 
0 1 1 
1 2 0 
2 3 0 

In [675]: getattr(df, 'one') 
Out[675]: 
0 1 
1 2 
2 3 
Name: one, dtype: int64 

通過從GROUPBY呼叫屬性,動態地選擇可以做的,是這樣的:

In [677]: getattr(df.groupby('one'), mycol).sum() 
Out[677]: 
one 
1 1 
2 0 
3 0 
Name: two, dtype: int64 

但是不要做到了。這是一個可怕的反模式,比df.groupby('one')[mycol].sum()更難讀。

+0

感謝coldspeed。我編輯了我的問題。我的觀點是,給定一個字符串作爲輸入,是否有可能將它轉換爲可以使用該語法的東西?說'notastring = magicfunction(mycol)',然後'df.notastring' –

+1

@ℕℴℴḆḽḘ再次編輯我的答案。這是可能的,但它是一個可怕的反模式。不要這樣做。 –

2

我認爲你需要[]通過列名什麼是選擇列通用的解決方案選擇列,因爲按屬性選擇有很多exceptions

  • 只有當索引元素是您可以使用此訪問一個有效的Python標識符,例如s.1是不允許的。請參閱此處以獲取有效標識符的解釋。
  • 如果該屬性與現有方法名稱相沖突,則該屬性將不可用。 s.min是不允許的。
  • 同樣,如果屬性與以下任何列表衝突,該屬性將不可用:index,major_axis,minor_axis,items,labels。
  • 在任何這些情況下,標準索引仍然有效,例如, s ['1'],s ['min']和s ['index']將訪問相應的元素或列。
def megabug(df,mycol): 
    return df.groupby('one')[mycol].sum() 

print (megabug(df, 'two')) 

one 
1 1 
2 0 
3 0 
Name: two, dtype: int64 
+0

是jezrael,這實際上是okidoki函數:D。我的問題是爲什麼是這種情況? –