Abrufen des Index einer Zeile in einer Pandas-Apply-Funktion

121

Ich versuche, auf den Index einer Zeile in einer Funktion zuzugreifen, die DataFramein Pandas auf eine gesamte Funktion angewendet wird . Ich habe so etwas:

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

und ich werde eine Funktion definieren, die auf Elemente mit einer bestimmten Zeile zugreift

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

Ich kann es so anwenden:

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

Genial! Was ist nun, wenn ich den Index in meine Funktion integrieren möchte? Der Index einer bestimmten Zeile in dieser Zeile DataFramevor dem Hinzufügen dwäre Index([u'a', u'b', u'c', u'd'], dtype='object'), aber ich möchte die 0 und 1. Ich kann also nicht einfach darauf zugreifen row.index.

Ich weiß, dass ich eine temporäre Spalte in der Tabelle erstellen könnte, in der ich den Index speichere, aber ich frage mich, ob er irgendwo im Zeilenobjekt gespeichert ist.

Mike
quelle
1
Nebenbei: Gibt es einen Grund, den Sie verwenden müssen apply? Es ist viel langsamer als vektorisierte Operationen am Frame selbst durchzuführen. (Manchmal gelten ist die einfachste Möglichkeit , etwas zu tun, und Leistungsinformationen werden oft übertrieben, aber für Ihr spezielles Beispiel ist es so einfach nicht , es zu benutzen.)
DSM
1
@DSM in Wirklichkeit rufe ich für jede Zeile einen anderen Objektkonstruktor mit unterschiedlichen Zeilenelementen auf. Ich wollte nur ein minimales Beispiel zusammenstellen, um die Frage zu veranschaulichen.
Mike

Antworten:

148

Um in diesem Fall auf den Index zuzugreifen, greifen Sie auf das nameAttribut zu:

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

Beachten Sie, dass, wenn dies wirklich das ist, was Sie versuchen, Folgendes funktioniert und viel schneller ist:

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

BEARBEITEN

Wenn Sie sich diese Frage mehr als 3 Jahre später ansehen, können Sie einfach Folgendes tun:

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

Aber vorausgesetzt, es ist nicht so trivial wie das, was auch immer Sie rowFuncwirklich tun, sollten Sie versuchen, die vektorisierten Funktionen zu verwenden und sie dann gegen den df-Index zu verwenden:

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
quelle
Wäre schön, wenn nameim Falle eines ein benanntes Tupel wäre Multindex, damit eine bestimmte Indexebene anhand ihres Namens abgefragt werden könnte.
Konstantin
18

Entweder:

1. mit row.nameinnerhalb des apply(..., axis=1)Anrufs:

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. mit iterrows()(langsamer)

Mit DataFrame.iterrows () können Sie Zeilen durchlaufen und auf deren Index zugreifen:

for idx, row in df.iterrows():
    ...
smci
quelle
2
und wenn es darum geht, ist die Leistung von "itertuples" im Allgemeinen weitaus besser: stackoverflow.com/questions/24870953/…
dpb
6

Um die ursprüngliche Frage zu beantworten: Ja, Sie können auf den Indexwert einer Zeile in zugreifen apply(). Es ist unter dem Schlüssel verfügbar nameund muss von Ihnen angegeben werden axis=1(da das Lambda die Spalten einer Zeile und nicht die Zeilen einer Spalte verarbeitet).

Arbeitsbeispiel (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
quelle
1
Funktioniert auch für Datenrahmen mit MultiIndex: row.name wird zu einem Tupel.
Charles Fox