получение индекса строки в функции применения панд

121

Я пытаюсь получить доступ к индексу строки в функции, применяемой ко всему DataFrameв Pandas. У меня примерно так:

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

и я определю функцию, которая обращается к элементам с заданной строкой

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

Я могу применить это так:

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

Потрясающие! Что делать, если я хочу включить индекс в свою функцию? Индекс любой данной строки DataFrameперед добавлением dбудет Index([u'a', u'b', u'c', u'd'], dtype='object'), но мне нужны 0 и 1. Так что я не могу просто получить доступ row.index.

Я знаю, что могу создать временный столбец в таблице, где я храню индекс, но мне интересно, хранится ли он где-нибудь в объекте строки.

Майк
источник
1
В сторону: есть ли причина, по которой вам нужно использовать apply? Это намного медленнее, чем выполнение векторизованных операций с самим фреймом. (Иногда применить - это самый простой способ что-то сделать, и соображения производительности часто преувеличиваются, но в вашем конкретном примере так же легко не использовать его.)
DSM
1
@DSM на самом деле я вызываю другой конструктор объектов для каждой строки, используя разные элементы строки. Я просто хотел собрать минимальный пример, чтобы проиллюстрировать вопрос.
Майк

Ответы:

148

В этом случае для доступа к индексу вы обращаетесь к nameатрибуту:

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

Обратите внимание, что если это действительно то, что вы пытаетесь сделать, следующее работает и работает намного быстрее:

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

РЕДАКТИРОВАТЬ

Глядя на этот вопрос спустя 3+ года, вы могли бы просто сделать:

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

но если предположить, что это не так тривиально, чем бы вы ни rowFuncзанимались на самом деле, вам следует использовать векторизованные функции, а затем использовать их против индекса 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
источник
Было бы неплохо, если nameбы в случае a был бы именованный кортеж Multindex, чтобы можно было запрашивать определенный уровень индекса по его имени.
Константин
18

Либо:

1. с row.nameвнутренним apply(..., axis=1)звонком:

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. с iterrows()(медленнее)

DataFrame.iterrows () позволяет перебирать строки и получать доступ к их индексу:

for idx, row in df.iterrows():
    ...
SMCI
источник
2
и, если это касается, itertuples обычно работает намного лучше: stackoverflow.com/questions/24870953/…
dpb 08
6

Чтобы ответить на исходный вопрос: да, вы можете получить доступ к значению индекса строки в apply(). Он доступен под ключом nameи требует вашего указания axis=1(поскольку лямбда обрабатывает столбцы строки, а не строки столбца).

Рабочий пример (панды 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
Фрик Викмейер
источник
1
Также работает для фреймов данных с MultiIndex: row.name становится кортежем.
Charles Fox