Более быстрый способ генерации скользящих вычислений в списке столбцов в объекте groupby

1

Я создал эту функцию, чтобы вычислить статистику проката для списка подвигов в моем df. Эта функция работает по назначению, но занимает примерно 30 минут, чтобы работать на моем df, который имеет около 1 миллиона строк. Есть ли более быстрый способ сделать это в python/pandas?

def add_rolling_vars(df, feats, amounts, group):
#creates rolling stats for a list of feats(columns) over a list of amounts[12,48](window sizes)
#grouped by a group like $gvkey or $sector
orig_feats = feats.copy()
new_feats= []
for amount in amounts:
    for name in feats:
        df[group+'_'+name+f'_{amount}_sma'] = df.groupby(group)[name].rolling(amount,1).mean().values
        df[group+'_'+name+f'_{amount}_std'] = df.groupby(group)[name].rolling(amount,1).std().values
        df[group+'_'+name+f'_{amount}_min'] = df.groupby(group)[name].rolling(amount,1).min().values
        df[group+'_'+name+f'_{amount}_max'] = df.groupby(group)[name].rolling(amount,1).max().values
        df[group+'_'+name+f'_{amount}_med'] = df.groupby(group)[name].rolling(amount,1).median().values
        df[group+'_'+name+f'_{amount}_25Q'] = df.groupby(group)[name].rolling(amount,1).quantile(.25).values
        df[group+'_'+name+f'_{amount}_75Q'] = df.groupby(group)[name].rolling(amount,1).quantile(.75).values

В качестве примера я также создал эту функцию, которая работает на одном наборе данных примерно за 1 минуту. Очевидно, это отличается от того, что ему не нужно перебирать строки из строк, но я все же могу передать список умений вместо имени в подвигах, а затем добавить весь преобразованный вывод в свой фреймворк с использованием схемы именования списка:

def add_cat_stats(df,feats,group):
    #feats is a list of continuous feats to compute the monthly stats of       
    df[[group+'_'+name+'_avg' for name in feats]] = df.groupby([group,'Date'])[feats].transform('mean')
    df[[group+'_'+name+'_std' for name in feats]] = df.groupby([group,'Date'])[feats].transform('std')
    df[[group+'_'+name+'_min' for name in feats]] = df.groupby([group,'Date'])[feats].transform('min')
    df[[group+'_'+name+'_max' for name in feats]] = df.groupby([group,'Date'])[feats].transform('max')
    df[[group+'_'+name+'_med' for name in feats]] = df.groupby([group,'Date'])[feats].transform('median')

ОБНОВИТЬ

len (количества) = 2

len (подвиги) = 16

Теги:
pandas
performance
python-3.x
cython

1 ответ

1
Лучший ответ

Я не смог получить код @John Zwinck, но он дал мне эту идею, чтобы переформатировать код, который сокращает время с 30 минут до 4 минут 45 секунд, что здорово! Было бы неплохо получить его дальше, но это приемлемое решение:

def add_rolling_vars(df, feats, amounts, group):
    for amount in amounts:
        grouped = df.groupby(group)[feats].rolling(amount,1)
        prefix = ['_'.join([group, name, str(amount)]) for name in feats]
        df[[pre+'_sma' for pre in prefix]] = grouped.mean().reset_index(0,drop=True)
        df[[pre+'_std' for pre in prefix]] = grouped.std().reset_index(0,drop=True)
        df[[pre+'_min' for pre in prefix]] = grouped.min().reset_index(0,drop=True)
        df[[pre+'_max' for pre in prefix]] = grouped.max().reset_index(0,drop=True)
        df[[pre+'_med' for pre in prefix]] = grouped.median().reset_index(0,drop=True)
        df[[pre+'_25Q' for pre in prefix]] = grouped.quantile(.25).reset_index(0,drop=True)
        df[[pre+'_75Q' for pre in prefix]] = grouped.quantile(.75).reset_index(0,drop=True)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню