2016-05-07 8 views
1

pandasを使用すると、毎月の一連の日付を簡単に作成できます。任意の開始日を含む月次時系列の作成

import pandas as pd 

pd.date_range('2012-04-23', '2013-01-23', freq='BM') 

DatetimeIndex(['2012-04-30', '2012-05-31', '2012-06-29', '2012-07-31', 
       '2012-08-31', '2012-09-28', '2012-10-31', '2012-11-30', 
       '2012-12-31'], 
       dtype='datetime64[ns]', freq='BM') 

DatetimeIndexの日付は月の端であることに注意してください。私はそれがfreq='BM'を選んだと考えなければならないことを知っていますが、私は自分の目標を達成したという選択肢があるとは信じていません。

私はしばしば、毎月遡って最後の営業日から始まる月次の一連の日付を作成する必要があります。

私の代わりにこれを見てみたいと思います:

DatetimeIndex(['2012-04-23', '2012-05-23', '2012-06-23', '2012-07-23', 
       '2012-08-23', '2012-09-23', '2012-10-23', '2012-11-23', 
       '2012-12-23'], 
       dtype='datetime64[ns]', freq=None) 

または別のより複雑な例は、「2012-04-30」から「2012-01-30」からヶ月を取得するかもしれませんが。私は見たいと思う:

DatetimeIndex(['2012-01-30', '2012-02-29', '2012-03-30', '2012-04-30'], 
       dtype='datetime64[ns]', freq=None) 
+0

わかりません。あなたが今尋ねたことは、あなたが見たいとは思っていないように見えます。すなわち、一番上のDatetimeIndex *は、その月の最後の営業日です。 – Alexander

+0

@Alexanderこれは私が 'freq'引数として何を入れるべきかわからないことの結果です。私は、デフォルトであると信じている毎日を作り出すことを望まなかった。 – piRSquared

+0

今日は5月6日です(既に?!?...)。 3月6日は日曜日です。何をご覧になりたいですか? 3月4日(金曜日)? – Alexander

答えて

1

from pandas.tseries.offsets import Day, BDay 
pd.date_range(start = '2012-01-01', periods = 6, freq = 'MS') + Day(22) + BDay(0) 
Out[12]: 
DatetimeIndex(['2012-01-23', '2012-02-23', '2012-03-23', '2012-04-23', 
       '2012-05-23', '2012-06-25'], 
       dtype='datetime64[ns]', freq=None) 

Day(22)は(BDay(0)は、最寄りの営業日かかります)22日のオフセットとBDayオフセット営業日を担当して追加します。

30日から始まる日付では少し難しいです。だから私はこれのための関数を書かなければならなかった。 (それはカスタムfreqパラメータを許可しないコードを明確にするため。)

def my_business_date_range(day, **kwargs): 
    assert(isinstance(day, int) & (day > 0) & (day < 32)) 
    rng0 = pd.date_range(freq = 'MS', **kwargs) 
    rng1 = rng0 + pd.tseries.offsets.Day(day-1) + pd.tseries.offsets.BDay(0) 
    # Correcting overflows: 
    overflow_idx, = np.nonzero(rng0.month != rng1.month) 
    if overflow_idx.size > 0: 
     # rng1 is not mutable 
     tmp = rng1.tolist()   
     bme = pd.tseries.offsets.BusinessMonthEnd(-1) 
     for i in overflow_idx: 
      tmp[i] = bme(rng1[i]) 
     rng1 = pd.DatetimeIndex(tmp) 
    return rng1 

my_business_date_range(30, start= '2012-01-01', periods = 6) 
Out[13]: 
DatetimeIndex(['2012-01-30', '2012-02-29', '2012-03-30', '2012-04-30', 
       '2012-05-30', '2012-06-29'], 
       dtype='datetime64[ns]', freq=None) 

パンダはまた、実験CustomBusinessMonth and the likeを持っていますが、私はそれを動作させることができませんでした。

+0

これは素晴らしいことです。興味深い機能に関する多くの良い洞察と参照。努力をいただきありがとうございます。 – piRSquared

+0

ようこそ。お役に立てて嬉しいです。 – ptrj

1

私はあなたの質問にはっきりしていないが、これは正しい方向への動きだと思う。

start = '2012-04-23' 
end = '2013-01-23' 

>>> pd.DatetimeIndex([pd.datetime(ts.year, ts.month, int(end.split("-")[-1])) 
         for ts in pd.date_range(start, end, freq='BM')]) 

DatetimeIndex(['2012-04-23', '2012-05-23', '2012-06-23', '2012-07-23', '2012-08-23', '2012-09-23', '2012-10-23', '2012-11-23', '2012-12-23'], dtype='datetime64[ns]', freq=None) 

スピードには最適化されていませんが、次の関数は要件ごとに正しい値を返します。あなたはこのような何かを探している可能性があり

def foo(date, periods, forward=True): 
    if isinstance(date, str): 
     date = pd.Timestamp(date).date() 
    dates = [date + relativedelta(date, months=n * (1 if forward else -1)) for n in range(1, periods +1)] 
    result = [] 
    print dates 
    for date in dates: 
     month = date.month 
     iso_day = date.isoweekday() 
     if iso_day == 6: 
      date += dt.timedelta(days=2 if forward else -1) 
     elif iso_day == 7: 
      date += dt.timedelta(days=1 if forward else -2) 
     if date.month != month: 
      # Gone into next/preceding month. Roll back/forward. 
      date -= dt.timedelta(days=3 if forward else -3) 
     result.append(date) 
    return result 
+0

これは私がこの例で使用した特定の日付のセットに対しては間違いなく機能します。私は既に畳み込まれた堅牢なソリューションを持っています。私は他の意見を募集したいので、よりきれいな回答が得られるかもしれません。私は私の質問で追加のコメントをフォローアップします。 – piRSquared

+1

'BM'は期間の有効なオプションではありません。今日が2016-6-01(Weds)だったらどうなりますか? 2016-05-01は日曜日ですので、2016-04-28(金曜日)を見たいですか? http://pandas.pydata.org/pandas-docs/stable/timeseries.html#anchored-offsets – Alexander

+0

これは良い質問です。私は2016-05-02を選択しなければならないでしょう。 – piRSquared

関連する問題