Как я могу ускорить этот процесс преобразования UTC?

Я хотел бы преобразовать диапазон Datetime в часовой пояс UTC. Следующий код занимает более трех минут для 500_000 записей.

Как я могу ускорить этот процесс?

import datetime
from pytz import timezone
import pytz
import pandas as pd
import time
abc = pd.date_range(start='2020-03-28 05:00:00', periods=500_000, freq='5min')
UTC = pytz.timezone('UTC')
BERLIN = pytz.timezone('Europe/Berlin')

print("abc[0]=\n", abc[0])
print("abc[-1]=\n", abc[-1])

myList = []
my_time = time.time()
for runner in abc:
    localizedToBerlin = BERLIN.localize(runner)
    localizedToBerlinAsUtc = localizedToBerlin.astimezone(UTC)
    myList.append([runner, localizedToBerlinAsUtc])
print('runtime:', time.time() - my_time)

приводит к:

abc[0]=
 2020-03-28 05:00:00
abc[-1]=
 2024-12-28 07:35:00
runtime: 209.57262253761292

person 7824238    schedule 19.05.2020    source источник
comment
связанный (но не использующий pandas): stackoverflow.com/questions/33532457/   -  person MrFuppes    schedule 19.05.2020


Ответы (1)


Встроенные панды — если вы работаете с/в pandas, старайтесь избегать циклов и используйте встроенные модули, например. tz_convert. Из Европы/Берлина в UTC:

import pandas as pd
dr = pd.date_range(start='2020-03-28 05:00:00', periods=500_000, freq='5min',
                   tz='Europe/Berlin')

%timeit dr.tz_convert('UTC')
77.2 µs ± 1.4 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Локализация из naive в Европу/Берлин, а затем в UTC:

dr = pd.date_range(start='2020-03-28 05:00:00', periods=500_000, freq='5min')

%timeit dr.tz_localize('Europe/Berlin', nonexistent='NaT', ambiguous='NaT').tz_convert('UTC')
69.5 ms ± 191 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

Сначала UTC. Также обратите внимание, что намного быстрее локализовать наивное значение для UTC и затем преобразовать в другой часовой пояс. При локализации UTC не требуется вычисление летнего времени. изменения и т.д.

dr = pd.date_range(start='2020-03-28 05:00:00', periods=500_000, freq='5min')

%timeit dr.tz_localize('UTC').tz_convert('Europe/Berlin')
173 µs ± 2.51 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Работа со списками. Если вы не работаете со структурами данных pandas или подобными им и должны использовать списки, локализация на UTC, а затем на другой часовой пояс все еще работает (относительно) нормально:

import pytz
l = dr.to_list()

l_utc = list(map(pytz.utc.localize, l))
# %timeit list(map(pytz.utc.localize, l))
# 1.44 s ± 7.72 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

cet = pytz.timezone('Europe/Berlin') # CEST at the moment
l_cet = list(map(lambda t: t.astimezone(cet), l_utc))
# %timeit list(map(lambda t: t.astimezone(cet), l_utc))
# 3.24 s ± 10.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Переход напрямую от наивного к определенному часовому поясу по-прежнему является проблемой с pytz:

%timeit list(map(cet.localize, l))
2min 9s ± 7.31 s per loop (mean ± std. dev. of 7 runs, 1 loop each)

dateutil vs. pytz. Альтернативой здесь может быть использование dateutil — поскольку он использует ту же модель часового пояса, что и Python, вы можете использовать replace():

import dateutil
d_cet = dateutil.tz.gettz('Europe/Berlin')

%timeit [t.replace(tzinfo=d_cet) for t in l]
5.67 s ± 357 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
person MrFuppes    schedule 19.05.2020