obtener el índice de una fila en una función de aplicación de pandas

121

Estoy tratando de acceder al índice de una fila en una función aplicada en todo un DataFramePandas. Tengo algo como esto:

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

y definiré una función que acceda a elementos con una fila determinada

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

Puedo aplicarlo así:

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

¡Increíble! Ahora, ¿qué pasa si quiero incorporar el índice en mi función? El índice de cualquier fila dada en esto DataFrameantes de agregar dsería Index([u'a', u'b', u'c', u'd'], dtype='object'), pero quiero el 0 y el 1. Así que no puedo acceder row.index.

Sé que podría crear una columna temporal en la tabla donde almaceno el índice, pero me pregunto si está almacenado en el objeto de fila en algún lugar.

Miguel
fuente
1
Aparte: ¿hay alguna razón por la que debas usar apply? Es mucho más lento que realizar operaciones vectorizadas en el propio marco. (A veces, aplicar es la forma más sencilla de hacer algo, y las consideraciones de rendimiento a menudo se exageran, pero para su ejemplo particular es tan fácil no usarlo)
DSM
1
@DSM en realidad estoy llamando a otro constructor de objetos para cada fila usando diferentes elementos de fila. Solo quería poner un ejemplo mínimo para ilustrar la pregunta.
Mike

Respuestas:

148

Para acceder al índice en este caso accedes al nameatributo:

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

Tenga en cuenta que si esto es realmente lo que está tratando de hacer, lo siguiente funciona y es mucho más rápido:

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

EDITAR

Si mira esta pregunta más de 3 años después, podría hacer lo siguiente:

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

pero asumiendo que no es tan trivial como esto, sea lo que sea lo que rowFuncesté haciendo realmente, debería buscar usar las funciones vectorizadas y luego usarlas contra el índice 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
fuente
Sería bueno si namefuera una tupla con nombre en el caso de a Multindex, de modo que se pueda consultar un nivel de índice específico por su nombre.
Konstantin
18

Ya sea:

1. row.namedentro de la apply(..., axis=1)llamada:

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. con iterrows()(más lento)

DataFrame.iterrows () le permite iterar sobre filas y acceder a su índice:

for idx, row in df.iterrows():
    ...
smci
fuente
2
y, si le preocupa, 'itertuples' generalmente funciona mucho mejor: stackoverflow.com/questions/24870953/…
dpb
6

Para responder a la pregunta original: sí, puede acceder al valor de índice de una fila en apply(). Está disponible bajo la clave namey requiere que usted especifique axis=1(porque la lambda procesa las columnas de una fila y no las filas de una columna).

Ejemplo de trabajo (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
fuente
1
También funciona para marcos de datos con MultiIndex: row.name se convierte en una tupla.
Charles Fox