2017-08-28 131 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。我的问题是为什么是这种情况? –