2014-02-27 4 views
3

У меня есть кадр данных Pandas, где я пытаюсь заменить значения в каждой группе средним значением группы. На моей машине линия df["signal"].groupby(g).transform(np.mean) занимает около 10 секунд для работы с N и N_TRANSITIONS установлена ​​на цифры ниже.Ускоренный способ преобразования группы со средним значением в Pandas

Есть ли более быстрый способ достижения такого же результата?

import pandas as pd 
import numpy as np 
from time import time 

np.random.seed(0) 

N = 120000 
N_TRANSITIONS = 1400 

# generate groups 
transition_points = np.random.permutation(np.arange(N))[:N_TRANSITIONS] 
transition_points.sort() 
transitions = np.zeros((N,), dtype=np.bool) 
transitions[transition_points] = True 
g = transitions.cumsum() 

df = pd.DataFrame({ "signal" : np.random.rand(N)}) 

# here is my bottleneck for large N 
tic = time() 
result = df["signal"].groupby(g).transform(np.mean) 
toc = time() 
print toc - tic 
+0

какая версия pandas? на master/0.13.1 это занимает 500 мс – Jeff

+0

@Jeff: я получаю 1,81 с, но я не понимаю, почему это так длиннее, чем 'df [" signal "]. groupby (g) .mean()' который принимает меня всего 6,07 мс. – DSM

+0

'' mean'' является cythonized, преобразование должно идти туда и обратно в пространство python – Jeff

ответ

4

Вдохновленный ответом Джеффа. Это самый быстрый способ на моей машине:

pd.Series(np.repeat(grp.mean().values, grp.count().values)) 
+0

yep ... еще лучше (имейте в виду, что вам нужно установить индекс конечного объекта, если ваш индекс отличается от начала) – Jeff

+0

ОК. Я буду читать информацию об индексах. Спасибо за вашу помощь, очень ценю. – YXD

4

Текущий метод, с помощью преобразования

In [44]: grp = df["signal"].groupby(g) 

In [45]: result2 = df["signal"].groupby(g).transform(np.mean) 

In [47]: %timeit df["signal"].groupby(g).transform(np.mean) 
1 loops, best of 3: 535 ms per loop 

Использование «вещания» результатов

In [43]: result = pd.concat([ Series([r]*len(grp.groups[i])) for i, r in enumerate(grp.mean().values) ],ignore_index=True) 

In [42]: %timeit pd.concat([ Series([r]*len(grp.groups[i])) for i, r in enumerate(grp.mean().values) ],ignore_index=True) 
10 loops, best of 3: 119 ms per loop 

In [46]: result.equals(result2) 
Out[46]: True 

Я думаю, что вам может понадобиться, чтобы установить индекс возвращаемый на результат вещания (он работает здесь, потому что его индекс по умолчанию

result = pd.concat([ Series([r]*len(grp.groups[i])) for i, r in enumerate(grp.mean().values) ],ignore_index=True) 
result.index = df.index 
+0

@DSM Я думаю, что это было бы хорошим улучшением на самом деле; https://github.com/pydata/pandas/issues/6496 – Jeff

+0

это намного быстрее. Благодарю. У вас есть ссылка, чтобы я мог понять, что происходит (в частности, почему у вас есть конкретный «ignore_index» - я довольно новичок в Pandas)? – YXD

+0

http://pandas-docs.github.io/pandas-docs-travis/merging.html#ignoring-indexes-on-the-concatenation-axis – Jeff

Смежные вопросы