2013-08-19 22 views
37

phép nói rằng tôi có một MultiIndex Dòng s:Access trong pandas.Series.apply

>>> s 
    values 
a b 
1 2 0.1 
3 6 0.3 
4 4 0.7 

và tôi muốn áp dụng một chức năng trong đó sử dụng các chỉ số của hàng:

def f(x): 
    # conditions or computations using the indexes 
    if x.index[0] and ...: 
    other = sum(x.index) + ... 
    return something 

thế nào Tôi có thể làm s.apply(f) để có chức năng như vậy không? Cách được khuyến nghị để thực hiện loại hoạt động này là gì? Tôi mong đợi để có được một Series mới với các giá trị kết quả từ chức năng này được áp dụng trên mỗi hàng và cùng một MultiIndex.

+2

Xem thảo luận này, có vẻ như x.name là những gì bạn đang tìm kiếm http: // stackoverflow.com/questions/26658240/get-the-index-of-a-row-in-a-pandas-apply-function –

Trả lời

31

Tôi không tin rằng apply có quyền truy cập vào chỉ mục; nó đối xử với mỗi hàng như một đối tượng NumPy, không phải là một Series, như bạn có thể thấy:

In [27]: s.apply(lambda x: type(x)) 
Out[27]: 
a b 
1 2 <type 'numpy.float64'> 
3 6 <type 'numpy.float64'> 
4 4 <type 'numpy.float64'> 

Để khắc phục hạn chế này, thúc đẩy các chỉ số vào các cột, áp dụng chức năng của bạn, và tạo một dòng với chỉ số ban đầu.

Series(s.reset_index().apply(f, axis=1).values, index=s.index) 

cách tiếp cận khác có thể sử dụng s.get_level_values, mà thường được một chút xấu xí trong quan điểm của tôi, hoặc s.iterrows(), mà có thể sẽ chậm hơn - có lẽ tùy thuộc vào chính xác những gì f làm.

+0

Cũng đáng chú ý rằng vectorising f, và sử dụng & | vv, cũng có thể nhanh hơn. –

+0

Hiện tại tôi đang sử dụng phương pháp reset_index, sẽ giữ một chút để xem liệu ai đó có đề xuất giải pháp sạch hơn hay không. – elyase

+3

+1 Để thoát khỏi 'MultiIndex'. Trong khi những điều này đôi khi hữu ích, tôi càng thấy mình biến các chỉ mục của tôi thành các cột. –

7

Làm cho nó một khung hình, trở vô hướng nếu bạn muốn (do đó kết quả là một series)

Cài đặt

In [11]: s = Series([1,2,3],dtype='float64',index=['a','b','c']) 

In [12]: s 
Out[12]: 
a 1 
b 2 
c 3 
dtype: float64 

In ấn chức năng

In [13]: def f(x): 
    print type(x), x 
    return x 
    ....: 

In [14]: pd.DataFrame(s).apply(f) 
<class 'pandas.core.series.Series'> a 1 
b 2 
c 3 
Name: 0, dtype: float64 
<class 'pandas.core.series.Series'> a 1 
b 2 
c 3 
Name: 0, dtype: float64 
Out[14]: 
    0 
a 1 
b 2 
c 3 

Vì bạn có thể trở lại bất cứ điều gì ở đây, chỉ trả lại vô hướng (truy cập chỉ mục qua thuộc tính name)

In [15]: pd.DataFrame(s).apply(lambda x: 5 if x.name == 'a' else x[0] ,1) 
Out[15]: 
a 5 
b 2 
c 3 
dtype: float64 
+1

vì vậy khi gọi 'apply' trên' DataFrame' chỉ mục của nó sẽ có thể truy cập thông qua 'tên' của mỗi chuỗi? Tôi thấy điều này cũng đúng với 'DateTimeIndex' nhưng nó hơi lạ khi sử dụng một cái gì đó tương tự như' x.name == Time (2015-06-27 20: 08: 32.097333 + 00: 00) ' – dashesy

+1

Đây phải là câu trả lời, việc áp dụng 'x.name' là cách giải quyết vấn đề rõ ràng và linh hoạt nhất. –

0

Bạn thể thấy nó nhanh hơn để sử dụng where hơn apply đây:

In [11]: s = pd.Series([1., 2., 3.], index=['a' ,'b', 'c']) 

In [12]: s.where(s.index != 'a', 5) 
Out[12]: 
a 5 
b 2 
c 3 
dtype: float64 

Ngoài ra bạn có thể sử dụng NumPy kiểu logic/chức năng để bất cứ bộ phận:

In [13]: (2 * s + 1).where((s.index == 'b') | (s.index == 'c'), -s) 
Out[13]: 
a -1 
b 5 
c 7 
dtype: float64 

In [14]: (2 * s + 1).where(s.index != 'a', -s) 
Out[14]: 
a -1 
b 5 
c 7 
dtype: float64 

Tôi khuyên bạn nên thử nghiệm cho tốc độ (như hiệu quả chống lại áp dụng sẽ phụ thuộc vào chức năng). Mặc dù, tôi thấy rằng apply s dễ đọc hơn ...

+2

Hm. Bây giờ tôi tự hỏi liệu có nên có phương thức 'Series.eval' /' query' ... tôi sẽ đưa nó lên trên gấu trúc. –

+1

@PhillipCloud, +1, tôi cần sử dụng nhiều chỉ mục (thêm/subs, căn chỉnh và thiếu dữ liệu) và điều này sẽ rất tuyệt vời. – elyase

+0

Tôi đang tìm kiếm ngày càng thường xuyên hơn nếu tôi chuyển đổi 'MultiIndex' thành các cột, tôi hạnh phúc hơn nhiều và cuộc sống dễ dàng hơn. Có * vậy * nhiều hơn nữa bạn có thể làm với các cột trong một 'DataFrame' hơn là một' Series' với một 'MultiIndex', trên thực tế chúng về cơ bản giống nhau, ngoại trừ các truy vấn sẽ nhanh hơn trong các cột' DataFrame' hơn trong 'Series'-with-'MultiIndex'. –

0

Bạn có thể truy nhập toàn bộ hàng làm đối số bên trong fucntion nếu bạn sử dụng DataFrame.apply() thay cho Series.apply().

def f1(row): 
    if row['I'] < 0.5: 
     return 0 
    else: 
     return 1 

def f2(row): 
    if row['N1']==1: 
     return 0 
    else: 
     return 1 

import pandas as pd 
import numpy as np 
df4 = pd.DataFrame(np.random.rand(6,1), columns=list('I')) 
df4['N1']=df4.apply(f1, axis=1) 
df4['N2']=df4.apply(f2, axis=1) 
2

Chuyển đổi thành DataFrame và áp dụng dọc theo hàng. Bạn có thể truy cập chỉ mục dưới dạng x.name. x cũng là một Series bây giờ với 1 giá trị

s.to_frame(0).apply(f, axis=1)[0] 
Các vấn đề liên quan