Праздник Python3 Panda не может найти даты в произвольных периодах в прошлом - PullRequest
3 голосов
/ 17 мая 2019

Сделано мое собственное определение дня праздника MLK, которое придерживается не того времени, когда праздник впервые наблюдался, а того времени, когда он впервые наблюдался NYSE. NYSE впервые наблюдал день MLK в январе 1998 года.

При запросе выходного дня, в который выходной день наступил между датами, он по большей части работает нормально, возвращая пустой набор, когда дата MLK не находится в запрошенном диапазоне, и возвращая соответствующую дату, когда она есть. Для диапазонов дат, которые предшествуют start_date выходного дня, он соответствующим образом возвращает пустой набор, пока мы не достигнем примерно 1995 года, а затем произойдет сбой. Я не могу понять, почему это терпит неудачу тогда и не в других ситуациях, когда пустой набор - правильный ответ.

Примечание: все еще застрял на Pandas 0.22.0. Python3

import pandas as pd
from datetime import datetime
from dateutil.relativedelta import MO
from pandas.tseries.holiday import Holiday

__author__ = 'eb'

mlk_rule = Holiday('MLK Day (NYSE Observed)',
                   start_date=datetime(1998, 1, 1), month=1, day=1,
                   offset=pd.DateOffset(weekday=MO(3)))

start = pd.to_datetime('1999-01-17')
end = pd.to_datetime('1999-05-01')
finish = pd.to_datetime('1980-01-01')
while start > finish:
    print(f"{start} - {end}:")
    try:
        dates = mlk_rule.dates(start, end, return_name=True)
    except Exception as e:
        print("\t****** Fail *******")
        print(f"\t{e}")
        break
    print(f"\t{dates}")
    start = start - pd.DateOffset(years=1)
    end = end - pd.DateOffset(years=1)

При запуске это приводит к:

1999-01-17 00:00:00 - 1999-05-01 00:00:00:
    1999-01-18    MLK Day (NYSE Observed)
Freq: 52W-MON, dtype: object
1998-01-17 00:00:00 - 1998-05-01 00:00:00:
    1998-01-19    MLK Day (NYSE Observed)
Freq: 52W-MON, dtype: object
1997-01-17 00:00:00 - 1997-05-01 00:00:00:
    Series([], dtype: object)
1996-01-17 00:00:00 - 1996-05-01 00:00:00:
    Series([], dtype: object)
1995-01-17 00:00:00 - 1995-05-01 00:00:00:
    ****** Fail *******
    Must provide freq argument if no data is supplied

Что происходит в 1995 году, что приводит к его провалу, чего не происходит в те же периоды в предыдущие годы?

1 Ответ

0 голосов
/ 23 мая 2019

ОТВЕТ: Внутри класса Holiday метод dates() используется для собрать список действительных праздников в пределах запрашиваемого диапазона дат. В Чтобы убедиться, что это происходит правильно, реализация собирает все праздники от одного года до одного года после запрошенной даты диапазон по внутреннему методу _reference_dates(). В этом методе если получающий экземпляр Holiday имеет внутреннюю дату начала или окончания, эта дата используется в качестве начала или конца исследуемого диапазона вместо того, чтобы передать в запрошенном диапазоне, даже если даты в запрошенном диапазон, предшествующий или превышающий дату начала или окончания правила.

Существующая реализация ошибочно предполагает, что можно ограничить эффективный диапазон, в котором она должна точно определить, какие существуют праздники, диапазоном, в котором существуют праздники. Как часть набора правил в календаре, Holiday так же важно определить, где не существует праздников, как и то, где они существуют. Ответ NULL set является важной функцией класса Holiday.

Например, в Календаре торговых дней , который должен определять, когда финансовые рынки открыты или закрыты, календарю может потребоваться точно определить, в какие дни рынок закрыт за 100-летнюю историю. Рынок закрылся только на день МЛК для небольшой части этой истории. Календарь, который включает праздничные дни MLK, как построено выше, выдает ошибку при запросе дней открытых дверей или праздничных дней для периодов, предшествующих MLK start_date [1].

Чтобы исправить это, я повторно реализовал метод _reference_dates() в Пользовательский подкласс Holiday, чтобы гарантировать, что, когда запрашиваемая дата диапазон расширяется до start_date или после end_date правило праздника, оно использует фактический запрошенный диапазон для построения ссылаться на даты, а не связывать запрос со стороны внутреннего даты начала и окончания.

Вот реализация, которую я использую.

class MLKHoliday(Holiday):

def __init__(self):
    super().__init__('MLK Day (NYSE Observed)',
                     start_date=datetime(1998, 1, 1), month=1, day=1,
                     offset=pd.DateOffset(weekday=MO(3)))

def _reference_dates(self, start_date, end_date):
    """
    Get reference dates for the holiday.

    Return reference dates for the holiday also returning the year
    prior to the start_date and year following the end_date.  This ensures
    that any offsets to be applied will yield the holidays within
    the passed in dates.
    """
    if self.start_date and start_date and start_date >= self.start_date:
        start_date = self.start_date.tz_localize(start_date.tz)

    if self.end_date and end_date and end_date <= self.end_date:
        end_date = self.end_date.tz_localize(end_date.tz)

    year_offset = pd.DateOffset(years=1)
    reference_start_date = pd.Timestamp(
        datetime(start_date.year - 1, self.month, self.day))

    reference_end_date = pd.Timestamp(
        datetime(end_date.year + 1, self.month, self.day))
    # Don't process unnecessary holidays
    dates = pd.DatetimeIndex(start=reference_start_date,
                             end=reference_end_date,
                             freq=year_offset, tz=start_date.tz)
    return dates

Кто-нибудь знает, было ли это исправлено в более новой версии панд?

[1] Примечание. Как было построено в исходном вопросе, mlk_rule фактически не сможет предоставить NULL, установленный для вызова dates(), в диапазоне, предшествующем start_date, но фактически начнет генерировать исключения a год или около того до этого. Это связано с тем, что ошибочное предположение об отсутствии необходимости в правильном ответе набора NULL смягчается расширением диапазона дат на год в каждом направлении на _reference_dates().

...