#python #pandas #performance #dataframe
Вопрос:
Pandas to_dict(«записи»), по-видимому, имеет гораздо более низкую производительность по сравнению с наивной реализацией. Ниже приведен фрагмент кода моей реализации:
def fast_to_dict_records(df):
data = df.values.tolist()
columns = df.columns.tolist()
return [
dict(zip(columns, datum))
for datum in data
]
Чтобы сравнить производительность, попробуйте приведенный ниже фрагмент кода:
import pandas as pd
import numpy as np
df_test = pd.DataFrame(
np.random.normal(size=(10000, 300)),
columns=range(300)
)
%timeit df_test.to_dict('records')
%timeit fast_to_dict_records(df_test)
И результаты являются:
2.21 s ± 71.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
293 ms ± 15.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
А именно, моя реализация на ~7,5 быстрее, чем собственная реализация pandas. Кроме того, должно быть легко убедиться, что два метода дают один и тот же результат. Я также протестировал производительность на разных размерах фреймов данных, и, похоже, моя реализация постоянно превосходит свою аналогию (хотя величина может отличаться).
Мне любопытно, не упускаю ли я здесь чего-нибудь? Я просто не уверен, что производительность собственной реализации pandas, которая, по моему впечатлению, была вполне конкурентоспособной, может быть настолько превзойдена не такой сложной альтернативой…
Комментарии:
1. вы могли бы взглянуть на исходный код, чтобы увидеть, в чем разница
2. На мой взгляд, причина в том, что нативная реализация работает над структурами pandas, и они тяжелы в обработке, вместо этого вы преобразуете за одну операцию все данные в собственные типы python, и с этого момента другие операции выполняются очень быстро. попробуйте преобразовать каждую строку фрейма данных, я ожидаю, что это будет лучше соответствовать собственной производительности.
3. Приятное открытие! Я думаю, что мы можем открыть билет на GitHub, чтобы исправить эту проблему с производительностью.
Ответ №1:
TL;DR: Pandas в основном написан на чистом Python, как и ваша реализация, хотя для ускорения вычислений в нем часто используются векторизованные вызовы Numpy. К сожалению, здесь это не так. В результате реализация Pandas неэффективна. Ваша реализация выполняется быстрее, но требует больше памяти.
Углубленное изучение:
Вы можете найти реализацию to_list
здесь. Он выполняет итерацию по данным, используя itertuples
внутренние данные (см. Здесь его код). Полученный (слегка упрощенный) код Панды на дату 12 марта 2021 года выглядит следующим образом:
def maybe_box_native(value: Scalar) -> Scalar:
if is_datetime_or_timedelta_dtype(value): # branch never taken here
value = maybe_box_datetimelike(value)
elif is_float(value): # branch always taken here
value = float(value) # slow manual conversion for EACH values!
elif is_integer(value):
value = int(value)
elif is_bool(value):
value = bool(value)
return value
def pandas_to_list(df):
# From itertuples:
fields = list(df.columns)
arrays = [df.iloc[:, k] for k in range(len(df.columns))]
tmpRes = zip(*arrays)
# From to_list:
columns = df.columns.tolist()
rows = (dict(zip(columns, row)) for row in tmpRes)
return [dict((k, maybe_box_native(v)) for k, v in row.items()) for row in rows]
Ваша реализация генерирует большой временный список в памяти, используя to_list
в то время как Pandas внутренне работает с генераторами Python. Этот список не должен быть проблемой на практике в большинстве простых случаев, так dict
как в конечном итоге он должен быть намного больше.
Однако to_list
(в вашей реализации) также эффективно преобразует типы Numpy, используя внутренние векторизованные вызовы Numpy, в то время как Панды используют очень медленный подход. Действительно, Панды проверяют и преобразуют все значения одно за другим, используя maybe_box_native
функцию pure Python и медленно, если/иначе… Поэтому неудивительно, что реализация Pandas происходит медленнее. При этом обратите внимание, что ваш код может вести себя по-разному с датами.
Текущая реализация Pandas неэффективна, и ее явно можно улучшить в будущем (возможно, не требуя значительно большего объема памяти).
Комментарии:
1. Действительно. После проверки реализации pandas я вижу, что она выполняет больше циклов. Спасибо!