Accediendo dinámicamente a una columna de dataframe pandas

Considera este ejemplo simple

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 

Quiero escribir una función que tome como entradas un df marcos de datos y una columna mycol .

Ahora esto funciona:

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

esto funciona también:

  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 

pero esto falla

 def megabug(df,mycol): return df.groupby('one').mycol.sum() megabug(df, 'two') AttributeError: 'DataFrameGroupBy' object has no attribute 'mycol' 

¿Que esta mal aquí?

Me preocupa que okidoki use algún encadenamiento que pueda crear algunos errores sutiles ( https://pandas.pydata.org/pandas-docs/stable/indexing.html#why-does-assignment-fail-when-using-chained-indexing ).

¿Cómo puedo seguir manteniendo la syntax groupby('one').mycol ? ¿ mycol puede convertir la cadena de mycol en algo que pueda funcionar de esa manera? ¡Gracias!

Pasas una cadena como segundo argumento. En efecto, estás tratando de hacer algo como:

 df.'two' 

Que es una syntax no válida. Si está intentando acceder dinámicamente a una columna, deberá usar la notación de índice, porque la [...] notación de acceso de punto / atributo no funciona para el acceso dynamic.


El acceso dynamic por sí mismo es posible. Por ejemplo, puede usar getattr (pero no lo recomiendo, es un antipattern):

 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 

La selección dinámica por atributo de una llamada grupal se puede hacer, algo así como:

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

Pero no lo hagas. Es un anti patrón horrible, y mucho más ilegible que df.groupby('one')[mycol].sum() .

Creo que necesita [] para seleccionar columna por nombre de columna, lo que es una solución general para seleccionar columnas, porque seleccionar por atributos tiene muchas excepciones :

  • Puede usar este acceso solo si el elemento de índice es un identificador válido de python, por ejemplo, no se permite el s1. Vea aquí para una explicación de identificadores válidos.
  • El atributo no estará disponible si entra en conflicto con un nombre de método existente, por ejemplo, min no está permitido.
  • De forma similar, el atributo no estará disponible si entra en conflicto con cualquiera de las siguientes listas: índice, eje principal, eje menor, elementos, tags.
  • En cualquiera de estos casos, la indexación estándar seguirá funcionando, por ejemplo, s [‘1’], s [‘min’] y s [‘index’] accederán al elemento o columna correspondiente.
 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