2015-02-16 4 views
1

Я хотел бы знать, как я могу ускорить выполнение следующей функции, например. с Китоном?Pandas speedup apply on max()

def groupby_maxtarget(df, group, target): 
    df_grouped = df.groupby([group]).apply(lambda row: row[row[target]==row[target].max()]) 
    return df_grouped 

Эта функция группируется по одному столбцу и возвращает все строки, где цель каждой группы достигает своего максимального значения; возвращаемый результирующий фрейм.

Если у df есть, скажем, строки 500K, для выполнения этой функции на компьютере требуется около 5 минут. Эта производительность в порядке, но у меня есть данные с более чем 10 миллионами строк ... Конечно, одним из решений было бы выполнить вышеуказанное в качестве запроса на SQL-сервере и получить Python результат, но я надеялся на SQL- свободное, Pythonic решение.

ответ

4
In [22]: pd.set_option('max_rows',20) 

In [33]: N = 10000000 

In [34]: df = DataFrame({'A' : np.random.randint(0,100,size=N), 'B' : np.random.randint(0,100,size=N)}) 

In [35]: df[df.groupby('A')['B'].transform('max') == df['B']] 
Out[35]: 
      A B 
161  30 99 
178  53 99 
264  58 99 
337  96 99 
411  44 99 
428  85 99 
500  84 99 
598  98 99 
602  24 99 
684  31 99 
...  .. .. 
9999412 25 99 
9999482 35 99 
9999502 6 99 
9999537 24 99 
9999579 65 99 
9999680 32 99 
9999713 74 99 
9999886 90 99 
9999887 57 99 
9999991 45 99 

[100039 rows x 2 columns] 

In [36]: %timeit df[df.groupby('A')['B'].transform('max') == df['B']] 
1 loops, best of 3: 1.85 s per loop 

Обратите внимание, что это пропорционально количеству групп, но коэффициент довольно мал. Например. Я делаю 100х групп и скорость только 2x. Трансформация довольно эффективна, когда транслируется.

In [8]: G = 100 

In [9]: df = DataFrame({'A' : np.random.randint(0,G,size=N), 'B' : np.random.randint(0,G,size=N)}) 

In [10]: %timeit df[df.groupby('A')['B'].transform('max') == df['B']] 
1 loops, best of 3: 1.86 s per loop 

In [11]: G = 10000 

In [12]: df = DataFrame({'A' : np.random.randint(0,G,size=N), 'B' : np.random.randint(0,G,size=N)}) 

In [13]: %timeit df[df.groupby('A')['B'].transform('max') == df['B']] 
1 loops, best of 3: 3.95 s per loop 
+0

Не совсем, способ преобразования реализован в основном в режиме вещания. Он вычисляет через cython. Таким образом, даже 100x групп всего в 2 раза медленнее. (IIRC мы сделали это в 0.15.0) – Jeff

+0

Huh! Это значительно улучшилось из прошлого, что заставляет задуматься, не нужны ли какие-то хакеры на уровне нескольких уровней, которые я использовал для повышения производительности. (4s все еще кажется мне длинным, но относительно на порядок лучше, чем я думал.) – DSM

+0

Кстати, улучшение в моем случае экспоненциально – Quetzalcoatl