Pandas Внутренний вопрос: я был удивлен, обнаружив несколько раз, когда явное пропускание вызываемого на date_parser
внутри pandas.read_csv
приводит к значительно более медленному времени чтения, чем просто используя infer_datetime_format=True
.
Почему это? Будут ли временные различия между этими двумя параметрами соответствовать конкретным датам или другим факторам, влияющим на их относительное время?
В нижеприведенном случае infer_datetime_format=True
занимает одну десятую время прохождения синтаксического анализатора даты с указанным форматом. Я бы наивно предположил, что последний будет быстрее, потому что он явный.
Документы отмечают,
[if True,] pandas будет пытаться вывести формат строк datetime в столбцах, и если это можно сделать вывод, переключитесь на более быстрый метод их разбора. В некоторых случаях это может увеличить скорость разбора на 5-10x.
но здесь не так много деталей, и я не смог полностью выполнить свой путь через источник.
Настройка:
from io import StringIO
import numpy as np
import pandas as pd
np.random.seed(444)
dates = pd.date_range('1980', '2018')
df = pd.DataFrame(np.random.randint(0, 100, (len(dates), 2)),
index=dates).add_prefix('col').reset_index()
# Something reproducible to be read back in
buf = StringIO()
df.to_string(buf=buf, index=False)
def read_test(**kwargs):
# Not ideal for .seek() to eat up runtime, but alleviate
# this with more loops than needed in timing below
buf.seek(0)
return pd.read_csv(buf, sep='\s+', parse_dates=['index'], **kwargs)
# dateutil.parser.parser called in this case, according to docs
%timeit -r 7 -n 100 read_test()
18.1 ms ± 217 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit -r 7 -n 100 read_test(infer_datetime_format=True)
19.8 ms ± 516 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# Doesn't change with native Python datetime.strptime either
%timeit -r 7 -n 100 read_test(date_parser=lambda dt: pd.datetime.strptime(dt, '%Y-%m-%d'))
187 ms ± 4.05 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
Мне интересно узнать немного о том, что происходит внутри с помощью infer
, чтобы придать этому преимущество. Мое прежнее понимание заключалось в том, что вначале уже происходит какой-то вывод, потому что dateutil.parser.parser
используется, если ни один из них не передан.
Обновление: некоторые из них были сделаны, но не смогли ответить на вопрос.
read_csv()
вызывает вспомогательную функцию, которая в свою очередь вызывает pd.core.tools.datetimes.to_datetime()
. Эта функция (доступная только как pd.to_datetime()
) имеет как аргумент infer_datetime_format
, так и format
.
Однако в этом случае относительные тайминги очень разные и не отражают выше:
s = pd.Series(['3/11/2000', '3/12/2000', '3/13/2000']*1000)
%timeit pd.to_datetime(s,infer_datetime_format=True)
19.8 ms ± 1.54 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit pd.to_datetime(s,infer_datetime_format=False)
1.01 s ± 65.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# This was taking the longest with i/o functions,
# now it behaving "as expected"
%timeit pd.to_datetime(s,format='%m/%d/%Y')
19 ms ± 373 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)