2017-08-28 11 views
1

Tenir compte cet exemple simpleaccéder à une colonne de Dynamiquement dataframe de pandas géants

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 

Je veux écrire une fonction qui prend en entrée une trame de données df et une colonne mycol.

Maintenant, cela fonctionne:

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

cela fonctionne aussi:

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 

mais PANNE

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

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

Quel est le problème ici?

Je suis inquiet que okidoki utilise une enchaînant qui pourraient créer quelques bugs subtils (https://pandas.pydata.org/pandas-docs/stable/indexing.html#why-does-assignment-fail-when-using-chained-indexing).

Comment puis-je toujours garder la syntaxe groupby('one').mycol? La chaîne mycol peut-elle être convertie en quelque chose qui pourrait fonctionner de cette façon? Merci!

Répondre

2

Vous passez une chaîne comme second argument. En effet, vous essayez de faire quelque chose comme:

df.'two' 

Ce qui est une syntaxe invalide. Si vous essayez d'accéder dynamiquement à une colonne, vous devez utiliser la notation d'index, [...] car la notation d'accesseur de point/attribut ne fonctionne pas pour l'accès dynamique.


accès dynamique lui-même est possible.Par exemple, vous pouvez utiliser getattr (mais je ne recommande pas cela, il est un antimodèle):

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 

sélection Dynamiquement par attribut d'un appel groupby peut être fait, quelque chose comme:

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

Mais ne le font pas le faire. C'est un anti-pattern horrible, et beaucoup plus illisible que df.groupby('one')[mycol].sum().

+0

merci coldspeed. J'ai édité ma question. Mon point est, étant donné une chaîne comme une entrée, est-il possible de le convertir en quelque chose qui fonctionnera avec cette syntaxe? dire 'notastring = magicfunction (mycol)' et ensuite 'df.notastring' –

+1

@ ℕℴℴḆḽḘ Edité ma réponse à nouveau. C'est possible mais c'est un anti-pattern horrible. Ne fais pas ça. –

2

Je pense que vous avez besoin [] pour la colonne Sélection par nom de colonne quelle est la solution générale pour sélectionner des colonnes, car sélectionnez par attributs ont beaucoup exceptions:

  • Vous pouvez utiliser cet accès que si l'élément d'index est un identifiant Python valide, par exemple s.1 n'est pas autorisé. Voir ici pour une explication des identifiants valides.
  • L'attribut ne sera pas disponible s'il est en conflit avec un nom de méthode existant, par ex. s.min n'est pas autorisé.
  • De même, l'attribut ne sera pas disponible s'il est en conflit avec l'une des listes suivantes: index, major_axis, minor_axis, items, labels.
  • Dans tous ces cas, l'indexation standard fonctionnera toujours, par ex. s ['1'], s ['min'] et s ['index'] accéderont à l'élément ou à la colonne correspondante.
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

oui jezrael, c'est la fonction okidoki ci-dessus en fait: D. Ma question est pourquoi est-ce le cas? –