pobieranie indeksu wiersza w pandach stosuje funkcję

121

Próbuję uzyskać dostęp do indeksu wiersza w funkcji stosowanej w całej DataFramePandas. Mam coś takiego:

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

i zdefiniuję funkcję, która ma dostęp do elementów z podanym wierszem

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

Mogę to zastosować w ten sposób:

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

Niesamowite! A co, jeśli chcę włączyć indeks do mojej funkcji? Indeks każdego wiersza w tym DataFrameprzed dodaniem dbyłby Index([u'a', u'b', u'c', u'd'], dtype='object'), ale chcę 0 i 1. Więc nie mogę po prostu uzyskać dostępu row.index.

Wiem, że mógłbym utworzyć tymczasową kolumnę w tabeli, w której przechowuję indeks, ale zastanawiam się, czy jest ona gdzieś przechowywana w obiekcie wiersza.

Mikrofon
źródło
1
Na bok: czy jest powód, dla którego musisz użyć apply? Jest to znacznie wolniejsze niż wykonywanie wektoryzowanych operacji na samej ramie. (Czasami zastosowanie jest najprostszym sposobem zrobienia czegoś, a względy wydajności są często wyolbrzymione, ale w twoim konkretnym przykładzie równie łatwo jest tego nie używać.)
DSM
1
@DSM w rzeczywistości wywołuję inny konstruktor obiektów dla każdego wiersza przy użyciu różnych elementów wiersza. Chciałem tylko zebrać minimalny przykład, aby zilustrować pytanie.
Mike

Odpowiedzi:

148

Aby uzyskać dostęp do indeksu w tym przypadku, należy uzyskać dostęp do nameatrybutu:

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

Zauważ, że jeśli naprawdę próbujesz to zrobić, poniższe działa i jest znacznie szybsze:

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

EDYTOWAĆ

Patrząc na to pytanie 3+ lata później, możesz po prostu zrobić:

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

ale zakładając, że nie jest to tak trywialne, jak to, cokolwiek rowFuncnaprawdę robisz, powinieneś użyć funkcji wektoryzowanych, a następnie użyć ich względem indeksu 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
źródło
Byłoby miło, gdyby namew przypadku a byłaby to nazwana krotka Multindex, tak aby można było zapytać o konkretny poziom indeksu o jego nazwę.
Konstantin
18

Zarówno:

1. z row.namewewnętrzną apply(..., axis=1)rozmową:

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. z iterrows()(wolniej)

DataFrame.iterrows () umożliwia iterację po wierszach i dostęp do ich indeksu:

for idx, row in df.iterrows():
    ...
smci
źródło
2
a jeśli dotyczy, „itertuples” generalnie działa znacznie lepiej: stackoverflow.com/questions/24870953/ ...
dpb Kwietnia
6

Aby odpowiedzieć na pierwotne pytanie: tak, możesz uzyskać dostęp do wartości indeksu wiersza w apply(). Jest dostępna pod kluczem namei wymaga określenia axis=1(ponieważ lambda przetwarza kolumny wiersza, a nie wiersze kolumny).

Przykład roboczy (pandy 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
źródło
1
Działa również dla ramek danych z MultiIndex: row.name staje się krotką.
Charles Fox