Векторизация Pandas применения функции для tz_convert - PullRequest
1 голос
/ 20 апреля 2020

У меня есть фрейм данных, в котором столбец hour содержит данные даты и времени в UT C. У меня есть столбец time_zone с часовыми поясами для каждого наблюдения, и я использую его для преобразования hour в местное время и сохранения его в новом столбце с именем local_hour. Для этого я использую следующий код:

import pandas as pd

# Sample dataframe
import pandas as pd
df = pd.DataFrame({
    'hour': ['2019-01-01 05:00:00', '2019-01-01 07:00:00', '2019-01-01 08:00:00'],
    'time_zone': ['US/Eastern', 'US/Central', 'US/Mountain']
})

# Ensure hour is in datetime format and localized to UTC
df['hour'] = pd.to_datetime(df['hour']).dt.tz_localize('UTC')

# Add local_hour column with hour in local time 
df['local_hour'] = df.apply(lambda row: row['hour'].tz_convert(row['time_zone']), axis=1)

df
    hour                        time_zone   local_hour
0   2019-01-01 05:00:00+00:00   US/Eastern  2019-01-01 00:00:00-05:00
1   2019-01-01 07:00:00+00:00   US/Central  2019-01-01 01:00:00-06:00
2   2019-01-01 08:00:00+00:00   US/Mountain 2019-01-01 01:00:00-07:00

Код работает. Однако использование apply работает довольно медленно, поскольку на самом деле у меня большой массив данных. Есть ли способ векторизовать это или иначе ускорить это?

Примечание. Я пытался использовать пакет swifter, но в моем случае он не ускоряется.

1 Ответ

1 голос
/ 20 апреля 2020

Исходя из предположения, что не существует бесконечного количества часовых поясов, возможно, вы могли бы выполнить tz_convert для каждой группы, например:

df['local_hour'] = df.groupby('time_zone')['hour'].apply(lambda x: x.dt.tz_convert(x.name))
print (df)

                       hour    time_zone                 local_hour
0 2019-01-01 05:00:00+00:00   US/Eastern  2019-01-01 00:00:00-05:00
1 2019-01-01 07:00:00+00:00   US/Central  2019-01-01 01:00:00-06:00
2 2019-01-01 08:00:00+00:00  US/Mountain  2019-01-01 01:00:00-07:00

В примере это будет, вероятно, медленнее, чем вы, но для больших данных и групп, должно быть быстрее

Для сравнения скорости, с df из 3-х предоставленных вами строк, это дает:

%timeit df.apply(lambda row: row['hour'].tz_convert(row['time_zone']), axis=1)
# 1.6 ms ± 102 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit df.groupby('time_zone')['hour'].apply(lambda x: x.dt.tz_convert(x.name))
# 2.58 ms ± 126 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

так что apply быстрее, но если вы создаете фрейм данных в 1000 раз больше, но только с 3 часовыми зонами, то вы получаете групповое увеличение примерно в 20 раз:

df = pd.concat([df]*1000, ignore_index=True)

%timeit df.apply(lambda row: row['hour'].tz_convert(row['time_zone']), axis=1)
# 585 ms ± 42.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit df.groupby('time_zone')['hour'].apply(lambda x: x.dt.tz_convert(x.name))
# 27.5 ms ± 2.15 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
...