Флаг перехода на летнее время (DST) в столбцах даты и времени Pandas - PullRequest
0 голосов
/ 23 сентября 2018

Я создал ежечасный фрейм данных дат, и теперь я хотел бы создать столбец, который будет отмечать, находится ли каждая строка (час) в летнем времени или нет.Например, в летние часы флаг должен == 1, а в зимние часы флаг должен == 0.

# Localized dates dataframe
dates = pd.DataFrame(data=pd.date_range('2018-1-1', '2019-1-1', freq='h', tz='America/Denver'), columns=['date_time'])

# My failed attempt to create the flag column
dates['dst_flag'] = np.where(dates['date_time'].dt.daylight_saving_time == True, 1, 0)

Ответы [ 2 ]

0 голосов
/ 24 сентября 2018

Вот что я в итоге сделал, и это работает для моих целей:

import pandas as pd
import pytz

# Create dates table and flag Daylight Saving Time dates
dates = pd.DataFrame(data=pd.date_range('2018-1-1', '2018-12-31-23', freq='h'), columns=['date_time'])

# Create a list of start and end dates for DST in each year, in UTC time
dst_changes_utc = pytz.timezone('America/Denver')._utc_transition_times[1:]

# Convert to local times from UTC times and then remove timezone information
dst_changes = [pd.Timestamp(i).tz_localize('UTC').tz_convert('America/Denver').tz_localize(None) for i in dst_changes_utc]

flag_list = []
for index, row in dates['date_time'].iteritems():
    # Isolate the start and end dates for DST in each year
    dst_dates_in_year = [date for date in dst_changes if date.year == row.year]
    spring = dst_dates_in_year[0]
    fall = dst_dates_in_year[1]
    if (row >= spring) & (row < fall):
        flag = 1
    else:
        flag = 0
    flag_list.append(flag)
print(flag_list)
dates['dst_flag'] = flag_list
del(flag_list)
0 голосов
/ 23 сентября 2018

В комментариях есть хорошая ссылка, по крайней мере, позволяющая сделать это вручную.AFAIK, нет векторизованного способа сделать это.

import pandas as pd
import numpy as np
from pytz import timezone

# Generate data (as opposed to index)                                                                                                                                                                                  
date_range = pd.to_datetime(pd.date_range('1/1/2018', '1/1/2019', freq='h', tz='America/Denver'))
date_range = [date for date in date_range]

# Localized dates dataframe                                                                                                                                                           
df = pd.DataFrame(data=date_range, columns=['date_time'])

# Map transition times to year for some efficiency gain                                                                                                                                                     
tz = timezone('America/Denver')
transition_times = tz._utc_transition_times[1:]
transition_times = [t.astimezone(tz) for t in transition_times]
transition_times_by_year = {}
for start_time, stop_time in zip(transition_times[::2], transition_times[1::2]):
    year = start_time.year
    transition_times_by_year[year] = [start_time, stop_time]

# If the date is in DST, mark true, else false                                                                                                                                                              
def mark_dst(dates):
    for date in dates:
        start_dst, stop_dst = transition_times_by_year[date.year]
        yield start_dst <= date <= stop_dst
df['dst_flag'] = [dst_flag for dst_flag in mark_dst(df['date_time'])]

# Do a quick sanity check to make sure we did this correctly for year 2018                                                                                                                                  
dst_start = df[df['dst_flag'] == True]['date_time'][0] # First dst time 2018
dst_end = df[df['dst_flag'] == True]['date_time'][-1] # Last dst time 2018
print(dst_start)
print(dst_end)

это выводит:

2018-03-11 07:00:00-06:00
2018-11-04 06:00:00-07:00

, что вероятно правильно.Я не делал UTC-преобразования вручную или что-либо, чтобы проверить, что часы точно соответствуют данному часовому поясу.Вы можете, по крайней мере, проверить правильность дат с помощью быстрого поиска в Google.

Некоторые ошибки:

  1. pd.date_range создает индекс , а неданные.Я немного изменил ваш исходный код, чтобы он стал данными, а не индексом.Я предполагаю, что у вас уже есть данные.

  2. Что-то глупое в том, как структурирована tz._utc_transition_times.Это время начала / остановки utc перехода на летнее время, но в ранние даты есть кое-что глупое.Это должно быть хорошо с 1965 года, хотя.Если вы делаете даты раньше, измените значение tz._utc_transition_times[1:] на tz._utc_transition_times.Обратите внимание, что присутствуют не все годы до 1965 года.

  3. tz._utc_transition_times - это "Python private".Он может быть изменен без предупреждения или уведомления и может работать, а может и не работать для будущих или прошлых версий pytz.Я использую pytz verion 2017.3.Я рекомендую вам запустить этот код, чтобы убедиться, что выходные данные совпадают, и если нет, обязательно используйте версию 2017.3.

HTH, удачи вам в вашей проблеме исследования / регрессии!

...