2014-08-30 3 views
3

DataFrame에서 여러 열을 통해 함수를 적용하는 똑똑한 솔루션을 제공하는 this question을 개선하면서 솔루션의 속도를 최적화 할 수 있는지 궁금합니다.팬더 데이터 프레임에 rolling_apply가 더 빠릅니까?

환경 : Python 2.7.8, Pandas 14.1, Numpy 1.8. meanmax 기능이 페어되지 않도록

import pandas as pd 
import numpy as np 
import random 

def meanmax(ii,df): 
    xdf = df.iloc[map(int,ii)] 
    n = max(xdf['A']) + max(xdf['B']) 
    return n/2.0 

df = pd.DataFrame(np.random.randn(2500,2)/10000, 
        index=pd.date_range('2001-01-01',periods=2500), 
        columns=['A','B'])    
df['ii'] = range(len(df))  

res = pd.rolling_apply(df.ii, 26, lambda x: meanmax(x, df)) 

참고 작동하지 않습니다 rolling_mean(df['A'] + df['B'],26) 같은 따라서 뭔가 :

다음은 예제 설정이다.

내가 좋아하는 뭔가를 할 수있다 그러나 : 빠른 약 3000x를 완료

res2 = (pd.rolling_max(df['A'],26) + pd.rolling_max(df['B'],26))/2 

:

%timeit res = pd.rolling_apply(df.ii, 26, lambda x: meanmax(x, df)) 
1 loops, best of 3: 1 s per loop 

%timeit res2 = (pd.rolling_max(df['A'],26) + pd.rolling_max(df['B'],26))/2 
1000 loops, best of 3: 325 µs per loop 

위의 두 번째 옵션보다는 동등한 더 나은 아무것도 /, 주어진 예 기능과 rolling_apply를 사용하여 거기를 ? A의 크기 n 배열 위에 일반 압연 함수 컴퓨팅 성능 타이밍 보정

+0

어 ..그것은 1 초에 비해 325 마이크로 초입니다. 1000 배 이상 빨라졌습니다. – EdChum

+0

사실, 거기서 'μ'를 알아 채지 못했습니다 ... 수정 해 주셔서 감사합니다. – bazel

답변

7

: 두 번째 옵션이 더 빠른 반면, 더 넓은 문제 설정

편집에 적용 할 수있는 rolling_apply를 사용하지 않는다 크기가 m 인 창에는 대략 O(n*m) 시간이 필요합니다. rollin_xxx에 내장 된 방법은 꽤 똑똑한 알고리즘을 사용하여 실행 시간을 그 이하로 유지하고 종종 O(n) 시간을 보장 할 수 있습니다. 이는 꽤 인상적인 것으로 생각합니다. 나는 내가 생각하는 this paper에서 동일한 알고리즘의 이전에 대한 설명입니다 찾을 수 있지만, 특히

rolling_minrolling_max는 알고리즘의 소스로 Richard Harter를 인용 bottleneck에서 구현을 빌렸다.

그래서 역사 수업을 마치고 나면 케이크를 먹을 수 없을 것입니다. rolling_apply은 매우 편리하지만 거의 항상 특정 알고리즘에 대한 성능을 희생합니다. 필자의 경험에 비추어 볼 때 Python 과학 스택을 사용하는 데 더 즐거운 부분 중 하나는 창의적인 방법으로 제공되는 빠른 기본 요소를 사용하여 효율적인 계산 방법을 찾는 것입니다. rolling_max을 두 번 호출하는 자체 솔루션이 이에 대한 좋은 예입니다. 그래서 당신이나 좋은 사람들이 더 똑똑한 해결책을 제시 할 수 없다면 언제든지 rolling_apply이 다시 돌아올 것이라는 것을 알고, 휴식을 취하고 즐기십시오.

+0

고마워요. - '병목 현상'에 대해 완전히 잊어 버렸습니다. 모듈 - 이중 rolling_max가 왜 그렇게 빠른지 설명합니다. 위의 원래 전략을 개선 할 수 있을지 궁금해하고 있습니다. 아마도 rolling_apply가 일차원 ndarray보다 큰 것을 취할 수 있을지 모른다면 말입니다. 그러면 우리는'meanmax' 함수 내에서 iloc을 수행하는 것을 고민 할 필요가 없으며 여분의 람다 호출을하지 않아도됩니다. – bazel

3

당신은 rolling_max 속도로 내려받을 수 없지만, 자주 .values를 통해 numpy에 내려 놓아 크기 정도의 순서를 면도 할 수 있습니다

def meanmax_np(ii, df): 
    ii = ii.astype(int) 
    n = df["A"].values[ii].max() + df["B"].values[ii].max() 
    return n/2.0 

나에게

>>> %timeit res = pd.rolling_apply(df.ii, 26, lambda x: meanmax(x, df)) 
1 loops, best of 3: 701 ms per loop 
>>> %timeit res_np = pd.rolling_apply(df.ii, 26, lambda x: meanmax_np(x, df)) 
10 loops, best of 3: 31.2 ms per loop 
>>> %timeit res2 = (pd.rolling_max(df['A'],26) + pd.rolling_max(df['B'],26))/2 
1000 loops, best of 3: 247 µs per loop 
을 제공합니다

최적화 된 경우보다 여전히 100 배 느리지 만 원본보다 훨씬 빠릅니다. 때로는 그저 10 배 빠른 것을 필요로 할 때만 충분할 정도로 지배적 인 타임 링크가되지 못합니다.

+0

좋은 캐치. 나는 여전히 rolling_apply를 요구하는 문제에 일반적으로 적용될 수있는 마법 (아마도 존재하지 않는)을 찾고있다.하지만이 예제는 아무리 감사해도 numpy 사용에 유익하다. – bazel

관련 문제