2015-08-08 2 views
4

Я использую модуль pandas. В моем поле DataFrame 3 находятся учетная запись, месяц и зарплата.Pandas groupby + преобразование на 50 миллионов строк занимает 3 часа

account month    Salary 
    1  201501    10000 
    2  201506    20000 
    2  201506    20000 
    3  201508    30000 
    3  201508    30000 
    3  201506    10000 
    3  201506    10000 
    3  201506    10000 
    3  201506    10000 

Я делаю groupby на счете и в месяц и конвертирую зарплату в проценты от зарплаты группы, которой он принадлежит.

MyDataFrame['salary'] = MyDataFrame.groupby(['account'], ['month'])['salary'].transform(lambda x: x/x.sum()) 

Теперь MyDataFrame становится как ниже таблице

account month    Salary 
    1  201501    1 
    2  201506    .5 
    2  201506    .5 
    3  201508    .5 
    3  201508    .5 
    3  201506    .25 
    3  201506    .25 
    3  201506    .25 
    3  201506    .25 

Проблема: Операция на 50 миллионов таких строк занимает 3 часа. Я выполнил groupyby отдельно быстро, занимает 5 секунд. Я думаю, что это преобразование занимает много времени здесь. есть ли способ улучшить производительность?

Update: Для обеспечения большей ясности, добавив пример Некоторые владелец счета получили зарплату 2000 в июне и 8000 в июле, так что его доля становится .2 в июне и в июле .8. моя цель - рассчитать эту пропорцию.

+0

Ответ = Запрос. Таким образом, создайте набор данных, чтобы ответить на каждую запись для лучшей производительности. Иначе ресурс отходов. Не перебирайте свои коллекции. Почему google бот посещает все веб-сайты? – dsgdfg

+0

@SDilmac Забыл добавить имя столбца после groupby, обновленный сейчас. Не уверен, что это была трата ресурсов в соответствии с вашим комментарием. И когда вы говорите, не перебирайте свою коллекцию, а что другое? это то что мне нужно. когда все в памяти, почему мне нужно перебирать один за другим. но я не знаю, что является другим способом. – Vipin

+0

И когда вы говорите, не итерируйте свою коллекцию = Вклад процента коллекций (1/50 м), поэтому, когда вы проверяете общее состояние, вы просматриваете всю коллекцию. Друг вы будете готовы ко всем запросам. Создайте коллекцию статусов коллекций. Записывайте исходный и статус (перегруппируйте, анализируйте) коллекцию с одинаковым временем. – dsgdfg

ответ

4

Ну, вам нужно быть более явным и показать, что именно вы делаете. Это что-то панды.

Примечание для @Uri Goren. Это постоянный процесс памяти и имеет только одну группу в памяти за раз. Это будет линейно масштабироваться с количеством групп. Сортировка также не требуется.

In [20]: np.random.seed(1234) 

In [21]: ngroups = 1000 

In [22]: nrows = 50000000 

In [23]: dates = pd.date_range('20000101',freq='MS',periods=ngroups) 

In [24]: df = DataFrame({'account' : np.random.randint(0,ngroups,size=nrows), 
       'date' : dates.take(np.random.randint(0,ngroups,size=nrows)), 
       'values' : np.random.randn(nrows) }) 


In [25]: 

In [25]: df.info() 
<class 'pandas.core.frame.DataFrame'> 
Int64Index: 50000000 entries, 0 to 49999999 
Data columns (total 3 columns): 
account int64 
date  datetime64[ns] 
values  float64 
dtypes: datetime64[ns](1), float64(1), int64(1) 
memory usage: 1.5 GB 

In [26]: df.head() 
Out[26]: 
    account  date values 
0  815 2048-02-01 -0.412587 
1  723 2023-01-01 -0.098131 
2  294 2020-11-01 -2.899752 
3  53 2058-02-01 -0.469925 
4  204 2080-11-01 1.389950 

In [27]: %timeit df.groupby(['account','date']).sum() 
1 loops, best of 3: 8.08 s per loop 

Если вы хотите, чтобы преобразовать выход, то Doit как это

In [37]: g = df.groupby(['account','date'])['values'] 

In [38]: result = 100*df['values']/g.transform('sum') 

In [41]: result.head() 
Out[41]: 
0  4.688957 
1 -2.340621 
2 -80.042089 
3 -13.813078 
4 -70.857014 
dtype: float64 

In [43]: len(result) 
Out[43]: 50000000 

In [42]: %timeit 100*df['values']/g.transform('sum') 
1 loops, best of 3: 30.9 s per loop 

Возьмите немного дольше. Но опять же это должна быть относительно быстрая операция.

+0

Я хочу рассчитать пропорциональную зарплату всем владельцам учетных записей, полученных ежемесячно. например, один владелец счета получил зарплату 2000 в июне и 8000 в июле, поэтому его доля составляет 0,2 на июнь и 0,8 за июль. моя цель - рассчитать эту пропорцию. – Vipin

+0

Будучи новым для панд и питонов, возможно, я не использую лучшие практики здесь. Как я понимаю, в этом случае с использованием преобразования я запускаю цикл для 50 м элементов. Глядя на то время, которое я знал, конечно, это не правильно. – Vipin

+0

Я думаю, что это трансформация, которая вызывает проблему. Во время самой суммы использование памяти удваивается, а потом возвращается лишь к незначительному увеличению. Во время преобразования для меня он увеличился в четыре раза (так что на 3 раза больше) и занял 2 мин. Если ОП углубляется в своп, я могу поверить, что все упадет до ползания. (Плюс, кажется немного странным, что для преобразования нужно больше 8 раз, чем сумма, которая должна быть просто суммой + повторением.) – DSM

0

Я хотел бы использовать другой подход сортировать,

MyDataFrame.sort(['account','month'],inplace=True) 

Тогда итерацию и просуммировать

(account,month)=('','') #some invalid values 
salary=0.0 
res=[] 
for index, row in MyDataFrame.iterrows(): 
    if (row['account'],row['month'])==(account,month): 
    salary+=row['salary'] 
    else: 
    res.append([account,month,salary]) 
    salary=0.0 
    (account,month)=(row['account'],row['month']) 
df=pd.DataFrame(res,columns=['account','month','salary']) 

Таким образом, панды не нужно держать сгруппированных данных в памяти.

+0

почему вы думаете, что это будет быстрее? – Vipin

+0

Функция 'transform' передает всю группу аргументы для функции обработчика, это означает, что pandas должно хранить эти данные где-то. Этот метод (вдохновленный шаблонами уменьшения карты) не хранит целые данные группы, а только агрегаты (в 'res') –

+0

Кстати, я бы предположил, что для маленького' DataFrame '' 'df.groupby(). sum()' будет быстрее –

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