シーズンを取得する方法と、日付範囲がパンダとの米国の休日に該当する場合はどうなりますか?

Aug 22 2020

date_xとdate_yという名前の2つの列を持つパンダデータフレームがあります。date_xの季節(冬、春、夏、または秋)を別の列に表示して、date_yを除く日付の範囲で休日が該当するかどうかを確認したいと思います。1年を数日に分割することで季節を変えたいくつかの潜在的な解決策を見てきましたが、それをうまく機能させることができないようです。私はまだパンダが何ができるかを考えています。私が直面しているもう1つの問題は、毎年変わるイースターのような休日をどのように説明するかです。どんな助けでも本当にありがたいです。

私もこのソリューションを機能させるために遊んだことがありますが、今日の日付ではなくdate_xで機能する新しい列を作成するためにそれを適応させる方法を理解できません

以下は私が目指していることのイメージです。

回答

1 DavidErickson Aug 22 2020 at 13:48

複数の休日に及ぶだけでなく、複数の季節に及ぶ日付のデータフレームがあるとします。

        Date_x      Date_y
0   2020-12-22  2021-01-01
1   2020-06-20  2020-07-11
3   2020-02-11  2020-03-27
4   2020-05-22  2020-06-27

1.Seasonと2を取得するためにHoliday

  1. 季節をカスタマイズするためにあなたが共有したリンクを構築しました
  2. 私は「サードパーティ」ライブラリを避けようとしUSFederalHolidayCalendarpandas holidayライブラリからを使用することを選択しました。なぜなら、それがより信頼できると思ったからです。しかし、私は休日の図書館についてはあまり経験がありません。また、calendarsパンダライブラリから使用できるものは複数あります。そこから、作成したget_season(x)andget_holiday()関数を使用しました。前者については、質問のリンクを参照し、後者については、リスト内包表記を使用して、作成したholidaysデータフレームからデータフレームに休日を取り込みます。

from pandas.tseries.holiday import USFederalHolidayCalendar
from datetime import datetime
import pandas as pd

cal = USFederalHolidayCalendar()
holidays = (pd.DataFrame(cal.holidays(return_name=True), columns=['Holiday'])
            .reset_index()
            .rename({'index': 'Date'}, axis=1))
holidays['Date'] = pd.to_datetime(holidays['Date'])
df= pd.DataFrame({'Date_x': {0: '2020-12-22', 1: '2020-06-20', 2: '2020-02-11', 3: '2020-05-22'},
                  'Date_y': {0: '2021-01-01', 1: '2020-07-11', 2: '2020-03-27', 3: '2020-06-27'}})
df['Date_x'] = pd.to_datetime(df['Date_x'])
df['Date_y'] = pd.to_datetime(df['Date_y'])

Y = 2000 # dummy leap year to allow input X-02-29 (leap day)
seasons = [('Winter', (date(Y,  1,  1),  date(Y,  3, 20))),
           ('Spring', (date(Y,  3, 21),  date(Y,  6, 20))),
           ('Summer', (date(Y,  6, 21),  date(Y,  9, 22))),
           ('Fall', (date(Y,  9, 23),  date(Y, 12, 20))),
           ('Winter', (date(Y, 12, 21),  date(Y, 12, 31)))]

def get_season(x):
    x = x.replace(year=Y)
    return next(season for season, (start, end) in seasons
                if start <= x <= end)


def get_holiday():
    return pd.DataFrame([(h,y,z) for (h,d) in zip(holidays['Holiday'], holidays['Date'])
     for (y, z) in zip(df['Date_x'], df['Date_y']) if y.date() <= d.date() if d.date() <= z.date()], columns=['Holiday', 'Date_x', 'Date_y'])


s1 = df['Date_x'].apply(lambda x: get_season(x))
s2 = df['Date_y'].apply(lambda x: get_season(x))
df['Season']= [', '.join(list(set([x,y]))) for (x,y) in zip(s1,s2)]
dft = get_holiday()
dft = dft.groupby(['Date_x', 'Date_y'])['Holiday'].apply(lambda x: ', '.join(list(x)))
df = pd.merge(df, dft, how='left', on=['Date_x', 'Date_y'])
df

