obter o índice de uma linha em uma função de aplicação do pandas

121

Estou tentando acessar o índice de uma linha em uma função aplicada em todo o DataFramePandas. Eu tenho algo assim:

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

e vou definir uma função que acessa elementos com uma determinada linha

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

Posso aplicá-lo assim:

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

Impressionante! Agora, e se eu quiser incorporar o índice à minha função? O índice de qualquer linha dada DataFrameantes de adicionar dseria Index([u'a', u'b', u'c', u'd'], dtype='object'), mas eu quero 0 e 1. Portanto, não posso simplesmente acessar row.index.

Eu sei que poderia criar uma coluna temporária na tabela onde armazeno o índice, mas estou me perguntando se ela está armazenada no objeto de linha em algum lugar.

Mike
fonte
1
À parte: há um motivo para você usar apply? É muito mais lento do que realizar operações vetorizadas no próprio quadro. (Às vezes, aplicar é a maneira mais simples de fazer algo, e as considerações de desempenho costumam ser exageradas, mas para o seu exemplo específico é tão fácil de não usar.)
DSM
1
@DSM, na verdade, estou chamando outro construtor de objetos para cada linha usando diferentes elementos de linha. Eu só queria reunir um exemplo mínimo para ilustrar a questão.
Mike

Respostas:

148

Para acessar o índice, neste caso, você acessa o 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

Observe que, se isso é realmente o que você está tentando fazer, o seguinte funciona e é muito mais 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

Olhando para esta questão mais de 3 anos depois, você poderia apenas fazer:

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

mas assumindo que não seja tão trivial quanto isso, o que quer que você rowFuncesteja realmente fazendo, você deve procurar usar as funções vetorizadas e, em seguida, usá-las contra o í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
fonte
Seria bom se namefosse uma tupla nomeada no caso de a Multindex, de modo que um nível de índice específico pudesse ser consultado por seu nome.
Konstantin
18

Ou:

1. com row.namedentro da apply(..., axis=1)chamada:

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. com iterrows()(mais lento)

DataFrame.iterrows () permite que você itere nas linhas e acesse seu índice:

for idx, row in df.iterrows():
    ...
smci
fonte
2
e, se preocupado, 'itertuples' geralmente tem um desempenho muito melhor: stackoverflow.com/questions/24870953/…
dpb
6

Para responder à pergunta original: sim, você pode acessar o valor do índice de uma linha em apply(). Ele está disponível na chave namee requer que você especifique axis=1(porque o lambda processa as colunas de uma linha e não as linhas de uma coluna).

Exemplo de trabalho (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
fonte
1
Também funciona para dataframes com MultiIndex: row.name torna-se uma tupla.
Charles Fox