Почему pandas.grouby.mean намного быстрее параллельной реализации - PullRequest
0 голосов
/ 04 февраля 2019

Я использовал функцию среднего значения pandas grouby, как показано ниже, для очень большого набора данных:

import pandas as pd
df=pd.read_csv("large_dataset.csv")
df.groupby(['variable']).mean() 

Похоже, что функция не использует многопроцессорную обработку, и поэтому я реализовал параллельную версию:

import pandas as pd 
from multiprocessing import Pool, cpu_count 

def meanFunc(tmp_name, df_input): 
    df_res=df_input.mean().to_frame().transpose()
    return df_res 

def applyParallel(dfGrouped, func):
    num_process=int(cpu_count())
    with Pool(num_process) as p: 
        ret_list=p.starmap(func, [[name, group] for name, group in dfGrouped])
    return pd.concat(ret_list)

applyParallel(df.groupby(['variable']), meanFunc)

Однако, похоже, что реализация pandas все еще на способ быстрее, чем моя параллельная реализация.

Я смотрю на исходный код для групп панд и вижу, что он использует cython.Это причина?

def _cython_agg_general(self, how, alt=None, numeric_only=True,
                        min_count=-1):
    output = {}
    for name, obj in self._iterate_slices():
        is_numeric = is_numeric_dtype(obj.dtype)
        if numeric_only and not is_numeric:
            continue

        try:
            result, names = self.grouper.aggregate(obj.values, how,
                                                   min_count=min_count)
        except AssertionError as e:
            raise GroupByError(str(e))
        output[name] = self._try_cast(result, obj)

    if len(output) == 0:
        raise DataError('No numeric types to aggregate')

    return self._wrap_aggregated_output(output, names)

1 Ответ

0 голосов
/ 05 февраля 2019

Краткий ответ - используйте dask , если вы хотите параллелизма для подобных случаев.В вашем подходе есть подводные камни, которых он избегает.Это все еще может быть не быстрее, но даст вам лучший шанс и в значительной степени заменяет панд.

Более длинный ответ

1) Параллелизм по своей природе добавляет накладные расходы, поэтому в идеале операциявы распараллеливание несколько дорого.Сложение чисел не особенно - вы правы, что здесь используется Cython, код, который вы просматриваете, - это логика рассылки.Фактический ядро ​​Cython - это здесь , что переводится как очень простой цикл C.

2) Вы используете мультиобработку, что означает, что каждый процесс должен получить копиюданных.Это дорогоОбычно вы должны делать это в python из-за GIL - вы на самом деле можете (и dask делает) использовать потоки здесь, потому что операция pandas находится в C и освобождает GIL.

3) Как заметил @AKX вкомментарии - итерация перед распараллеливанием (... name, group in dfGrouped) также относительно дорогая - она ​​создает новые фреймы данных для каждой группы.Оригинальный алгоритм панд перебирает данные на месте.

...