2012-06-23 4 views
9

Semblable à this R question, je voudrais appliquer une fonction à chaque élément d'une série (ou chaque ligne d'un DataFrame) en utilisant Pandas, mais je veux utiliser comme argument de cette fonction l'index ou l'id de cette rangée. Comme un exemple trivial, supposons que l'on veuille créer une liste de tuples de la forme [(index_i, valeur_i), ..., (index_n, valeur_n)]. L'utilisation d'un simple Python pour la boucle, je peux le faire: pandas row specific apply

In [1] L = [] 
In [2] s = Series(['six', 'seven', 'six', 'seven', 'six'], 
      index=['a', 'b', 'c', 'd', 'e']) 
In [3] for i, item in enumerate(s): 
      L.append((i,item)) 
In [4] L 
Out[4] [(0, 'six'), (1, 'seven'), (2, 'six'), (3, 'seven'), (4, 'six')] 

Mais il doit y avoir un moyen plus efficace de le faire? Peut-être quelque chose de plus Panda-ish comme Series.apply? En réalité, je ne m'inquiète pas (dans ce cas) de rendre quelque chose de significatif, mais plutôt d'améliorer quelque chose comme "appliquer". Des idées?

Répondre

7

Si vous utilisez la méthode apply avec une fonction, chaque élément de la série sera mappé avec une telle fonction. Par exemple.

>>> s.apply(enumerate) 
a <enumerate object at 0x13cf910> 
b <enumerate object at 0x13cf870> 
c <enumerate object at 0x13cf820> 
d <enumerate object at 0x13cf7d0> 
e <enumerate object at 0x13ecdc0> 

Ce que vous voulez faire est simplement d'énumérer la série elle-même.

>>> list(enumerate(s)) 
[(0, 'six'), (1, 'seven'), (2, 'six'), (3, 'seven'), (4, 'six')] 

Et si par exemple vous vouliez additionner la chaîne de toutes les entités?

>>> ",".join(s) 
'six,seven,six,seven,six' 

Une utilisation plus complexe d'appliquer serait celui-ci:

>>> from functools import partial 
>>> s.apply(partial(map, lambda x: x*2)) 
a    ['ss', 'ii', 'xx'] 
b ['ss', 'ee', 'vv', 'ee', 'nn'] 
c    ['ss', 'ii', 'xx'] 
d ['ss', 'ee', 'vv', 'ee', 'nn'] 
e    ['ss', 'ii', 'xx'] 

[Modifier]

Suite à la question des éclaircissements de l'OP: Ne confondez pas la série (1D) avec DataFrames (2D) http://pandas.pydata.org/pandas-docs/stable/dsintro.html#dataframe - car je ne vois pas vraiment comment vous pouvez parler de lignes. Cependant, vous pouvez inclure des indices dans votre fonction en créant une nouvelle série (appliquer vous donnera pas d'informations sur l'indice actuel):

>>> Series([s[x]+" my index is: "+x for x in s.keys()], index=s.keys()) 
a  six index a 
b seven index b 
c  six index c 
d seven index d 
e  six index e 

Quoiqu'il en soit, je vous suggère de passer à d'autres types de données pour éviter les fuites de mémoire énormes.

+0

Merci @ luke14free pour le pointeur sur l'énumération. En fin de compte, j'ai probablement fourni un exemple trop simpliste, mais vous avez en effet fourni une réponse appropriée. Ce que je veux vraiment, c'est quelque chose comme votre troisième exemple, avec la condition supplémentaire que disons, l'exposant est une fonction de la ligne ou de l'index ... –

+0

Hey @CarsonFarmer - voir mon dernier edit – luke14free

+0

Merci @ luke14free. En fin de compte, j'ai fait comme vous l'avez suggéré, et j'ai résolu mon problème d'une manière différente en restructurant mes données. –

3

Voici une belle façon, en utilisant pour itertools count et zip:

import pandas as pd 
from itertools import count 

s = pd.Series(['six', 'seven', 'six', 'seven', 'six'], 
        index=['a', 'b', 'c', 'd', 'e']) 

In [4]: zip(count(), s) 
Out[4]: [(0, 'six'), (1, 'seven'), (2, 'six'), (3, 'seven'), (4, 'six')] 

Malheureusement, seulement aussi efficace que enumerate(list(s))!