Производительность Python собственного контейнера данных по сравнению с Pandas DataFrame - PullRequest
1 голос
/ 21 марта 2019

Мне интересно, может ли кто-нибудь предоставить какие-либо данные о скорости / производительности собственных контейнеров данных Python по сравнению с Pandas DataFrame, а именно при выполнении поиска подстроки.

Несколько месяцев назад я опубликовал вопрос, касающийся операции ( Выполнение поиска подстроки между одним кадром данных и другим ).По сути, у меня есть список имен (столбец в DataFrame, длина> 2 мм), и я хотел бы «пометить» те имена, которые содержат подстроку из отдельного списка вульгарных слов (длина> 3000).Представленное мне решение хорошо сработало, и я предполагаю, что это наиболее эффективный вариант для DataFrame.

С тех пор, однако, я перешел к созданию GUI (с PyQt5), который включает индикатор выполнения.Проблема с индикатором выполнения состоит в том, что мне потребуется некоторая форма итерации, которая позволила бы мне определить% выполненного прогресса.На этом этапе я изменил свой код, чтобы использовать только нативные итераторы Python (без Pandas DataFrame), и выполнял свои операции в forloop, что позволило мне иметь определенный индикатор выполнения.

Я предположил, что это будет намного медленнее, зная, что преимущество DataFrame в производительности связано с возможностью векторизации операций.Однако, к моему удивлению, итерационный метод с использованием python был ~ 15%.

В чем причина этого?Действительно ли метод панд не векторизован и все еще выполняет зацикливание?Или список / наборы / генераторы являются более легкими и быстрыми по сравнению с DataFrame?


Вот мой код обоих методов:

Реализация Pandas DataFrame

import pandas as pd

df = pd.read_csv(source_file, names = ['ID', 'Fullname'])

vulgars = [line for line in open(vulgar_lookup_file, 'r')]

df['Vulgar Flag'] = df['Fullname'].str.contains('|'.join(vulgars))

Итерационный метод Native Python

vulgars = set(line for line in open(vulgar_lookup_file, 'r'))

# accessing second column of comma-delimited file (containing the fullname)
source = (line.split(',')[1] for line in open(source_file, 'r'))

vulgar_flag = []
for item in source:
    result = any(substr in item for substr in vulgars)
    vulgar_flag.append(result)

Я знаю, что итеративный метод может быть еще более упрощен до понимания списка, и он дает тот же результат на ~ 12% быстрее, чем приведенный выше цикл.Я просто поместил это в форму цикла для удобства чтения.

Спасибо!

1 Ответ

1 голос
/ 22 марта 2019

Короче говоря, нет, методы str не векторизованы.

Если мы посмотрим на код pandas, мы обнаружим, что методы str в конечном итоге делегируют pandas._lib.lib.map_infer, чтоопределяется следующим образом:

def map_infer(ndarray arr, object f, bint convert=1):
    """
    Substitute for np.vectorize with pandas-friendly dtype inference
    Parameters
    ----------
    arr : ndarray
    f : function
    Returns
    -------
    mapped : ndarray
    """
    cdef:
        Py_ssize_t i, n
        ndarray[object] result
        object val

    n = len(arr)
    result = np.empty(n, dtype=object)
    for i in range(n):
        val = f(arr[i])

        if cnp.PyArray_IsZeroDim(val):
            # unbox 0-dim arrays, GH#690
            # TODO: is there a faster way to unbox?
            #   item_from_zerodim?
            val = val.item()

        result[i] = val

    if convert:
        return maybe_convert_objects(result,
                                     try_float=0,
                                     convert_datetime=0,
                                     convert_timedelta=0)

    return result

Мы можем видеть, что это в основном цикл for, хотя и в Cython для скорости.

...