obtenir l'index d'une ligne dans une fonction d'application pandas

121

J'essaie d'accéder à l'index d'une ligne dans une fonction appliquée sur tout un DataFrame dans Pandas. J'ai quelque chose comme ça:

df = pandas.DataFrame([[1,2,3],[4,5,6]], columns=['a','b','c'])
>>> df
   a  b  c
0  1  2  3
1  4  5  6

et je définirai une fonction qui accède aux éléments avec une ligne donnée

def rowFunc(row):
    return row['a'] + row['b'] * row['c']

Je peux l'appliquer comme ceci:

df['d'] = df.apply(rowFunc, axis=1)
>>> df
   a  b  c   d
0  1  2  3   7
1  4  5  6  34

Impressionnant! Maintenant, que faire si je veux incorporer l'index dans ma fonction? L'index de n'importe quelle ligne donnée dans ceci DataFrameavant l'ajout dseraitIndex([u'a', u'b', u'c', u'd'], dtype='object') , mais je veux le 0 et 1. Donc je ne peux pas simplement accéder row.index.

Je sais que je pourrais créer une colonne temporaire dans la table où je stocke l'index, mais je me demande si elle est stockée quelque part dans l'objet de ligne.

Mike
la source
1
À part: y a-t-il une raison pour laquelle vous devez utiliser apply? C'est beaucoup plus lent que d'effectuer des opérations vectorisées sur l'image elle-même. (Parfois, appliquer est le moyen le plus simple de faire quelque chose, et les considérations de performances sont souvent exagérées, mais pour votre exemple particulier, il est aussi facile de ne pas l'utiliser.)
DSM
1
@DSM en réalité J'appelle un autre constructeur d'objets pour chaque ligne en utilisant différents éléments de ligne. Je voulais juste donner un exemple minimal pour illustrer la question.
Mike

Réponses:

148

Pour accéder à l'index dans ce cas, vous accédez à l' nameattribut:

In [182]:

df = pd.DataFrame([[1,2,3],[4,5,6]], columns=['a','b','c'])
def rowFunc(row):
    return row['a'] + row['b'] * row['c']

def rowIndex(row):
    return row.name
df['d'] = df.apply(rowFunc, axis=1)
df['rowIndex'] = df.apply(rowIndex, axis=1)
df
Out[182]:
   a  b  c   d  rowIndex
0  1  2  3   7         0
1  4  5  6  34         1

Notez que si c'est vraiment ce que vous essayez de faire, ce qui suit fonctionne et est beaucoup plus rapide:

In [198]:

df['d'] = df['a'] + df['b'] * df['c']
df
Out[198]:
   a  b  c   d
0  1  2  3   7
1  4  5  6  34

In [199]:

%timeit df['a'] + df['b'] * df['c']
%timeit df.apply(rowIndex, axis=1)
10000 loops, best of 3: 163 µs per loop
1000 loops, best of 3: 286 µs per loop

ÉDITER

En regardant cette question 3+ ans plus tard, vous pouvez simplement faire:

In[15]:
df['d'],df['rowIndex'] = df['a'] + df['b'] * df['c'], df.index
df

Out[15]: 
   a  b  c   d  rowIndex
0  1  2  3   7         0
1  4  5  6  34         1

mais en supposant que ce ne soit pas aussi simple que cela, quoi que vous rowFuncfassiez vraiment, vous devriez chercher à utiliser les fonctions vectorisées, puis les utiliser contre l'index df:

In[16]:
df['newCol'] = df['a'] + df['b'] + df['c'] + df.index
df

Out[16]: 
   a  b  c   d  rowIndex  newCol
0  1  2  3   7         0       6
1  4  5  6  34         1      16
EdChum
la source
Ce serait bien si nameserait un tuple nommé dans le cas d'un Multindex, de sorte qu'un niveau d'index spécifique puisse être interrogé par son nom.
Konstantin le
18

Soit:

1. à l' row.nameintérieur de l' apply(..., axis=1)appel:

df = pandas.DataFrame([[1,2,3],[4,5,6]], columns=['a','b','c'], index=['x','y'])

   a  b  c
x  1  2  3
y  4  5  6

df.apply(lambda row: row.name, axis=1)

x    x
y    y

2. avec iterrows()(plus lent)

DataFrame.iterrows () vous permet d'itérer sur les lignes et d'accéder à leur index:

for idx, row in df.iterrows():
    ...
smci
la source
2
et, si concerné, 'itertuples' fonctionne généralement bien mieux: stackoverflow.com/questions/24870953/...
dpb
6

Pour répondre à la question d'origine: oui, vous pouvez accéder à la valeur d'index d'une ligne dans apply(). Il est disponible sous la clé nameet nécessite que vous spécifiiezaxis=1 (car le lambda traite les colonnes d'une ligne et non les lignes d'une colonne).

Exemple de travail (pandas 0.23.4):

>>> import pandas as pd
>>> df = pd.DataFrame([[1,2,3],[4,5,6]], columns=['a','b','c'])
>>> df.set_index('a', inplace=True)
>>> df
   b  c
a      
1  2  3
4  5  6
>>> df['index_x10'] = df.apply(lambda row: 10*row.name, axis=1)
>>> df
   b  c  index_x10
a                 
1  2  3         10
4  5  6         40
Freek Wiekmeijer
la source
1
Fonctionne également pour les dataframes avec MultiIndex: row.name devient un tuple.
Charles Fox