Using concurrent.futures.ProcessPoolExecutor with DataFrame.GroupBy

Viewed 379

This might be a common problem, but I failed to find any good / up-to-date solutions online. I am currently working on a huge dataframe for n companies, whereby we do some heavy calculations per company an then aggregate all the results as a new dataframe. Pretty straightforward, we run df.groupby('company').apply(function) and go grab a cup of coffee while it runs, since this is a single threaded operations.

Now things are getting out of control, with (3h+ wait time), and we're experimenting with multiprocessing. We have implemented the small 'concept' below, whereby we pass a DataFrame.GroupBy to the executor.map callback function and wait for the results.

Problem is, it seems to take a veeeeeeery long time to run, with no feedback on what is actually happening inside each thread. Not sure this is the correct implementation, all I can see is CPU and memory running at 100% use, but the executor never finishes.

Below is a simplified version of the calculations to be done for every company in the database. Advise on how to properly use groupby with multiprocessing is much appreciated.

import time
import concurrent

def append_new_company_technicals(group):
    '''
    Takes a dataframe and build new columns with technical information
    '''
    print(group['ticker'].unique())
    group.sort_values(by='date', inplace=True)

    group['halfvol_30_abs'] = group['px'].rolling(30,min_periods = 21).apply(func)
    group['halfvol_180_abs'] = group['px1'].rolling(180,min_periods = 135).apply(func)
    group['halfvol_30_rel'] = group['px2'].rolling(30,min_periods = 21).apply(func)
    group['halfvol_180_rel'] = group['px3'].rolling(180,min_periods = 135).apply(func)
    return group
    
start = time.time()
with concurrent.futures.ProcessPoolExecutor() as executor:
    futures = {executor.map(append_new_company_technicals, df_merged.groupby('ticker'))}
end = time.time()
print("MultiProcessing computation: {} secs ".format(end - start))
1 Answers

If you want some feedback as the thing is running try applying the tqdm function (from the tqdm package) to an iterable. In your case to df_merged.groupby('ticker').

Related