【问题标题】:Dynamically accessing a pandas dataframe column动态访问 pandas 数据框列
【发布时间】:2018-02-05 20:59:29
【问题描述】:

考虑这个简单的例子

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').mycol 的语法?可以将mycol 字符串转换为可能以这种方式工作的东西吗? 谢谢!

【问题讨论】:

    标签: python pandas dataframe dynamic accessor


    【解决方案1】:

    我认为您需要[] 来按列名选择列什么是选择列的一般解决方案,因为按属性选择有很多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
    

    【讨论】:

    • 是的,jezrael,这实际上是上面的 okidoki 函数:D。我的问题是为什么会这样?
    【解决方案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() 更难读。

    【讨论】:

    • 感谢冷速。我已经编辑了我的问题。我的观点是,给定一个字符串作为输入,是否可以将其转换为可以使用这种语法的东西?说notastring = magicfunction(mycol) 然后df.notastring
    • @ℕℴℴḆḽḘ 再次编辑我的答案。这是可能的,但这是一种可怕的反模式。不要这样做。
    猜你喜欢
    • 1970-01-01
    • 2021-09-14
    • 2019-06-25
    • 1970-01-01
    • 2021-07-08
    • 2016-08-16
    • 2021-09-13
    • 1970-01-01
    • 2017-01-21
    相关资源
    最近更新 更多