Out[32]: 
      Date_x     Date_y            Season                     Holiday
0 2020-12-22 2021-01-01            Winter    Christmas, New Years Day
1 2020-06-20 2020-07-11    Summer, Spring                    July 4th
2 2020-02-11 2020-03-27    Spring, Winter              Presidents Day
3 2020-05-22 2020-06-27    Summer, Spring                Memorial Day
2 kerasbaz Aug 22 2020 at 12:18

以下のようなものをお探しだと思います。このソリューションの一部では、ここで提供される回答を使用していることに注意してください。

あなたはあなたの排他的な要件を説明するために調整しなければならないかもしれません、しかしこれはあなたに考えを与えます。

import pandas as pd
import numpy as np

import holidays # pip install holidays

from datetime import date, datetime

us_holidays = holidays.UnitedStates()

Y = 2000 # dummy leap year to allow input X-02-29 (leap day)
seasons = [('winter', (date(Y,  1,  1),  date(Y,  3, 20))),
           ('spring', (date(Y,  3, 21),  date(Y,  6, 20))),
           ('summer', (date(Y,  6, 21),  date(Y,  9, 22))),
           ('autumn', (date(Y,  9, 23),  date(Y, 12, 20))),
           ('winter', (date(Y, 12, 21),  date(Y, 12, 31)))]

def get_season(dt):
    if isinstance(dt, datetime):
        dt = dt.date()
    dt = dt.replace(year=Y)
    return next(season for season, (start, end) in seasons
                if start <= dt <= end)

def get_holiday(data):
    return ",".join([us_holidays.get(x) for x in us_holidays[data["Date_X"] : data["Date_Y"]]])

np.random.seed(0)
rng_x = pd.date_range('2020-12-22', periods=365, freq='D')
rng_y = pd.date_range('2020-12-26', periods=365, freq='D')

df = pd.DataFrame({ 'Date_X': rng_x, 'Season_X': "", 'Date_Y': rng_y, 'Season_Y': ""}) 
print(df.head())

df['Season_X'] = df["Date_X"].apply(get_season)
df['Season_Y'] = df["Date_Y"].apply(get_season)
print(df.head())

df['Holiday'] = df.apply(get_holiday, axis=1)
print(df.head())

出力:

      Date_X Season_X     Date_Y Season_Y        Holiday
0 2020-12-22   winter 2020-12-26   winter  Christmas Day
1 2020-12-23   winter 2020-12-27   winter  Christmas Day
2 2020-12-24   winter 2020-12-28   winter  Christmas Day
3 2020-12-25   winter 2020-12-29   winter  Christmas Day
4 2020-12-26   winter 2020-12-30   winter
1 JohnZwinck Aug 22 2020 at 12:19

列を日時型に変換し(まだ変換されていない場合)、2つの新しい空の列を作成します。

df.Date_x = pd.to_datetime(df.Date_x)
df.Date_y = pd.to_datetime(df.Date_y)

quarterdatetime Seriesの属性に気づいたら、Season列の追加は簡単です。

df['Season'] = df.Date_x.dt.quarter.map({1: 'Spring', 2: 'Summer', 3: 'Fall', 4: 'Winter'})

休日は明らかにもう少し複雑です。空の列から始めます。

df['Holiday'] = ''

イースターは特別なものです。最初にそれを処理しましょう。Pandasにはそれが組み込まれていますが、独自の休日ルールを定義することもできます。

easter = df.Date_y - pd.tseries.offsets.Easter()

それはあなたに以前のイースターを与えますDate_y(私は使うことができましたがDate_x + Easter()、あなたはそれを排他的にしたいと言いましたDate_y)。次に:

df.loc[df.Date_x < easter, 'Holiday'] = 'Easter'

これにより、休日が含まれる行に「イースター」が配置されます[Date_x, Date_y)

残りの休日の休日ルールを作成するための演習として残しておきます。それに関するいくつかのアドバイスがあります:パンダ時系列ホリデールールオフセット