DataFrame Index에 기능 적용


84

Pandas의 인덱스에 함수를 적용하는 가장 좋은 방법은 무엇입니까 DataFrame? 현재 저는이 장황한 접근 방식을 사용하고 있습니다.

pd.DataFrame({"Month": df.reset_index().Date.apply(foo)})

어디 Date 인덱스의 이름이고 foo내가 적용하고있는 함수의 이름입니다.


6
않는 df.index.map(foo)일을?
HYRY

1
"작동"하지만 Pandas Series가 아닌 numpy 배열을 반환합니다.
Alex Rothberg 2013

1
당신의 최종 목표는 무엇입니까? DataFrame 생성자에 배열을 전달할 수 있습니다. 또는 같은 것을 할pd.Series(df.index).apply(foo)
로마 Pekar

그것은 완전히 기능이 ... 무엇을 따라
앤디 헤이든에게

1
기존 DataFrame의 인덱스 만 수정하려는 경우 @HYRY에서 다음을 수행 할 수 있습니다.df.index = df.index.map(foo)
Ben

답변:


99

HYRY 가 의견에서 이미 제안 했듯이 Series.map 은 여기로 이동하는 방법입니다. 결과 시리즈에 인덱스를 설정하기 만하면됩니다.

간단한 예 :

df = pd.DataFrame({'d': [1, 2, 3]}, index=['FOO', 'BAR', 'BAZ'])
df
        d
FOO     1
BAR     2
BAZ     3

df.index = df.index.map(str.lower)
df
        d
foo     1
bar     2
baz     3

색인! = 시리즈

@OP가 지적한 바와 같습니다. df.index.map(str.lower)호출은 NumPy와 배열을 반환합니다. 이는 데이터 프레임 인덱스 시리즈가 아닌 numpy 배열을 기반으로 하기 때문 입니다.

인덱스를 Series로 만드는 유일한 방법은 그것에서 Series를 만드는 것입니다.

pd.Series(df.index.map(str.lower))

경고

Index클래스는 이제 서브 클래스 StringAccessorMixin는 다음과 같이 위의 작업을 할 수있는 수단,

df.index.str.lower()

이것은 여전히 ​​Series가 아닌 Index 객체를 생성합니다.


1
다중 인덱스를 사용하면 함수에서 두 항목을 모두 사용하려는 경우 슬라이싱을 사용할 수 있습니다 (예 : x[0]x[1].
Elliott 2016

3
좀 더 짧은 방법df.index.map(str.lower)
Zero

1
@JohnGalt 지적 해 주셔서 감사합니다. str.lower는 컴파일 된 cython 함수이고 내가 작성한 람다 함수는 그렇지 않기 때문에 더 짧을뿐만 아니라 더 빠릅니다.
firelynx

12

인덱스에 "foo"함수를 적용하여 현재 DataFrame에서 열을 만들고 싶다고 가정합니다. 당신은 쓸 수 있습니다 ...

df['Month'] = df.index.map(foo)

시리즈 만 생성하려면 대신 할 수 있습니다.

pd.Series({x: foo(x) for x in foo.index})

1
pandas / numpy 에코 시스템에서 for 루프를 사용하는 것은 매우 권장되지 않습니다. 메모리가 매우 비효율적이며 더 큰 데이터 세트와 쉽게 충돌합니다.
firelynx

3

많은 답변이 인덱스를 배열로 반환하므로 인덱스 이름 등에 대한 정보가 손실됩니다 (할 수는 있지만 pd.Series(index.map(myfunc), name=index.name)). MultiIndex에서도 작동하지 않습니다.

이 작업을 수행 한 방법은 "이름 바꾸기"를 사용하는 것입니다.

mix = pd.MultiIndex.from_tuples([[1, 'hi'], [2, 'there'], [3, 'dude']], names=['num', 'name'])
data = np.random.randn(3)
df = pd.Series(data, index=mix)
print(df)
num  name 
1    hi       1.249914
2    there   -0.414358
3    dude     0.987852
dtype: float64

# Define a few dictionaries to denote the mapping
rename_dict = {i: i*100 for i in df.index.get_level_values('num')}
rename_dict.update({i: i+'_yeah!' for i in df.index.get_level_values('name')})
df = df.rename(index=rename_dict)
print(df)
num  name       
100  hi_yeah!       1.249914
200  there_yeah!   -0.414358
300  dude_yeah!     0.987852
dtype: float64

이것에 대한 유일한 트릭은 당신의 인덱스가 다른 다중 인덱스 레벨과 함께 고유 한 레이블을 가져야한다는 것입니다.하지만 아마도 저보다 더 똑똑한 누군가가 그것을 극복하는 방법을 알고있을 것입니다. 내 목적을 위해 이것은 95 %의 시간 동안 작동합니다.


3

언제든지 해당 to_series()방법을 사용하여 색인을 변환 한 다음 선호 사항 / 필요에 따라 apply또는을 변환 할 수 있습니다 map.

ret = df.index.map(foo)                # Returns pd.Index
ret = df.index.to_series().map(foo)    # Returns pd.Series
ret = df.index.to_series().apply(foo)  # Returns pd.Series

위의 모든 항목은의 신규 또는 기존 열에 직접 할당 할 수 있습니다 df.

df["column"] = ret

완전성을 위해 : pd.Index.map, pd.Series.map그리고 pd.Series.apply모두 요소별로 작동합니다. 나는 종종 또는로 map표시되는 조회를 적용 하는 데 사용 합니다 . 추가와 함께 어떤 기능을 전달할 수 있기 때문에 더 일반적이기 거나 . 차이점 및 상기에서 설명 이 SO 실 . 왜 생략 되었는지 모르겠습니다 .dictspd.Seriesapplyargskwargsapplymappd.Index.apply

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.