時系列 / 日付機能#

pandasは、あらゆる分野の時系列データを扱うための豊富な機能と特徴を備えています。NumPyのdatetime64およびtimedelta64のdtypeを使用することで、pandasはscikits.timeseriesのような他のPythonライブラリの多数の機能を取り込み、時系列データを操作するための非常に多くの新しい機能を作成しました。

例えば、pandasは以下をサポートしています。

さまざまなソースやフォーマットからの時系列情報の解析

In [1]: import datetime

In [2]: dti = pd.to_datetime(
   ...:     ["1/1/2018", np.datetime64("2018-01-01"), datetime.datetime(2018, 1, 1)]
   ...: )
   ...: 

In [3]: dti
Out[3]: DatetimeIndex(['2018-01-01', '2018-01-01', '2018-01-01'], dtype='datetime64[ns]', freq=None)

固定頻度の日付と時間スパンのシーケンスの生成

In [4]: dti = pd.date_range("2018-01-01", periods=3, freq="h")

In [5]: dti
Out[5]: 
DatetimeIndex(['2018-01-01 00:00:00', '2018-01-01 01:00:00',
               '2018-01-01 02:00:00'],
              dtype='datetime64[ns]', freq='h')

タイムゾーン情報を持つ日時データの操作と変換

In [6]: dti = dti.tz_localize("UTC")

In [7]: dti
Out[7]: 
DatetimeIndex(['2018-01-01 00:00:00+00:00', '2018-01-01 01:00:00+00:00',
               '2018-01-01 02:00:00+00:00'],
              dtype='datetime64[ns, UTC]', freq='h')

In [8]: dti.tz_convert("US/Pacific")
Out[8]: 
DatetimeIndex(['2017-12-31 16:00:00-08:00', '2017-12-31 17:00:00-08:00',
               '2017-12-31 18:00:00-08:00'],
              dtype='datetime64[ns, US/Pacific]', freq='h')

特定の頻度への時系列のリサンプリングまたは変換

In [9]: idx = pd.date_range("2018-01-01", periods=5, freq="h")

In [10]: ts = pd.Series(range(len(idx)), index=idx)

In [11]: ts
Out[11]: 
2018-01-01 00:00:00    0
2018-01-01 01:00:00    1
2018-01-01 02:00:00    2
2018-01-01 03:00:00    3
2018-01-01 04:00:00    4
Freq: h, dtype: int64

In [12]: ts.resample("2h").mean()
Out[12]: 
2018-01-01 00:00:00    0.5
2018-01-01 02:00:00    2.5
2018-01-01 04:00:00    4.0
Freq: 2h, dtype: float64

絶対または相対的な時間増分を使用した日付と時間の算術演算の実行

In [13]: friday = pd.Timestamp("2018-01-05")

In [14]: friday.day_name()
Out[14]: 'Friday'

# Add 1 day
In [15]: saturday = friday + pd.Timedelta("1 day")

In [16]: saturday.day_name()
Out[16]: 'Saturday'

# Add 1 business day (Friday --> Monday)
In [17]: monday = friday + pd.offsets.BDay()

In [18]: monday.day_name()
Out[18]: 'Monday'

pandasは、上記のタスクなどを実行するための比較的コンパクトで自己完結的なツールセットを提供します。

概要#

pandasは、時間に関する4つの一般的な概念を捉えています。

  1. 日時: タイムゾーンをサポートする特定の日時。標準ライブラリのdatetime.datetimeに類似しています。

  2. 時間差: 絶対的な時間間隔。標準ライブラリのdatetime.timedeltaに類似しています。

  3. 時間スパン: 時点とそれに関連する頻度によって定義される時間のスパン。

  4. 日付オフセット: カレンダー演算を考慮する相対的な時間間隔。 dateutilパッケージのdateutil.relativedelta.relativedeltaに類似しています。

概念

スカラークラス

配列クラス

pandasのデータ型

主な作成方法

日時

Timestamp

DatetimeIndex

datetime64[ns] または datetime64[ns, tz]

to_datetime または date_range

時間差

時間差

TimedeltaIndex

timedelta64[ns]

to_timedelta または timedelta_range

時間スパン

Period

PeriodIndex

period[freq]

Period または period_range

日付オフセット

DateOffset

None

None

DateOffset

時系列データの場合、SeriesまたはDataFrameのインデックスに時間コンポーネントを表現するのが一般的で、時間要素に関して操作を実行できます。

In [19]: pd.Series(range(3), index=pd.date_range("2000", freq="D", periods=3))
Out[19]: 
2000-01-01    0
2000-01-02    1
2000-01-03    2
Freq: D, dtype: int64

ただし、SeriesDataFrameは、時間コンポーネントをデータ自体としても直接サポートできます。

In [20]: pd.Series(pd.date_range("2000", freq="D", periods=3))
Out[20]: 
0   2000-01-01
1   2000-01-02
2   2000-01-03
dtype: datetime64[ns]

SeriesDataFrameは、これらのコンストラクタに渡された場合に、datetimetimedelta、およびPeriodデータに対する拡張されたデータ型サポートと機能を持っています。ただし、DateOffsetデータはobjectデータとして保存されます。

In [21]: pd.Series(pd.period_range("1/1/2011", freq="M", periods=3))
Out[21]: 
0    2011-01
1    2011-02
2    2011-03
dtype: period[M]

In [22]: pd.Series([pd.DateOffset(1), pd.DateOffset(2)])
Out[22]: 
0         <DateOffset>
1    <2 * DateOffsets>
dtype: object

In [23]: pd.Series(pd.date_range("1/1/2011", freq="ME", periods=3))
Out[23]: 
0   2011-01-31
1   2011-02-28
2   2011-03-31
dtype: datetime64[ns]

最後に、pandasは、欠損またはnullの日付のような値を表現するのに役立ち、floatデータに対するnp.nanと同様に動作するnullの日時、時間差、および時間スパンをNaTとして表現します。

In [24]: pd.Timestamp(pd.NaT)
Out[24]: NaT

In [25]: pd.Timedelta(pd.NaT)
Out[25]: NaT

In [26]: pd.Period(pd.NaT)
Out[26]: NaT

# Equality acts as np.nan would
In [27]: pd.NaT == pd.NaT
Out[27]: False

タイムスタンプと時間スパン#

タイムスタンプ付きデータは、時間内のポイントと値を関連付ける最も基本的な時系列データの型です。pandasオブジェクトの場合、それは時間内のポイントを使用することを意味します。

In [28]: import datetime

In [29]: pd.Timestamp(datetime.datetime(2012, 5, 1))
Out[29]: Timestamp('2012-05-01 00:00:00')

In [30]: pd.Timestamp("2012-05-01")
Out[30]: Timestamp('2012-05-01 00:00:00')

In [31]: pd.Timestamp(2012, 5, 1)
Out[31]: Timestamp('2012-05-01 00:00:00')

ただし、多くの場合、変化変数のようなものを時間スパンに関連付ける方がより自然です。Periodで表されるスパンは、明示的に指定するか、日時文字列形式から推測できます。

例えば

In [32]: pd.Period("2011-01")
Out[32]: Period('2011-01', 'M')

In [33]: pd.Period("2012-05", freq="D")
Out[33]: Period('2012-05-01', 'D')

TimestampPeriodはインデックスとして機能できます。TimestampPeriodのリストは、それぞれDatetimeIndexPeriodIndexに自動的に強制変換されます。

In [34]: dates = [
   ....:     pd.Timestamp("2012-05-01"),
   ....:     pd.Timestamp("2012-05-02"),
   ....:     pd.Timestamp("2012-05-03"),
   ....: ]
   ....: 

In [35]: ts = pd.Series(np.random.randn(3), dates)

In [36]: type(ts.index)
Out[36]: pandas.core.indexes.datetimes.DatetimeIndex

In [37]: ts.index
Out[37]: DatetimeIndex(['2012-05-01', '2012-05-02', '2012-05-03'], dtype='datetime64[ns]', freq=None)

In [38]: ts
Out[38]: 
2012-05-01    0.469112
2012-05-02   -0.282863
2012-05-03   -1.509059
dtype: float64

In [39]: periods = [pd.Period("2012-01"), pd.Period("2012-02"), pd.Period("2012-03")]

In [40]: ts = pd.Series(np.random.randn(3), periods)

In [41]: type(ts.index)
Out[41]: pandas.core.indexes.period.PeriodIndex

In [42]: ts.index
Out[42]: PeriodIndex(['2012-01', '2012-02', '2012-03'], dtype='period[M]')

In [43]: ts
Out[43]: 
2012-01   -1.135632
2012-02    1.212112
2012-03   -0.173215
Freq: M, dtype: float64

pandasを使用すると、両方の表現を捉え、それらの間で変換することができます。内部的には、pandasはTimestampのインスタンスを使用してタイムスタンプを表し、DatetimeIndexのインスタンスを使用してタイムスタンプのシーケンスを表します。定期的な時間スパンの場合、pandasはスカラー値にPeriodオブジェクトを使用し、スパンのシーケンスにPeriodIndexを使用します。任意開始点と終了点を持つ不規則な間隔のサポートは、今後のリリースで提供される予定です。

タイムスタンプへの変換#

Seriesまたは日付のようなオブジェクト(文字列、エポック、または混合など)のリストのようなオブジェクトを変換するには、to_datetime関数を使用できます。Seriesを渡すと、これはSeries(同じインデックスを持つ)を返し、リストのようなオブジェクトはDatetimeIndexに変換されます

In [44]: pd.to_datetime(pd.Series(["Jul 31, 2009", "Jan 10, 2010", None]))
Out[44]: 
0   2009-07-31
1   2010-01-10
2          NaT
dtype: datetime64[ns]

In [45]: pd.to_datetime(["2005/11/23", "2010/12/31"])
Out[45]: DatetimeIndex(['2005-11-23', '2010-12-31'], dtype='datetime64[ns]', freq=None)

最初が日付である(つまり、ヨーロッパスタイル)日付を使用する場合、dayfirstフラグを渡すことができます。

In [46]: pd.to_datetime(["04-01-2012 10:00"], dayfirst=True)
Out[46]: DatetimeIndex(['2012-01-04 10:00:00'], dtype='datetime64[ns]', freq=None)

In [47]: pd.to_datetime(["04-14-2012 10:00"], dayfirst=True)
Out[47]: DatetimeIndex(['2012-04-14 10:00:00'], dtype='datetime64[ns]', freq=None)

警告

上記の例では、dayfirstが厳密でないことがわかります。日付が最初の日として解析できない場合、dayfirstFalseであるかのように解析され、警告も発生します。

単一の文字列をto_datetimeに渡すと、単一のTimestampが返されます。Timestampも文字列入力を受け入れることができますが、dayfirstformatのような文字列解析オプションは受け入れないため、これらが必要な場合はto_datetimeを使用してください。

In [48]: pd.to_datetime("2010/11/12")
Out[48]: Timestamp('2010-11-12 00:00:00')

In [49]: pd.Timestamp("2010/11/12")
Out[49]: Timestamp('2010-11-12 00:00:00')

DatetimeIndexコンストラクタを直接使用することもできます

In [50]: pd.DatetimeIndex(["2018-01-01", "2018-01-03", "2018-01-05"])
Out[50]: DatetimeIndex(['2018-01-01', '2018-01-03', '2018-01-05'], dtype='datetime64[ns]', freq=None)

インデックスの頻度を作成時に推測された頻度として設定するために、文字列'infer'を渡すことができます

In [51]: pd.DatetimeIndex(["2018-01-01", "2018-01-03", "2018-01-05"], freq="infer")
Out[51]: DatetimeIndex(['2018-01-01', '2018-01-03', '2018-01-05'], dtype='datetime64[ns]', freq='2D')

format引数の提供#

必須の日時文字列に加えて、特定の解析を保証するためにformat引数を渡すことができます。これにより、変換を大幅に高速化することもできます。

In [52]: pd.to_datetime("2010/11/12", format="%Y/%m/%d")
Out[52]: Timestamp('2010-11-12 00:00:00')

In [53]: pd.to_datetime("12-11-2010 00:00", format="%d-%m-%Y %H:%M")
Out[53]: Timestamp('2010-11-12 00:00:00')

formatオプションを指定するときに利用できる選択肢の詳細については、Pythonのdatetimeドキュメントを参照してください。

複数のDataFrame列から日時を組み立てる#

整数または文字列の列のDataFrameを渡して、TimestampsSeriesに組み立てることもできます。

In [54]: df = pd.DataFrame(
   ....:     {"year": [2015, 2016], "month": [2, 3], "day": [4, 5], "hour": [2, 3]}
   ....: )
   ....: 

In [55]: pd.to_datetime(df)
Out[55]: 
0   2015-02-04 02:00:00
1   2016-03-05 03:00:00
dtype: datetime64[ns]

組み立てに必要な列のみを渡すことができます。

In [56]: pd.to_datetime(df[["year", "month", "day"]])
Out[56]: 
0   2015-02-04
1   2016-03-05
dtype: datetime64[ns]

pd.to_datetime は、列名に含まれる日時コンポーネントの標準的な指定を検索します。これには以下が含まれます。

  • 必須: year, month, day

  • オプション: hour, minute, second, millisecond, microsecond, nanosecond

無効なデータ#

デフォルトの動作 errors='raise' では、解析できない場合に例外が発生します。

In [57]: pd.to_datetime(['2009/07/31', 'asd'], errors='raise')
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[57], line 1
----> 1 pd.to_datetime(['2009/07/31', 'asd'], errors='raise')

File ~/work/pandas/pandas/pandas/core/tools/datetimes.py:1099, in to_datetime(arg, errors, dayfirst, yearfirst, utc, format, exact, unit, infer_datetime_format, origin, cache)
   1097         result = _convert_and_box_cache(argc, cache_array)
   1098     else:
-> 1099         result = convert_listlike(argc, format)
   1100 else:
   1101     result = convert_listlike(np.array([arg]), format)[0]

File ~/work/pandas/pandas/pandas/core/tools/datetimes.py:433, in _convert_listlike_datetimes(arg, format, name, utc, unit, errors, dayfirst, yearfirst, exact)
    431 # `format` could be inferred, or user didn't ask for mixed-format parsing.
    432 if format is not None and format != "mixed":
--> 433     return _array_strptime_with_fallback(arg, name, utc, format, exact, errors)
    435 result, tz_parsed = objects_to_datetime64(
    436     arg,
    437     dayfirst=dayfirst,
   (...)
    441     allow_object=True,
    442 )
    444 if tz_parsed is not None:
    445     # We can take a shortcut since the datetime64 numpy array
    446     # is in UTC

File ~/work/pandas/pandas/pandas/core/tools/datetimes.py:467, in _array_strptime_with_fallback(arg, name, utc, fmt, exact, errors)
    456 def _array_strptime_with_fallback(
    457     arg,
    458     name,
   (...)
    462     errors: str,
    463 ) -> Index:
    464     """
    465     Call array_strptime, with fallback behavior depending on 'errors'.
    466     """
--> 467     result, tz_out = array_strptime(arg, fmt, exact=exact, errors=errors, utc=utc)
    468     if tz_out is not None:
    469         unit = np.datetime_data(result.dtype)[0]

File strptime.pyx:501, in pandas._libs.tslibs.strptime.array_strptime()

File strptime.pyx:451, in pandas._libs.tslibs.strptime.array_strptime()

File strptime.pyx:583, in pandas._libs.tslibs.strptime._parse_with_format()

ValueError: time data "asd" doesn't match format "%Y/%m/%d", at position 1. You might want to try:
    - passing `format` if your strings have a consistent format;
    - passing `format='ISO8601'` if your strings are all ISO8601 but not necessarily in exactly the same format;
    - passing `format='mixed'`, and the format will be inferred for each element individually. You might want to use `dayfirst` alongside this.

errors='coerce' を渡すと、解析できないデータは NaT (not a time) に変換されます。

In [58]: pd.to_datetime(["2009/07/31", "asd"], errors="coerce")
Out[58]: DatetimeIndex(['2009-07-31', 'NaT'], dtype='datetime64[ns]', freq=None)

エポックタイムスタンプ#

pandasは、整数または浮動小数点のエポック時間を Timestamp および DatetimeIndex に変換することをサポートしています。デフォルトの単位はナノ秒です。これは、Timestamp オブジェクトが内部的に格納される方法であるためです。ただし、エポックは多くの場合、別の unit で格納され、これを指定できます。これらは、origin パラメータで指定された開始点から計算されます。

In [59]: pd.to_datetime(
   ....:     [1349720105, 1349806505, 1349892905, 1349979305, 1350065705], unit="s"
   ....: )
   ....: 
Out[59]: 
DatetimeIndex(['2012-10-08 18:15:05', '2012-10-09 18:15:05',
               '2012-10-10 18:15:05', '2012-10-11 18:15:05',
               '2012-10-12 18:15:05'],
              dtype='datetime64[ns]', freq=None)

In [60]: pd.to_datetime(
   ....:     [1349720105100, 1349720105200, 1349720105300, 1349720105400, 1349720105500],
   ....:     unit="ms",
   ....: )
   ....: 
Out[60]: 
DatetimeIndex(['2012-10-08 18:15:05.100000', '2012-10-08 18:15:05.200000',
               '2012-10-08 18:15:05.300000', '2012-10-08 18:15:05.400000',
               '2012-10-08 18:15:05.500000'],
              dtype='datetime64[ns]', freq=None)

注意

unit パラメータは、上記 で説明した format パラメータと同じ文字列を使用しません。使用可能な単位は、pandas.to_datetime() のドキュメントに記載されています。

tz 引数を指定してエポックタイムスタンプで Timestamp または DatetimeIndex を構築すると、ValueErrorが発生します。別のタイムゾーンの壁時間でエポックがある場合は、エポックをタイムゾーンを認識しないタイムスタンプとして読み取り、適切なタイムゾーンにローカライズできます。

In [61]: pd.Timestamp(1262347200000000000).tz_localize("US/Pacific")
Out[61]: Timestamp('2010-01-01 12:00:00-0800', tz='US/Pacific')

In [62]: pd.DatetimeIndex([1262347200000000000]).tz_localize("US/Pacific")
Out[62]: DatetimeIndex(['2010-01-01 12:00:00-08:00'], dtype='datetime64[ns, US/Pacific]', freq=None)

注意

エポック時間は、最も近いナノ秒に丸められます。

警告

浮動小数点のエポック時間の変換は、不正確で予期しない結果につながる可能性があります。Pythonの浮動小数点数 は、10進数で約15桁の精度を持っています。浮動小数点数から高精度の Timestamp への変換中に丸めは避けられません。正確な精度を実現する唯一の方法は、固定幅の型 (例: int64) を使用することです。

In [63]: pd.to_datetime([1490195805.433, 1490195805.433502912], unit="s")
Out[63]: DatetimeIndex(['2017-03-22 15:16:45.433000088', '2017-03-22 15:16:45.433502913'], dtype='datetime64[ns]', freq=None)

In [64]: pd.to_datetime(1490195805433502912, unit="ns")
Out[64]: Timestamp('2017-03-22 15:16:45.433502912')

タイムスタンプからエポックへ#

上記の操作、つまり、Timestamp から「unix」エポックに変換するには

In [65]: stamps = pd.date_range("2012-10-08 18:15:05", periods=4, freq="D")

In [66]: stamps
Out[66]: 
DatetimeIndex(['2012-10-08 18:15:05', '2012-10-09 18:15:05',
               '2012-10-10 18:15:05', '2012-10-11 18:15:05'],
              dtype='datetime64[ns]', freq='D')

エポック(1970年1月1日UTCの午前0時)を減算し、「unit」(1秒)で切り捨て除算します。

In [67]: (stamps - pd.Timestamp("1970-01-01")) // pd.Timedelta("1s")
Out[67]: Index([1349720105, 1349806505, 1349892905, 1349979305], dtype='int64')

origin パラメータの使用#

origin パラメータを使用すると、DatetimeIndex の作成の代替開始点を指定できます。たとえば、1960-01-01を開始日として使用するには

In [68]: pd.to_datetime([1, 2, 3], unit="D", origin=pd.Timestamp("1960-01-01"))
Out[68]: DatetimeIndex(['1960-01-02', '1960-01-03', '1960-01-04'], dtype='datetime64[ns]', freq=None)

デフォルトは origin='unix' に設定されており、これは 1970-01-01 00:00:00 にデフォルト設定されています。一般的に「unix エポック」または POSIX 時間と呼ばれます。

In [69]: pd.to_datetime([1, 2, 3], unit="D")
Out[69]: DatetimeIndex(['1970-01-02', '1970-01-03', '1970-01-04'], dtype='datetime64[ns]', freq=None)

タイムスタンプの範囲の生成#

タイムスタンプ付きのインデックスを生成するには、DatetimeIndex または Index コンストラクタを使用し、datetimeオブジェクトのリストを渡すことができます。

In [70]: dates = [
   ....:     datetime.datetime(2012, 5, 1),
   ....:     datetime.datetime(2012, 5, 2),
   ....:     datetime.datetime(2012, 5, 3),
   ....: ]
   ....: 

# Note the frequency information
In [71]: index = pd.DatetimeIndex(dates)

In [72]: index
Out[72]: DatetimeIndex(['2012-05-01', '2012-05-02', '2012-05-03'], dtype='datetime64[ns]', freq=None)

# Automatically converted to DatetimeIndex
In [73]: index = pd.Index(dates)

In [74]: index
Out[74]: DatetimeIndex(['2012-05-01', '2012-05-02', '2012-05-03'], dtype='datetime64[ns]', freq=None)

実際には、多数のタイムスタンプを含む非常に長いインデックスが必要になることが多いため、これは非常に面倒になります。一定の頻度でタイムスタンプが必要な場合は、date_range() 関数と bdate_range() 関数を使用して DatetimeIndex を作成できます。date_range のデフォルトの頻度は **カレンダー日** であり、bdate_range のデフォルトは **営業日** です。

In [75]: start = datetime.datetime(2011, 1, 1)

In [76]: end = datetime.datetime(2012, 1, 1)

In [77]: index = pd.date_range(start, end)

In [78]: index
Out[78]: 
DatetimeIndex(['2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04',
               '2011-01-05', '2011-01-06', '2011-01-07', '2011-01-08',
               '2011-01-09', '2011-01-10',
               ...
               '2011-12-23', '2011-12-24', '2011-12-25', '2011-12-26',
               '2011-12-27', '2011-12-28', '2011-12-29', '2011-12-30',
               '2011-12-31', '2012-01-01'],
              dtype='datetime64[ns]', length=366, freq='D')

In [79]: index = pd.bdate_range(start, end)

In [80]: index
Out[80]: 
DatetimeIndex(['2011-01-03', '2011-01-04', '2011-01-05', '2011-01-06',
               '2011-01-07', '2011-01-10', '2011-01-11', '2011-01-12',
               '2011-01-13', '2011-01-14',
               ...
               '2011-12-19', '2011-12-20', '2011-12-21', '2011-12-22',
               '2011-12-23', '2011-12-26', '2011-12-27', '2011-12-28',
               '2011-12-29', '2011-12-30'],
              dtype='datetime64[ns]', length=260, freq='B')

date_rangebdate_range のような便利な関数は、さまざまな 頻度エイリアス を利用できます。

In [81]: pd.date_range(start, periods=1000, freq="ME")
Out[81]: 
DatetimeIndex(['2011-01-31', '2011-02-28', '2011-03-31', '2011-04-30',
               '2011-05-31', '2011-06-30', '2011-07-31', '2011-08-31',
               '2011-09-30', '2011-10-31',
               ...
               '2093-07-31', '2093-08-31', '2093-09-30', '2093-10-31',
               '2093-11-30', '2093-12-31', '2094-01-31', '2094-02-28',
               '2094-03-31', '2094-04-30'],
              dtype='datetime64[ns]', length=1000, freq='ME')

In [82]: pd.bdate_range(start, periods=250, freq="BQS")
Out[82]: 
DatetimeIndex(['2011-01-03', '2011-04-01', '2011-07-01', '2011-10-03',
               '2012-01-02', '2012-04-02', '2012-07-02', '2012-10-01',
               '2013-01-01', '2013-04-01',
               ...
               '2071-01-01', '2071-04-01', '2071-07-01', '2071-10-01',
               '2072-01-01', '2072-04-01', '2072-07-01', '2072-10-03',
               '2073-01-02', '2073-04-03'],
              dtype='datetime64[ns]', length=250, freq='BQS-JAN')

date_range および bdate_range を使用すると、startendperiodsfreq などのパラメータのさまざまな組み合わせを使用して日付の範囲を簡単に生成できます。開始日と終了日は厳密に含まれるため、指定された日付の範囲外の日付は生成されません。

In [83]: pd.date_range(start, end, freq="BME")
Out[83]: 
DatetimeIndex(['2011-01-31', '2011-02-28', '2011-03-31', '2011-04-29',
               '2011-05-31', '2011-06-30', '2011-07-29', '2011-08-31',
               '2011-09-30', '2011-10-31', '2011-11-30', '2011-12-30'],
              dtype='datetime64[ns]', freq='BME')

In [84]: pd.date_range(start, end, freq="W")
Out[84]: 
DatetimeIndex(['2011-01-02', '2011-01-09', '2011-01-16', '2011-01-23',
               '2011-01-30', '2011-02-06', '2011-02-13', '2011-02-20',
               '2011-02-27', '2011-03-06', '2011-03-13', '2011-03-20',
               '2011-03-27', '2011-04-03', '2011-04-10', '2011-04-17',
               '2011-04-24', '2011-05-01', '2011-05-08', '2011-05-15',
               '2011-05-22', '2011-05-29', '2011-06-05', '2011-06-12',
               '2011-06-19', '2011-06-26', '2011-07-03', '2011-07-10',
               '2011-07-17', '2011-07-24', '2011-07-31', '2011-08-07',
               '2011-08-14', '2011-08-21', '2011-08-28', '2011-09-04',
               '2011-09-11', '2011-09-18', '2011-09-25', '2011-10-02',
               '2011-10-09', '2011-10-16', '2011-10-23', '2011-10-30',
               '2011-11-06', '2011-11-13', '2011-11-20', '2011-11-27',
               '2011-12-04', '2011-12-11', '2011-12-18', '2011-12-25',
               '2012-01-01'],
              dtype='datetime64[ns]', freq='W-SUN')

In [85]: pd.bdate_range(end=end, periods=20)
Out[85]: 
DatetimeIndex(['2011-12-05', '2011-12-06', '2011-12-07', '2011-12-08',
               '2011-12-09', '2011-12-12', '2011-12-13', '2011-12-14',
               '2011-12-15', '2011-12-16', '2011-12-19', '2011-12-20',
               '2011-12-21', '2011-12-22', '2011-12-23', '2011-12-26',
               '2011-12-27', '2011-12-28', '2011-12-29', '2011-12-30'],
              dtype='datetime64[ns]', freq='B')

In [86]: pd.bdate_range(start=start, periods=20)
Out[86]: 
DatetimeIndex(['2011-01-03', '2011-01-04', '2011-01-05', '2011-01-06',
               '2011-01-07', '2011-01-10', '2011-01-11', '2011-01-12',
               '2011-01-13', '2011-01-14', '2011-01-17', '2011-01-18',
               '2011-01-19', '2011-01-20', '2011-01-21', '2011-01-24',
               '2011-01-25', '2011-01-26', '2011-01-27', '2011-01-28'],
              dtype='datetime64[ns]', freq='B')

startend、および periods を指定すると、start から end までを含む均等に間隔を空けた日付の範囲が生成され、結果の DatetimeIndex には periods 個の要素が含まれます。

In [87]: pd.date_range("2018-01-01", "2018-01-05", periods=5)
Out[87]: 
DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04',
               '2018-01-05'],
              dtype='datetime64[ns]', freq=None)

In [88]: pd.date_range("2018-01-01", "2018-01-05", periods=10)
Out[88]: 
DatetimeIndex(['2018-01-01 00:00:00', '2018-01-01 10:40:00',
               '2018-01-01 21:20:00', '2018-01-02 08:00:00',
               '2018-01-02 18:40:00', '2018-01-03 05:20:00',
               '2018-01-03 16:00:00', '2018-01-04 02:40:00',
               '2018-01-04 13:20:00', '2018-01-05 00:00:00'],
              dtype='datetime64[ns]', freq=None)

カスタム頻度範囲#

bdate_range は、weekmask および holidays パラメータを使用することにより、カスタム頻度の日付の範囲も生成できます。これらのパラメータは、カスタム頻度文字列が渡された場合にのみ使用されます。

In [89]: weekmask = "Mon Wed Fri"

In [90]: holidays = [datetime.datetime(2011, 1, 5), datetime.datetime(2011, 3, 14)]

In [91]: pd.bdate_range(start, end, freq="C", weekmask=weekmask, holidays=holidays)
Out[91]: 
DatetimeIndex(['2011-01-03', '2011-01-07', '2011-01-10', '2011-01-12',
               '2011-01-14', '2011-01-17', '2011-01-19', '2011-01-21',
               '2011-01-24', '2011-01-26',
               ...
               '2011-12-09', '2011-12-12', '2011-12-14', '2011-12-16',
               '2011-12-19', '2011-12-21', '2011-12-23', '2011-12-26',
               '2011-12-28', '2011-12-30'],
              dtype='datetime64[ns]', length=154, freq='C')

In [92]: pd.bdate_range(start, end, freq="CBMS", weekmask=weekmask)
Out[92]: 
DatetimeIndex(['2011-01-03', '2011-02-02', '2011-03-02', '2011-04-01',
               '2011-05-02', '2011-06-01', '2011-07-01', '2011-08-01',
               '2011-09-02', '2011-10-03', '2011-11-02', '2011-12-02'],
              dtype='datetime64[ns]', freq='CBMS')

タイムスタンプの制限#

タイムスタンプ表現の制限は、選択した分解能によって異なります。ナノ秒分解能の場合、64ビット整数を使用して表現できる時間スパンは約584年に制限されます。

In [93]: pd.Timestamp.min
Out[93]: Timestamp('1677-09-21 00:12:43.145224193')

In [94]: pd.Timestamp.max
Out[94]: Timestamp('2262-04-11 23:47:16.854775807')

秒分解能を選択すると、利用可能な範囲は +/- 2.9e11 に拡大します。異なる分解能は、as_unit を介して相互に変換できます。

インデックス作成#

DatetimeIndex の主な用途の1つは、pandasオブジェクトのインデックスとして使用することです。DatetimeIndex クラスには、多くの時系列関連の最適化が含まれています。

  • 後続の日付範囲の生成を非常に高速にするために(単にスライスを取得する必要があるだけ)、さまざまなオフセットの広範囲の日付が事前に計算され、内部でキャッシュされます。

  • pandasオブジェクトの shift メソッドを使用した高速シフト。

  • 同じ頻度の重複する DatetimeIndex オブジェクトの結合は非常に高速です(高速なデータ配置に重要)。

  • yearmonth などのプロパティを介した日付フィールドへの高速アクセス。

  • snap のような正規化関数と、非常に高速な asof ロジック。

DatetimeIndex オブジェクトには、通常の Index オブジェクトのすべての基本機能と、簡単な頻度処理のための高度な時系列固有のメソッドの盛り合わせがあります。

注意

pandasは、日付インデックスをソートすることを強制しませんが、日付がソートされていない場合、これらのメソッドの一部は予期しない、または誤った動作をする可能性があります。

DatetimeIndex は、通常のインデックスのように使用でき、選択、スライスなどのすべてのインテリジェント機能を提供します。

In [95]: rng = pd.date_range(start, end, freq="BME")

In [96]: ts = pd.Series(np.random.randn(len(rng)), index=rng)

In [97]: ts.index
Out[97]: 
DatetimeIndex(['2011-01-31', '2011-02-28', '2011-03-31', '2011-04-29',
               '2011-05-31', '2011-06-30', '2011-07-29', '2011-08-31',
               '2011-09-30', '2011-10-31', '2011-11-30', '2011-12-30'],
              dtype='datetime64[ns]', freq='BME')

In [98]: ts[:5].index
Out[98]: 
DatetimeIndex(['2011-01-31', '2011-02-28', '2011-03-31', '2011-04-29',
               '2011-05-31'],
              dtype='datetime64[ns]', freq='BME')

In [99]: ts[::2].index
Out[99]: 
DatetimeIndex(['2011-01-31', '2011-03-31', '2011-05-31', '2011-07-29',
               '2011-09-30', '2011-11-30'],
              dtype='datetime64[ns]', freq='2BME')

部分文字列インデックス作成#

タイムスタンプに解析される日付と文字列をインデックスパラメータとして渡すことができます。

In [100]: ts["1/31/2011"]
Out[100]: 0.11920871129693428

In [101]: ts[datetime.datetime(2011, 12, 25):]
Out[101]: 
2011-12-30    0.56702
Freq: BME, dtype: float64

In [102]: ts["10/31/2011":"12/31/2011"]
Out[102]: 
2011-10-31    0.271860
2011-11-30   -0.424972
2011-12-30    0.567020
Freq: BME, dtype: float64

より長い時系列へのアクセスを容易にするために、年または年と月を文字列として渡すこともできます。

In [103]: ts["2011"]
Out[103]: 
2011-01-31    0.119209
2011-02-28   -1.044236
2011-03-31   -0.861849
2011-04-29   -2.104569
2011-05-31   -0.494929
2011-06-30    1.071804
2011-07-29    0.721555
2011-08-31   -0.706771
2011-09-30   -1.039575
2011-10-31    0.271860
2011-11-30   -0.424972
2011-12-30    0.567020
Freq: BME, dtype: float64

In [104]: ts["2011-6"]
Out[104]: 
2011-06-30    1.071804
Freq: BME, dtype: float64

このタイプのスライスは、DatetimeIndex を持つ DataFrame でも機能します。部分文字列選択はラベルスライスの形式であるため、エンドポイントは **含まれます**。これには、含まれる日付の一致する時間も含まれます。

警告

DataFrame の行を単一の文字列で getitem (例: frame[dtstring]) でインデックス付けすることは、pandas 1.2.0 から非推奨となりました (行のインデックス付けか列の選択かのあいまいさのため)。将来のバージョンで削除される予定です。.loc (例: frame.loc[dtstring]) を使用した同等の操作は引き続きサポートされます。

In [105]: dft = pd.DataFrame(
   .....:     np.random.randn(100000, 1),
   .....:     columns=["A"],
   .....:     index=pd.date_range("20130101", periods=100000, freq="min"),
   .....: )
   .....: 

In [106]: dft
Out[106]: 
                            A
2013-01-01 00:00:00  0.276232
2013-01-01 00:01:00 -1.087401
2013-01-01 00:02:00 -0.673690
2013-01-01 00:03:00  0.113648
2013-01-01 00:04:00 -1.478427
...                       ...
2013-03-11 10:35:00 -0.747967
2013-03-11 10:36:00 -0.034523
2013-03-11 10:37:00 -0.201754
2013-03-11 10:38:00 -1.509067
2013-03-11 10:39:00 -1.693043

[100000 rows x 1 columns]

In [107]: dft.loc["2013"]
Out[107]: 
                            A
2013-01-01 00:00:00  0.276232
2013-01-01 00:01:00 -1.087401
2013-01-01 00:02:00 -0.673690
2013-01-01 00:03:00  0.113648
2013-01-01 00:04:00 -1.478427
...                       ...
2013-03-11 10:35:00 -0.747967
2013-03-11 10:36:00 -0.034523
2013-03-11 10:37:00 -0.201754
2013-03-11 10:38:00 -1.509067
2013-03-11 10:39:00 -1.693043

[100000 rows x 1 columns]

これは月の最初の日から始まり、月の最後の日時を含みます。

In [108]: dft["2013-1":"2013-2"]
Out[108]: 
                            A
2013-01-01 00:00:00  0.276232
2013-01-01 00:01:00 -1.087401
2013-01-01 00:02:00 -0.673690
2013-01-01 00:03:00  0.113648
2013-01-01 00:04:00 -1.478427
...                       ...
2013-02-28 23:55:00  0.850929
2013-02-28 23:56:00  0.976712
2013-02-28 23:57:00 -2.693884
2013-02-28 23:58:00 -1.575535
2013-02-28 23:59:00 -1.573517

[84960 rows x 1 columns]

これは、**最終日のすべての時間を含む** 終了時間を指定します。

In [109]: dft["2013-1":"2013-2-28"]
Out[109]: 
                            A
2013-01-01 00:00:00  0.276232
2013-01-01 00:01:00 -1.087401
2013-01-01 00:02:00 -0.673690
2013-01-01 00:03:00  0.113648
2013-01-01 00:04:00 -1.478427
...                       ...
2013-02-28 23:55:00  0.850929
2013-02-28 23:56:00  0.976712
2013-02-28 23:57:00 -2.693884
2013-02-28 23:58:00 -1.575535
2013-02-28 23:59:00 -1.573517

[84960 rows x 1 columns]

これは**正確な**終了時間を指定します (上記とは異なります)。

In [110]: dft["2013-1":"2013-2-28 00:00:00"]
Out[110]: 
                            A
2013-01-01 00:00:00  0.276232
2013-01-01 00:01:00 -1.087401
2013-01-01 00:02:00 -0.673690
2013-01-01 00:03:00  0.113648
2013-01-01 00:04:00 -1.478427
...                       ...
2013-02-27 23:56:00  1.197749
2013-02-27 23:57:00  0.720521
2013-02-27 23:58:00 -0.072718
2013-02-27 23:59:00 -0.681192
2013-02-28 00:00:00 -0.557501

[83521 rows x 1 columns]

インデックスの一部であるため、含まれるエンドポイントで停止します。

In [111]: dft["2013-1-15":"2013-1-15 12:30:00"]
Out[111]: 
                            A
2013-01-15 00:00:00 -0.984810
2013-01-15 00:01:00  0.941451
2013-01-15 00:02:00  1.559365
2013-01-15 00:03:00  1.034374
2013-01-15 00:04:00 -1.480656
...                       ...
2013-01-15 12:26:00  0.371454
2013-01-15 12:27:00 -0.930806
2013-01-15 12:28:00 -0.069177
2013-01-15 12:29:00  0.066510
2013-01-15 12:30:00 -0.003945

[751 rows x 1 columns]

DatetimeIndex の部分文字列インデックス付けは、MultiIndex を持つ DataFrame でも機能します。

In [112]: dft2 = pd.DataFrame(
   .....:     np.random.randn(20, 1),
   .....:     columns=["A"],
   .....:     index=pd.MultiIndex.from_product(
   .....:         [pd.date_range("20130101", periods=10, freq="12h"), ["a", "b"]]
   .....:     ),
   .....: )
   .....: 

In [113]: dft2
Out[113]: 
                              A
2013-01-01 00:00:00 a -0.298694
                    b  0.823553
2013-01-01 12:00:00 a  0.943285
                    b -1.479399
2013-01-02 00:00:00 a -1.643342
...                         ...
2013-01-04 12:00:00 b  0.069036
2013-01-05 00:00:00 a  0.122297
                    b  1.422060
2013-01-05 12:00:00 a  0.370079
                    b  1.016331

[20 rows x 1 columns]

In [114]: dft2.loc["2013-01-05"]
Out[114]: 
                              A
2013-01-05 00:00:00 a  0.122297
                    b  1.422060
2013-01-05 12:00:00 a  0.370079
                    b  1.016331

In [115]: idx = pd.IndexSlice

In [116]: dft2 = dft2.swaplevel(0, 1).sort_index()

In [117]: dft2.loc[idx[:, "2013-01-05"], :]
Out[117]: 
                              A
a 2013-01-05 00:00:00  0.122297
  2013-01-05 12:00:00  0.370079
b 2013-01-05 00:00:00  1.422060
  2013-01-05 12:00:00  1.016331

文字列インデックスによるスライスも UTC オフセットを考慮します。

In [118]: df = pd.DataFrame([0], index=pd.DatetimeIndex(["2019-01-01"], tz="US/Pacific"))

In [119]: df
Out[119]: 
                           0
2019-01-01 00:00:00-08:00  0

In [120]: df["2019-01-01 12:00:00+04:00":"2019-01-01 13:00:00+04:00"]
Out[120]: 
                           0
2019-01-01 00:00:00-08:00  0

スライスと完全一致#

インデックスパラメータとして使用される同じ文字列は、インデックスの解像度に応じて、スライスまたは完全一致のいずれかとして扱われます。文字列がインデックスよりも精度が低い場合、スライスとして扱われ、それ以外の場合は完全一致として扱われます。

分単位の解像度のインデックスを持つ Series オブジェクトを考えます。

In [121]: series_minute = pd.Series(
   .....:     [1, 2, 3],
   .....:     pd.DatetimeIndex(
   .....:         ["2011-12-31 23:59:00", "2012-01-01 00:00:00", "2012-01-01 00:02:00"]
   .....:     ),
   .....: )
   .....: 

In [122]: series_minute.index.resolution
Out[122]: 'minute'

分未満の精度のタイムスタンプ文字列は、Series オブジェクトを返します。

In [123]: series_minute["2011-12-31 23"]
Out[123]: 
2011-12-31 23:59:00    1
dtype: int64

分単位の解像度 (またはそれ以上の精度) のタイムスタンプ文字列は、スライスにキャストされず、代わりにスカラーを返します。

In [124]: series_minute["2011-12-31 23:59"]
Out[124]: 1

In [125]: series_minute["2011-12-31 23:59:00"]
Out[125]: 1

インデックスの解像度が秒の場合、分単位の精度のタイムスタンプは Series を返します。

In [126]: series_second = pd.Series(
   .....:     [1, 2, 3],
   .....:     pd.DatetimeIndex(
   .....:         ["2011-12-31 23:59:59", "2012-01-01 00:00:00", "2012-01-01 00:00:01"]
   .....:     ),
   .....: )
   .....: 

In [127]: series_second.index.resolution
Out[127]: 'second'

In [128]: series_second["2011-12-31 23:59"]
Out[128]: 
2011-12-31 23:59:59    1
dtype: int64

タイムスタンプ文字列がスライスとして扱われる場合、DataFrame のインデックス付けにも .loc[] を使用できます。

In [129]: dft_minute = pd.DataFrame(
   .....:     {"a": [1, 2, 3], "b": [4, 5, 6]}, index=series_minute.index
   .....: )
   .....: 

In [130]: dft_minute.loc["2011-12-31 23"]
Out[130]: 
                     a  b
2011-12-31 23:59:00  1  4

警告

ただし、文字列が完全一致として扱われる場合、DataFrame[] での選択は行単位ではなく列単位になります。「インデックスの基本」を参照してください。たとえば、dft_minute['2011-12-31 23:59'] は、'2012-12-31 23:59' がインデックスと同じ解像度を持ち、そのような名前の列がないため、KeyError を発生させます。

行がスライスとして扱われるか、単一の選択として扱われるかにかかわらず、あいまいさのない選択を常に行うには、.loc を使用します。

In [131]: dft_minute.loc["2011-12-31 23:59"]
Out[131]: 
a    1
b    4
Name: 2011-12-31 23:59:00, dtype: int64

また、DatetimeIndex の解像度は日未満の精度にはできないことに注意してください。

In [132]: series_monthly = pd.Series(
   .....:     [1, 2, 3], pd.DatetimeIndex(["2011-12", "2012-01", "2012-02"])
   .....: )
   .....: 

In [133]: series_monthly.index.resolution
Out[133]: 'day'

In [134]: series_monthly["2011-12"]  # returns Series
Out[134]: 
2011-12-01    1
dtype: int64

正確なインデックス付け#

前のセクションで説明したように、部分文字列による DatetimeIndex のインデックス付けは、期間の「精度」、言い換えれば、インデックスの解像度に対する間隔の具体性に依存します。対照的に、Timestamp または datetime オブジェクトによるインデックス付けは、オブジェクトに正確な意味があるため、正確です。これらも両方のエンドポイントを含むセマンティクスに従います。

これらの Timestamp および datetime オブジェクトは、明示的に指定されていなくても (0 です)、正確な hours, minutes, および seconds を持ちます。

In [135]: dft[datetime.datetime(2013, 1, 1): datetime.datetime(2013, 2, 28)]
Out[135]: 
                            A
2013-01-01 00:00:00  0.276232
2013-01-01 00:01:00 -1.087401
2013-01-01 00:02:00 -0.673690
2013-01-01 00:03:00  0.113648
2013-01-01 00:04:00 -1.478427
...                       ...
2013-02-27 23:56:00  1.197749
2013-02-27 23:57:00  0.720521
2013-02-27 23:58:00 -0.072718
2013-02-27 23:59:00 -0.681192
2013-02-28 00:00:00 -0.557501

[83521 rows x 1 columns]

デフォルトなし。

In [136]: dft[
   .....:     datetime.datetime(2013, 1, 1, 10, 12, 0): datetime.datetime(
   .....:         2013, 2, 28, 10, 12, 0
   .....:     )
   .....: ]
   .....: 
Out[136]: 
                            A
2013-01-01 10:12:00  0.565375
2013-01-01 10:13:00  0.068184
2013-01-01 10:14:00  0.788871
2013-01-01 10:15:00 -0.280343
2013-01-01 10:16:00  0.931536
...                       ...
2013-02-28 10:08:00  0.148098
2013-02-28 10:09:00 -0.388138
2013-02-28 10:10:00  0.139348
2013-02-28 10:11:00  0.085288
2013-02-28 10:12:00  0.950146

[83521 rows x 1 columns]

切り捨てとファンシーインデックス付け#

スライスと同様の便利な関数である truncate() が提供されています。truncate は、部分的に一致する日付を返すスライスとは対照的に、DatetimeIndex の未指定の日付コンポーネントに 0 値を想定していることに注意してください。

In [137]: rng2 = pd.date_range("2011-01-01", "2012-01-01", freq="W")

In [138]: ts2 = pd.Series(np.random.randn(len(rng2)), index=rng2)

In [139]: ts2.truncate(before="2011-11", after="2011-12")
Out[139]: 
2011-11-06    0.437823
2011-11-13   -0.293083
2011-11-20   -0.059881
2011-11-27    1.252450
Freq: W-SUN, dtype: float64

In [140]: ts2["2011-11":"2011-12"]
Out[140]: 
2011-11-06    0.437823
2011-11-13   -0.293083
2011-11-20   -0.059881
2011-11-27    1.252450
2011-12-04    0.046611
2011-12-11    0.059478
2011-12-18   -0.286539
2011-12-25    0.841669
Freq: W-SUN, dtype: float64

DatetimeIndex の頻度規則性を破るような複雑なファンシーインデックス付けでさえ、頻度が失われたとしても、DatetimeIndex になります。

In [141]: ts2.iloc[[0, 2, 6]].index
Out[141]: DatetimeIndex(['2011-01-02', '2011-01-16', '2011-02-13'], dtype='datetime64[ns]', freq=None)

時間/日付コンポーネント#

Timestamp または DatetimeIndex のようなタイムスタンプのコレクションからアクセスできる、いくつかの時間/日付プロパティがあります。

プロパティ

説明

year

datetime の年

month

datetime の月

day

datetime の日

hour

datetime の時間

minute

datetime の分

second

datetime の秒

microsecond

datetime のマイクロ秒

nanosecond

datetime のナノ秒

date

datetime.date を返します (タイムゾーン情報は含まれません)。

time

datetime.time を返します (タイムゾーン情報は含まれません)。

timetz

タイムゾーン情報を含むローカル時間として datetime.time を返します。

dayofyear

年の序数日

day_of_year

年の序数日

weekofyear

年の週の序数

week

年の週の序数

dayofweek

月曜日=0、日曜日=6 の週の日の数

day_of_week

月曜日=0、日曜日=6 の週の日の数

weekday

月曜日=0、日曜日=6 の週の日の数

quarter

日付の四半期: 1月~3月 = 1、4月~6月 = 2 など

days_in_month

datetime の月の日の数

is_month_start

月の最初の日 (頻度で定義) かどうかを示す論理値

is_month_end

月の最後の日 (頻度で定義) かどうかを示す論理値

is_quarter_start

四半期の最初の日 (頻度で定義) かどうかを示す論理値

is_quarter_end

四半期の最後の日 (頻度で定義) かどうかを示す論理値

is_year_start

年の最初の日 (頻度で定義) かどうかを示す論理値

is_year_end

年の最後の日 (頻度で定義) かどうかを示す論理値

is_leap_year

日付がうるう年に属するかどうかを示す論理値

さらに、datetimelike 値を持つ Series がある場合は、「.dt アクセサ」のセクションで詳しく説明されているように、.dt アクセサを介してこれらのプロパティにアクセスできます。

ISO 8601 標準から、ISO 年の年、週、日のコンポーネントを取得できます。

In [142]: idx = pd.date_range(start="2019-12-29", freq="D", periods=4)

In [143]: idx.isocalendar()
Out[143]: 
            year  week  day
2019-12-29  2019    52    7
2019-12-30  2020     1    1
2019-12-31  2020     1    2
2020-01-01  2020     1    3

In [144]: idx.to_series().dt.isocalendar()
Out[144]: 
            year  week  day
2019-12-29  2019    52    7
2019-12-30  2020     1    1
2019-12-31  2020     1    2
2020-01-01  2020     1    3

DateOffset オブジェクト#

前の例では、頻度文字列 (例: 'D') を使用して、定義された頻度を指定しました。

これらの頻度文字列は、DateOffset オブジェクトとそのサブクラスにマップされます。DateOffset は、時間の長さを表す Timedelta に似ていますが、特定のカレンダー期間ルールに従います。たとえば、Timedelta の日は常に datetimes を 24 時間ずつインクリメントしますが、DateOffset の日は、夏時間のために日が 23 時間、24 時間、または 25 時間を表すかどうかにかかわらず、datetimes を次の日の同じ時間にインクリメントします。ただし、1 時間以下のすべての DateOffset サブクラス (HourMinuteSecondMilliMicroNano) は、Timedelta のように動作し、絶対時間を尊重します。

基本的なDateOffsetは、指定されたカレンダー期間だけ日時をずらす点で、dateutil.relativedeltarelativedeltaのドキュメント)と似たように動作します。算術演算子(+)を使ってシフトを実行できます。

# This particular day contains a day light savings time transition
In [145]: ts = pd.Timestamp("2016-10-30 00:00:00", tz="Europe/Helsinki")

# Respects absolute time
In [146]: ts + pd.Timedelta(days=1)
Out[146]: Timestamp('2016-10-30 23:00:00+0200', tz='Europe/Helsinki')

# Respects calendar time
In [147]: ts + pd.DateOffset(days=1)
Out[147]: Timestamp('2016-10-31 00:00:00+0200', tz='Europe/Helsinki')

In [148]: friday = pd.Timestamp("2018-01-05")

In [149]: friday.day_name()
Out[149]: 'Friday'

# Add 2 business days (Friday --> Tuesday)
In [150]: two_business_days = 2 * pd.offsets.BDay()

In [151]: friday + two_business_days
Out[151]: Timestamp('2018-01-09 00:00:00')

In [152]: (friday + two_business_days).day_name()
Out[152]: 'Tuesday'

ほとんどのDateOffsetには、freqキーワード引数に渡すことができる、関連する頻度文字列またはオフセットエイリアスがあります。利用可能な日付オフセットと関連する頻度文字列は以下のとおりです。

日付オフセット

頻度文字列

説明

DateOffset

None

汎用オフセットクラス、デフォルトは絶対24時間

BDay または BusinessDay

'B'

営業日(平日)

CDay または CustomBusinessDay

'C'

カスタム営業日

'W'

1週間、オプションで曜日を基準に指定

WeekOfMonth

'WOM'

各月の第y週のx番目の日

LastWeekOfMonth

'LWOM'

各月の最終週のx番目の日

月末

'ME'

カレンダーの月末

月初

'MS'

カレンダーの月初

BMonthEnd または BusinessMonthEnd

'BME'

営業月末

BMonthBegin または BusinessMonthBegin

'BMS'

営業月初

CBMonthEnd または CustomBusinessMonthEnd

'CBME'

カスタム営業月末

CBMonthBegin または CustomBusinessMonthBegin

'CBMS'

カスタム営業月初

半月終了

'SME'

15日(または他のday_of_month)とカレンダーの月末

半月開始

'SMS'

15日(または他のday_of_month)とカレンダーの月初

四半期末

'QE'

カレンダーの四半期末

四半期開始

'QS'

カレンダーの四半期開始

営業四半期末

'BQE'

営業四半期末

営業四半期開始

'BQS'

営業四半期開始

FY5253四半期

'REQ'

小売(52-53週)四半期

年末

'YE'

カレンダーの年末

年初

'YS' または 'BYS'

カレンダーの年初

営業年末

'BYE'

営業年末

営業年初

'BYS'

営業年初

FY5253

'RE'

小売(52-53週)年

イースター

None

イースターの祝日

ビジネス時間

'bh'

ビジネス時間

カスタムビジネス時間

'cbh'

カスタムビジネス時間

'D'

絶対的な1日

時間

'h'

1時間

'min'

1分

's'

1秒

ミリ秒

'ms'

1ミリ秒

マイクロ秒

'us'

1マイクロ秒

ナノ秒

'ns'

1ナノ秒

DateOffsetsにはさらに、オフセットを基準とした有効なオフセット日付に日付を前後に移動するためのrollforward()メソッドとrollback()メソッドがあります。たとえば、ビジネスオフセットは、週末(土曜日と日曜日)に該当する日付を、ビジネスオフセットが平日で動作するため、月曜日にロールフォワードします。

In [153]: ts = pd.Timestamp("2018-01-06 00:00:00")

In [154]: ts.day_name()
Out[154]: 'Saturday'

# BusinessHour's valid offset dates are Monday through Friday
In [155]: offset = pd.offsets.BusinessHour(start="09:00")

# Bring the date to the closest offset date (Monday)
In [156]: offset.rollforward(ts)
Out[156]: Timestamp('2018-01-08 09:00:00')

# Date is brought to the closest offset date first and then the hour is added
In [157]: ts + offset
Out[157]: Timestamp('2018-01-08 10:00:00')

これらの操作は、デフォルトで時間(時、分など)情報を保持します。時間を真夜中にリセットするには、操作を適用する前または後にnormalize()を使用します(操作に時間情報を含めるかどうかによって異なります)。

In [158]: ts = pd.Timestamp("2014-01-01 09:00")

In [159]: day = pd.offsets.Day()

In [160]: day + ts
Out[160]: Timestamp('2014-01-02 09:00:00')

In [161]: (day + ts).normalize()
Out[161]: Timestamp('2014-01-02 00:00:00')

In [162]: ts = pd.Timestamp("2014-01-01 22:00")

In [163]: hour = pd.offsets.Hour()

In [164]: hour + ts
Out[164]: Timestamp('2014-01-01 23:00:00')

In [165]: (hour + ts).normalize()
Out[165]: Timestamp('2014-01-01 00:00:00')

In [166]: (hour + pd.Timestamp("2014-01-01 23:30")).normalize()
Out[166]: Timestamp('2014-01-02 00:00:00')

パラメトリックオフセット#

オフセットの中には、作成時に「パラメーター化」することで、異なる動作をもたらすものがあります。たとえば、週単位のデータを生成するためのWeekオフセットは、weekdayパラメーターを受け取り、これにより生成された日付が常に特定の曜日になるようにします。

In [167]: d = datetime.datetime(2008, 8, 18, 9, 0)

In [168]: d
Out[168]: datetime.datetime(2008, 8, 18, 9, 0)

In [169]: d + pd.offsets.Week()
Out[169]: Timestamp('2008-08-25 09:00:00')

In [170]: d + pd.offsets.Week(weekday=4)
Out[170]: Timestamp('2008-08-22 09:00:00')

In [171]: (d + pd.offsets.Week(weekday=4)).weekday()
Out[171]: 4

In [172]: d - pd.offsets.Week()
Out[172]: Timestamp('2008-08-11 09:00:00')

normalizeオプションは、加算と減算に有効です。

In [173]: d + pd.offsets.Week(normalize=True)
Out[173]: Timestamp('2008-08-25 00:00:00')

In [174]: d - pd.offsets.Week(normalize=True)
Out[174]: Timestamp('2008-08-11 00:00:00')

もう1つの例は、YearEndに特定の終了月を指定してパラメーター化することです。

In [175]: d + pd.offsets.YearEnd()
Out[175]: Timestamp('2008-12-31 09:00:00')

In [176]: d + pd.offsets.YearEnd(month=6)
Out[176]: Timestamp('2009-06-30 09:00:00')

Series / DatetimeIndexでのオフセットの使用#

オフセットは、SeriesまたはDatetimeIndexのいずれかと一緒に使用して、各要素にオフセットを適用できます。

In [177]: rng = pd.date_range("2012-01-01", "2012-01-03")

In [178]: s = pd.Series(rng)

In [179]: rng
Out[179]: DatetimeIndex(['2012-01-01', '2012-01-02', '2012-01-03'], dtype='datetime64[ns]', freq='D')

In [180]: rng + pd.DateOffset(months=2)
Out[180]: DatetimeIndex(['2012-03-01', '2012-03-02', '2012-03-03'], dtype='datetime64[ns]', freq=None)

In [181]: s + pd.DateOffset(months=2)
Out[181]: 
0   2012-03-01
1   2012-03-02
2   2012-03-03
dtype: datetime64[ns]

In [182]: s - pd.DateOffset(months=2)
Out[182]: 
0   2011-11-01
1   2011-11-02
2   2011-11-03
dtype: datetime64[ns]

オフセットクラスがTimedeltaDayHourMinuteSecondMicroMilliNano)に直接マップする場合は、Timedeltaとまったく同じように使用できます。詳細については、Timedeltaセクションを参照してください。

In [183]: s - pd.offsets.Day(2)
Out[183]: 
0   2011-12-30
1   2011-12-31
2   2012-01-01
dtype: datetime64[ns]

In [184]: td = s - pd.Series(pd.date_range("2011-12-29", "2011-12-31"))

In [185]: td
Out[185]: 
0   3 days
1   3 days
2   3 days
dtype: timedelta64[ns]

In [186]: td + pd.offsets.Minute(15)
Out[186]: 
0   3 days 00:15:00
1   3 days 00:15:00
2   3 days 00:15:00
dtype: timedelta64[ns]

一部のオフセット(BQuarterEndなど)には、ベクトル化された実装がないことに注意してください。これらは引き続き使用できますが、計算が大幅に遅くなり、PerformanceWarningが表示されます。

In [187]: rng + pd.offsets.BQuarterEnd()
Out[187]: DatetimeIndex(['2012-03-30', '2012-03-30', '2012-03-30'], dtype='datetime64[ns]', freq=None)

カスタム営業日#

CDayまたはCustomBusinessDayクラスは、ローカルの祝日とローカルの週末の慣習を考慮したカスタマイズされた営業日カレンダーを作成するために使用できるパラメトリックなBusinessDayクラスを提供します。

興味深い例として、金曜日-土曜日の週末が守られているエジプトを見てみましょう。

In [188]: weekmask_egypt = "Sun Mon Tue Wed Thu"

# They also observe International Workers' Day so let's
# add that for a couple of years
In [189]: holidays = [
   .....:     "2012-05-01",
   .....:     datetime.datetime(2013, 5, 1),
   .....:     np.datetime64("2014-05-01"),
   .....: ]
   .....: 

In [190]: bday_egypt = pd.offsets.CustomBusinessDay(
   .....:     holidays=holidays,
   .....:     weekmask=weekmask_egypt,
   .....: )
   .....: 

In [191]: dt = datetime.datetime(2013, 4, 30)

In [192]: dt + 2 * bday_egypt
Out[192]: Timestamp('2013-05-05 00:00:00')

曜日名にマップしましょう

In [193]: dts = pd.date_range(dt, periods=5, freq=bday_egypt)

In [194]: pd.Series(dts.weekday, dts).map(pd.Series("Mon Tue Wed Thu Fri Sat Sun".split()))
Out[194]: 
2013-04-30    Tue
2013-05-02    Thu
2013-05-05    Sun
2013-05-06    Mon
2013-05-07    Tue
Freq: C, dtype: object

祝日カレンダーは、祝日の一覧を提供するために使用できます。詳細については、祝日カレンダーセクションを参照してください。

In [195]: from pandas.tseries.holiday import USFederalHolidayCalendar

In [196]: bday_us = pd.offsets.CustomBusinessDay(calendar=USFederalHolidayCalendar())

# Friday before MLK Day
In [197]: dt = datetime.datetime(2014, 1, 17)

# Tuesday after MLK Day (Monday is skipped because it's a holiday)
In [198]: dt + bday_us
Out[198]: Timestamp('2014-01-21 00:00:00')

特定の祝日カレンダーを尊重する月次オフセットは、通常の方法で定義できます。

In [199]: bmth_us = pd.offsets.CustomBusinessMonthBegin(calendar=USFederalHolidayCalendar())

# Skip new years
In [200]: dt = datetime.datetime(2013, 12, 17)

In [201]: dt + bmth_us
Out[201]: Timestamp('2014-01-02 00:00:00')

# Define date index with custom offset
In [202]: pd.date_range(start="20100101", end="20120101", freq=bmth_us)
Out[202]: 
DatetimeIndex(['2010-01-04', '2010-02-01', '2010-03-01', '2010-04-01',
               '2010-05-03', '2010-06-01', '2010-07-01', '2010-08-02',
               '2010-09-01', '2010-10-01', '2010-11-01', '2010-12-01',
               '2011-01-03', '2011-02-01', '2011-03-01', '2011-04-01',
               '2011-05-02', '2011-06-01', '2011-07-01', '2011-08-01',
               '2011-09-01', '2011-10-03', '2011-11-01', '2011-12-01'],
              dtype='datetime64[ns]', freq='CBMS')

注意

頻度文字列「C」は、CustomBusinessDay DateOffsetが使用されていることを示すために使用されます。CustomBusinessDayはパラメーター化された型であるため、CustomBusinessDayのインスタンスは異なる可能性があり、これは「C」の頻度文字列からは検出できないことに注意することが重要です。したがって、ユーザーは、アプリケーション内で「C」の頻度文字列が一貫して使用されていることを確認する必要があります。

ビジネス時間#

BusinessHourクラスは、特定の開始時刻と終了時刻を使用できるように、BusinessDayでビジネス時間の表現を提供します。

デフォルトでは、BusinessHourはビジネス時間として9:00〜17:00を使用します。BusinessHourを追加すると、Timestampが時間単位の頻度でインクリメントされます。ターゲットTimestampが営業時間外の場合は、次のビジネス時間に移動してからインクリメントします。結果が営業時間終了を超える場合は、残りの時間が次の営業日に追加されます。

In [203]: bh = pd.offsets.BusinessHour()

In [204]: bh
Out[204]: <BusinessHour: bh=09:00-17:00>

# 2014-08-01 is Friday
In [205]: pd.Timestamp("2014-08-01 10:00").weekday()
Out[205]: 4

In [206]: pd.Timestamp("2014-08-01 10:00") + bh
Out[206]: Timestamp('2014-08-01 11:00:00')

# Below example is the same as: pd.Timestamp('2014-08-01 09:00') + bh
In [207]: pd.Timestamp("2014-08-01 08:00") + bh
Out[207]: Timestamp('2014-08-01 10:00:00')

# If the results is on the end time, move to the next business day
In [208]: pd.Timestamp("2014-08-01 16:00") + bh
Out[208]: Timestamp('2014-08-04 09:00:00')

# Remainings are added to the next day
In [209]: pd.Timestamp("2014-08-01 16:30") + bh
Out[209]: Timestamp('2014-08-04 09:30:00')

# Adding 2 business hours
In [210]: pd.Timestamp("2014-08-01 10:00") + pd.offsets.BusinessHour(2)
Out[210]: Timestamp('2014-08-01 12:00:00')

# Subtracting 3 business hours
In [211]: pd.Timestamp("2014-08-01 10:00") + pd.offsets.BusinessHour(-3)
Out[211]: Timestamp('2014-07-31 15:00:00')

キーワードでstartend時間を指定することもできます。引数は、hour:minute表現のstrまたはdatetime.timeインスタンスである必要があります。ビジネス時間として秒、マイクロ秒、ナノ秒を指定すると、ValueErrorになります。

In [212]: bh = pd.offsets.BusinessHour(start="11:00", end=datetime.time(20, 0))

In [213]: bh
Out[213]: <BusinessHour: bh=11:00-20:00>

In [214]: pd.Timestamp("2014-08-01 13:00") + bh
Out[214]: Timestamp('2014-08-01 14:00:00')

In [215]: pd.Timestamp("2014-08-01 09:00") + bh
Out[215]: Timestamp('2014-08-01 12:00:00')

In [216]: pd.Timestamp("2014-08-01 18:00") + bh
Out[216]: Timestamp('2014-08-01 19:00:00')

endよりも後のstart時間を渡すと、真夜中のビジネス時間が表されます。この場合、ビジネス時間は真夜中を超え、翌日に重なります。有効なビジネス時間は、有効なBusinessDayから開始されたかどうかによって区別されます。

In [217]: bh = pd.offsets.BusinessHour(start="17:00", end="09:00")

In [218]: bh
Out[218]: <BusinessHour: bh=17:00-09:00>

In [219]: pd.Timestamp("2014-08-01 17:00") + bh
Out[219]: Timestamp('2014-08-01 18:00:00')

In [220]: pd.Timestamp("2014-08-01 23:00") + bh
Out[220]: Timestamp('2014-08-02 00:00:00')

# Although 2014-08-02 is Saturday,
# it is valid because it starts from 08-01 (Friday).
In [221]: pd.Timestamp("2014-08-02 04:00") + bh
Out[221]: Timestamp('2014-08-02 05:00:00')

# Although 2014-08-04 is Monday,
# it is out of business hours because it starts from 08-03 (Sunday).
In [222]: pd.Timestamp("2014-08-04 04:00") + bh
Out[222]: Timestamp('2014-08-04 18:00:00')

営業時間外にBusinessHour.rollforwardrollbackを適用すると、次のビジネス時間の開始または前日の終了になります。他のオフセットとは異なり、BusinessHour.rollforwardは定義上applyとは異なる結果を出力する場合があります。

これは、ある日のビジネス時間の終了が、次の日のビジネス時間の開始と等しいためです。たとえば、デフォルトの営業時間(9:00〜17:00)では、2014-08-01 17:002014-08-04 09:00の間にはギャップ(0分)はありません。

# This adjusts a Timestamp to business hour edge
In [223]: pd.offsets.BusinessHour().rollback(pd.Timestamp("2014-08-02 15:00"))
Out[223]: Timestamp('2014-08-01 17:00:00')

In [224]: pd.offsets.BusinessHour().rollforward(pd.Timestamp("2014-08-02 15:00"))
Out[224]: Timestamp('2014-08-04 09:00:00')

# It is the same as BusinessHour() + pd.Timestamp('2014-08-01 17:00').
# And it is the same as BusinessHour() + pd.Timestamp('2014-08-04 09:00')
In [225]: pd.offsets.BusinessHour() + pd.Timestamp("2014-08-02 15:00")
Out[225]: Timestamp('2014-08-04 10:00:00')

# BusinessDay results (for reference)
In [226]: pd.offsets.BusinessHour().rollforward(pd.Timestamp("2014-08-02"))
Out[226]: Timestamp('2014-08-04 09:00:00')

# It is the same as BusinessDay() + pd.Timestamp('2014-08-01')
# The result is the same as rollworward because BusinessDay never overlap.
In [227]: pd.offsets.BusinessHour() + pd.Timestamp("2014-08-02")
Out[227]: Timestamp('2014-08-04 10:00:00')

BusinessHourは、土曜日と日曜日を休日とみなします。任意の休日を使用するには、次のサブセクションで説明するように、CustomBusinessHourオフセットを使用できます。

カスタムビジネス時間#

CustomBusinessHour は、BusinessHourCustomBusinessDay の組み合わせであり、任意の日付を休日として指定できます。 CustomBusinessHour は、指定されたカスタム休日をスキップする点を除いて、BusinessHour と同様に機能します。

In [228]: from pandas.tseries.holiday import USFederalHolidayCalendar

In [229]: bhour_us = pd.offsets.CustomBusinessHour(calendar=USFederalHolidayCalendar())

# Friday before MLK Day
In [230]: dt = datetime.datetime(2014, 1, 17, 15)

In [231]: dt + bhour_us
Out[231]: Timestamp('2014-01-17 16:00:00')

# Tuesday after MLK Day (Monday is skipped because it's a holiday)
In [232]: dt + bhour_us * 2
Out[232]: Timestamp('2014-01-21 09:00:00')

BusinessHourCustomBusinessDay のどちらかでサポートされているキーワード引数を使用できます。

In [233]: bhour_mon = pd.offsets.CustomBusinessHour(start="10:00", weekmask="Tue Wed Thu Fri")

# Monday is skipped because it's a holiday, business hour starts from 10:00
In [234]: dt + bhour_mon * 2
Out[234]: Timestamp('2014-01-21 10:00:00')

オフセットエイリアス#

便利な一般的な時系列頻度には、多くの文字列エイリアスが与えられています。これらのエイリアスをオフセットエイリアスと呼びます。

エイリアス

説明

B

営業日頻度

C

カスタム営業日頻度

D

カレンダー日頻度

W

週次頻度

ME

月末頻度

SME

半月終頻度(15日と月末)

BME

営業月末頻度

CBME

カスタム営業月末頻度

MS

月始頻度

SMS

半月始頻度(1日と15日)

BMS

営業月始頻度

CBMS

カスタム営業月始頻度

QE

四半期末頻度

BQE

営業四半期末頻度

QS

四半期始頻度

BQS

営業四半期始頻度

YE

年末頻度

BYE

営業年末頻度

YS

年始頻度

BYS

営業年始頻度

h

時間頻度

bh

営業時間頻度

cbh

カスタム営業時間頻度

min

分単位頻度

s

秒単位頻度

ms

ミリ秒

us

マイクロ秒

ns

ナノ秒

バージョン 2.2.0 で非推奨: エイリアス HBHCBHTSLU、および N は、エイリアス hbhcbhminsmsus、および ns を優先して非推奨になりました。

注意

上記のオフセットエイリアスを使用する場合、date_range()bdate_range() などの関数は、start_dateend_date で定義された間隔にあるタイムスタンプのみを返すことに注意する必要があります。 start_date が頻度に対応しない場合、返されるタイムスタンプは次の有効なタイムスタンプから開始され、end_date の場合も同様に、返されるタイムスタンプは前の有効なタイムスタンプで停止します。

たとえば、オフセット MS の場合、start_date が月の最初の日でない場合、返されるタイムスタンプは翌月の最初の日から開始されます。 end_date が月の最初の日でない場合、最後に返されるタイムスタンプは、対応する月の最初の日になります。

In [235]: dates_lst_1 = pd.date_range("2020-01-06", "2020-04-03", freq="MS")

In [236]: dates_lst_1
Out[236]: DatetimeIndex(['2020-02-01', '2020-03-01', '2020-04-01'], dtype='datetime64[ns]', freq='MS')

In [237]: dates_lst_2 = pd.date_range("2020-01-01", "2020-04-01", freq="MS")

In [238]: dates_lst_2
Out[238]: DatetimeIndex(['2020-01-01', '2020-02-01', '2020-03-01', '2020-04-01'], dtype='datetime64[ns]', freq='MS')

上記の例では、date_range() および bdate_range() は、start_dateend_date の間の有効なタイムスタンプのみを返すことがわかります。これらが指定された頻度に対して有効なタイムスタンプでない場合は、start_date の場合は次の値にロールし(end_date の場合はそれぞれ前の値)、ます。

期間エイリアス#

便利な一般的な時系列頻度には、多くの文字列エイリアスが与えられています。これらのエイリアスを期間エイリアスと呼びます。

エイリアス

説明

B

営業日頻度

D

カレンダー日頻度

W

週次頻度

M

月次頻度

Q

四半期頻度

Y

年次頻度

h

時間頻度

min

分単位頻度

s

秒単位頻度

ms

ミリ秒

us

マイクロ秒

ns

ナノ秒

バージョン 2.2.0 で非推奨: エイリアス AHTSLU、および N は、エイリアス Yhminsmsus、および ns を優先して非推奨になりました。

エイリアスの組み合わせ#

前述のように、ほとんどの関数でエイリアスとオフセットインスタンスは交換可能です。

In [239]: pd.date_range(start, periods=5, freq="B")
Out[239]: 
DatetimeIndex(['2011-01-03', '2011-01-04', '2011-01-05', '2011-01-06',
               '2011-01-07'],
              dtype='datetime64[ns]', freq='B')

In [240]: pd.date_range(start, periods=5, freq=pd.offsets.BDay())
Out[240]: 
DatetimeIndex(['2011-01-03', '2011-01-04', '2011-01-05', '2011-01-06',
               '2011-01-07'],
              dtype='datetime64[ns]', freq='B')

日単位および日中のオフセットを組み合わせることができます。

In [241]: pd.date_range(start, periods=10, freq="2h20min")
Out[241]: 
DatetimeIndex(['2011-01-01 00:00:00', '2011-01-01 02:20:00',
               '2011-01-01 04:40:00', '2011-01-01 07:00:00',
               '2011-01-01 09:20:00', '2011-01-01 11:40:00',
               '2011-01-01 14:00:00', '2011-01-01 16:20:00',
               '2011-01-01 18:40:00', '2011-01-01 21:00:00'],
              dtype='datetime64[ns]', freq='140min')

In [242]: pd.date_range(start, periods=10, freq="1D10us")
Out[242]: 
DatetimeIndex([       '2011-01-01 00:00:00', '2011-01-02 00:00:00.000010',
               '2011-01-03 00:00:00.000020', '2011-01-04 00:00:00.000030',
               '2011-01-05 00:00:00.000040', '2011-01-06 00:00:00.000050',
               '2011-01-07 00:00:00.000060', '2011-01-08 00:00:00.000070',
               '2011-01-09 00:00:00.000080', '2011-01-10 00:00:00.000090'],
              dtype='datetime64[ns]', freq='86400000010us')

アンカー付きオフセット#

一部の頻度では、アンカー接尾辞を指定できます。

エイリアス

説明

W-SUN

週次頻度(日曜日)。「W」と同じ

W-MON

週次頻度(月曜日)

W-TUE

週次頻度(火曜日)

W-WED

週次頻度(水曜日)

W-THU

週次頻度(木曜日)

W-FRI

週次頻度(金曜日)

W-SAT

週次頻度(土曜日)

(B)Q(E)(S)-DEC

四半期頻度、年は 12 月に終わります。「QE」と同じ

(B)Q(E)(S)-JAN

四半期頻度、年は 1 月に終わります

(B)Q(E)(S)-FEB

四半期頻度、年は 2 月に終わります

(B)Q(E)(S)-MAR

四半期頻度、年は 3 月に終わります

(B)Q(E)(S)-APR

四半期頻度、年は 4 月に終わります

(B)Q(E)(S)-MAY

四半期頻度、年は 5 月に終わります

(B)Q(E)(S)-JUN

四半期頻度、年は 6 月に終わります

(B)Q(E)(S)-JUL

四半期頻度、年は 7 月に終わります

(B)Q(E)(S)-AUG

四半期頻度、年は 8 月に終わります

(B)Q(E)(S)-SEP

四半期頻度、年は 9 月に終わります

(B)Q(E)(S)-OCT

四半期頻度、年は 10 月に終わります

(B)Q(E)(S)-NOV

四半期頻度、年は 11 月に終わります

(B)Y(E)(S)-DEC

年次頻度、12 月のアンカー付き終了。「YE」と同じ

(B)Y(E)(S)-JAN

年次頻度、1 月のアンカー付き終了

(B)Y(E)(S)-FEB

年次頻度、2 月のアンカー付き終了

(B)Y(E)(S)-MAR

年次頻度、3 月のアンカー付き終了

(B)Y(E)(S)-APR

年次頻度、4 月のアンカー付き終了

(B)Y(E)(S)-MAY

年次頻度、5 月のアンカー付き終了

(B)Y(E)(S)-JUN

年次頻度、6 月のアンカー付き終了

(B)Y(E)(S)-JUL

年次頻度、7 月のアンカー付き終了

(B)Y(E)(S)-AUG

年次頻度、8 月のアンカー付き終了

(B)Y(E)(S)-SEP

年次頻度、9 月のアンカー付き終了

(B)Y(E)(S)-OCT

年次頻度、10 月のアンカー付き終了

(B)Y(E)(S)-NOV

年次頻度、11 月のアンカー付き終了

これらは、date_rangebdate_rangeDatetimeIndex のコンストラクター、および pandas のその他のさまざまな時系列関連関数への引数として使用できます。

アンカー付きオフセットのセマンティクス#

特定の頻度(MonthEndMonthBeginWeekEnd など)の開始または終了にアンカーされているオフセットの場合、次のルールが順方向および逆方向のロールに適用されます。

n が 0 でない場合、指定された日付がアンカーポイントにない場合は、次の(前の)アンカーポイントにスナップされ、|n|-1 追加ステップが前進または後退します。

In [243]: pd.Timestamp("2014-01-02") + pd.offsets.MonthBegin(n=1)
Out[243]: Timestamp('2014-02-01 00:00:00')

In [244]: pd.Timestamp("2014-01-02") + pd.offsets.MonthEnd(n=1)
Out[244]: Timestamp('2014-01-31 00:00:00')

In [245]: pd.Timestamp("2014-01-02") - pd.offsets.MonthBegin(n=1)
Out[245]: Timestamp('2014-01-01 00:00:00')

In [246]: pd.Timestamp("2014-01-02") - pd.offsets.MonthEnd(n=1)
Out[246]: Timestamp('2013-12-31 00:00:00')

In [247]: pd.Timestamp("2014-01-02") + pd.offsets.MonthBegin(n=4)
Out[247]: Timestamp('2014-05-01 00:00:00')

In [248]: pd.Timestamp("2014-01-02") - pd.offsets.MonthBegin(n=4)
Out[248]: Timestamp('2013-10-01 00:00:00')

指定された日付がアンカーポイントにある場合は、|n| ポイント前進または後退します。

In [249]: pd.Timestamp("2014-01-01") + pd.offsets.MonthBegin(n=1)
Out[249]: Timestamp('2014-02-01 00:00:00')

In [250]: pd.Timestamp("2014-01-31") + pd.offsets.MonthEnd(n=1)
Out[250]: Timestamp('2014-02-28 00:00:00')

In [251]: pd.Timestamp("2014-01-01") - pd.offsets.MonthBegin(n=1)
Out[251]: Timestamp('2013-12-01 00:00:00')

In [252]: pd.Timestamp("2014-01-31") - pd.offsets.MonthEnd(n=1)
Out[252]: Timestamp('2013-12-31 00:00:00')

In [253]: pd.Timestamp("2014-01-01") + pd.offsets.MonthBegin(n=4)
Out[253]: Timestamp('2014-05-01 00:00:00')

In [254]: pd.Timestamp("2014-01-31") - pd.offsets.MonthBegin(n=4)
Out[254]: Timestamp('2013-10-01 00:00:00')

n=0 の場合、日付がアンカーポイントにある場合は移動されず、そうでない場合は次のアンカーポイントにロールフォワードされます。

In [255]: pd.Timestamp("2014-01-02") + pd.offsets.MonthBegin(n=0)
Out[255]: Timestamp('2014-02-01 00:00:00')

In [256]: pd.Timestamp("2014-01-02") + pd.offsets.MonthEnd(n=0)
Out[256]: Timestamp('2014-01-31 00:00:00')

In [257]: pd.Timestamp("2014-01-01") + pd.offsets.MonthBegin(n=0)
Out[257]: Timestamp('2014-01-01 00:00:00')

In [258]: pd.Timestamp("2014-01-31") + pd.offsets.MonthEnd(n=0)
Out[258]: Timestamp('2014-01-31 00:00:00')

祝日/祝日カレンダー#

祝日とカレンダーは、CustomBusinessDay で使用する、または定義済みの祝日セットが必要な他の分析で使用する祝日ルールを定義する簡単な方法を提供します。 AbstractHolidayCalendar クラスは、祝日のリストを返すために必要なすべてのメソッドを提供し、rules のみを特定の祝日カレンダー クラスで定義する必要があります。さらに、start_date および end_date クラス属性は、祝日が生成される日付範囲を決定します。これらは、すべてのカレンダークラスに範囲を適用するために、AbstractHolidayCalendar クラスで上書きする必要があります。 USFederalHolidayCalendar は存在する唯一のカレンダーであり、主に他のカレンダーを開発するための例として機能します。

固定日(例:米国の戦没将兵追悼記念日または 7 月 4 日)に発生する祝日については、週末またはその他の非観察日に該当する場合に、その祝日がいつ観察されるかを決定する観察ルールがあります。定義された観察ルールは次のとおりです。

ルール

説明

nearest_workday

土曜日を金曜日に、日曜日を月曜日に移動

sunday_to_monday

日曜日を翌月曜日に移動

next_monday_or_tuesday

土曜日を月曜日に、日曜日/月曜日を火曜日に移動

previous_friday

土曜日と日曜日を前の金曜日に移動

next_monday

土曜日と日曜日を翌月曜日に移動

祝日と祝日カレンダーの定義方法の例

In [259]: from pandas.tseries.holiday import (
   .....:     Holiday,
   .....:     USMemorialDay,
   .....:     AbstractHolidayCalendar,
   .....:     nearest_workday,
   .....:     MO,
   .....: )
   .....: 

In [260]: class ExampleCalendar(AbstractHolidayCalendar):
   .....:     rules = [
   .....:         USMemorialDay,
   .....:         Holiday("July 4th", month=7, day=4, observance=nearest_workday),
   .....:         Holiday(
   .....:             "Columbus Day",
   .....:             month=10,
   .....:             day=1,
   .....:             offset=pd.DateOffset(weekday=MO(2)),
   .....:         ),
   .....:     ]
   .....: 

In [261]: cal = ExampleCalendar()

In [262]: cal.holidays(datetime.datetime(2012, 1, 1), datetime.datetime(2012, 12, 31))
Out[262]: DatetimeIndex(['2012-05-28', '2012-07-04', '2012-10-08'], dtype='datetime64[ns]', freq=None)
ヒント:

weekday=MO(2)2 * Week(weekday=2) と同じです

このカレンダーを使用すると、インデックスの作成やオフセット演算を行う際に、週末や祝日(例:戦没将兵追悼記念日、7月4日)がスキップされます。例えば、以下はExampleCalendarを使用してカスタムの営業日オフセットを定義しています。他のオフセットと同様に、DatetimeIndexを作成したり、datetimeTimestampオブジェクトに加算したりすることができます。

In [263]: pd.date_range(
   .....:     start="7/1/2012", end="7/10/2012", freq=pd.offsets.CDay(calendar=cal)
   .....: ).to_pydatetime()
   .....: 
Out[263]: 
array([datetime.datetime(2012, 7, 2, 0, 0),
       datetime.datetime(2012, 7, 3, 0, 0),
       datetime.datetime(2012, 7, 5, 0, 0),
       datetime.datetime(2012, 7, 6, 0, 0),
       datetime.datetime(2012, 7, 9, 0, 0),
       datetime.datetime(2012, 7, 10, 0, 0)], dtype=object)

In [264]: offset = pd.offsets.CustomBusinessDay(calendar=cal)

In [265]: datetime.datetime(2012, 5, 25) + offset
Out[265]: Timestamp('2012-05-29 00:00:00')

In [266]: datetime.datetime(2012, 7, 3) + offset
Out[266]: Timestamp('2012-07-05 00:00:00')

In [267]: datetime.datetime(2012, 7, 3) + 2 * offset
Out[267]: Timestamp('2012-07-06 00:00:00')

In [268]: datetime.datetime(2012, 7, 6) + offset
Out[268]: Timestamp('2012-07-09 00:00:00')

範囲は、AbstractHolidayCalendarstart_dateend_dateクラス属性によって定義されます。デフォルトは以下に示されています。

In [269]: AbstractHolidayCalendar.start_date
Out[269]: Timestamp('1970-01-01 00:00:00')

In [270]: AbstractHolidayCalendar.end_date
Out[270]: Timestamp('2200-12-31 00:00:00')

これらの日付は、属性をdatetime/Timestamp/文字列として設定することで上書きできます。

In [271]: AbstractHolidayCalendar.start_date = datetime.datetime(2012, 1, 1)

In [272]: AbstractHolidayCalendar.end_date = datetime.datetime(2012, 12, 31)

In [273]: cal.holidays()
Out[273]: DatetimeIndex(['2012-05-28', '2012-07-04', '2012-10-08'], dtype='datetime64[ns]', freq=None)

すべてのカレンダー クラスは、祝日クラスのインスタンスを返すget_calendar関数を使用して名前でアクセスできます。インポートされたカレンダー クラスはすべて、この関数で自動的に使用可能になります。また、HolidayCalendarFactoryは、カレンダーの組み合わせや追加ルールを持つカレンダーを作成するための簡単なインターフェースを提供します。

In [274]: from pandas.tseries.holiday import get_calendar, HolidayCalendarFactory, USLaborDay

In [275]: cal = get_calendar("ExampleCalendar")

In [276]: cal.rules
Out[276]: 
[Holiday: Memorial Day (month=5, day=31, offset=<DateOffset: weekday=MO(-1)>),
 Holiday: July 4th (month=7, day=4, observance=<function nearest_workday at 0x7fac095fd2d0>),
 Holiday: Columbus Day (month=10, day=1, offset=<DateOffset: weekday=MO(+2)>)]

In [277]: new_cal = HolidayCalendarFactory("NewExampleCalendar", cal, USLaborDay)

In [278]: new_cal.rules
Out[278]: 
[Holiday: Labor Day (month=9, day=1, offset=<DateOffset: weekday=MO(+1)>),
 Holiday: Memorial Day (month=5, day=31, offset=<DateOffset: weekday=MO(-1)>),
 Holiday: July 4th (month=7, day=4, observance=<function nearest_workday at 0x7fac095fd2d0>),
 Holiday: Columbus Day (month=10, day=1, offset=<DateOffset: weekday=MO(+2)>)]

リサンプリング#

pandasには、頻度変換中のリサンプリング操作(例えば、秒単位のデータを5分単位のデータに変換するなど)を実行するためのシンプルで強力かつ効率的な機能があります。これは、金融アプリケーションで非常に一般的ですが、それに限定されるものではありません。

resample()は、時間ベースのgroupbyであり、その各グループでreductionメソッドが実行されます。いくつかの高度な戦略については、クックブックの例を参照してください。

resample()メソッドは、DataFrameGroupByオブジェクトから直接使用できます。groupbyドキュメントを参照してください。

基本#

In [290]: rng = pd.date_range("1/1/2012", periods=100, freq="s")

In [291]: ts = pd.Series(np.random.randint(0, 500, len(rng)), index=rng)

In [292]: ts.resample("5Min").sum()
Out[292]: 
2012-01-01    25103
Freq: 5min, dtype: int64

resample関数は非常に柔軟性があり、頻度変換とリサンプリング操作を制御するための多くの異なるパラメータを指定できます。

GroupByを介して利用可能な組み込みメソッドは、summeanstdsemmaxminmedianfirstlastohlcなど、返されたオブジェクトのメソッドとして利用できます。

In [293]: ts.resample("5Min").mean()
Out[293]: 
2012-01-01    251.03
Freq: 5min, dtype: float64

In [294]: ts.resample("5Min").ohlc()
Out[294]: 
            open  high  low  close
2012-01-01   308   460    9    205

In [295]: ts.resample("5Min").max()
Out[295]: 
2012-01-01    460
Freq: 5min, dtype: int64

ダウンサンプリングの場合、closedを「left」または「right」に設定して、間隔のどちらの端を閉じるかを指定できます。

In [296]: ts.resample("5Min", closed="right").mean()
Out[296]: 
2011-12-31 23:55:00    308.000000
2012-01-01 00:00:00    250.454545
Freq: 5min, dtype: float64

In [297]: ts.resample("5Min", closed="left").mean()
Out[297]: 
2012-01-01    251.03
Freq: 5min, dtype: float64

labelのようなパラメータは、結果のラベルを操作するために使用されます。labelは、結果に間隔の開始または終了のどちらでラベルを付けるかを指定します。

In [298]: ts.resample("5Min").mean()  # by default label='left'
Out[298]: 
2012-01-01    251.03
Freq: 5min, dtype: float64

In [299]: ts.resample("5Min", label="left").mean()
Out[299]: 
2012-01-01    251.03
Freq: 5min, dtype: float64

警告

labelclosedのデフォルト値は、「ME」、「YE」、「QE」、「BME」、「BYE」、「BQE」、および「W」を除くすべての頻度オフセットで「**left**」であり、これらはすべてデフォルトで「right」になっています。

これにより、意図せずに先を見越してしまう可能性があります。その場合、後の時間の値が前の時間に戻されます。以下に示すBusinessDay頻度の例をご覧ください。

In [300]: s = pd.date_range("2000-01-01", "2000-01-05").to_series()

In [301]: s.iloc[2] = pd.NaT

In [302]: s.dt.day_name()
Out[302]: 
2000-01-01     Saturday
2000-01-02       Sunday
2000-01-03          NaN
2000-01-04      Tuesday
2000-01-05    Wednesday
Freq: D, dtype: object

# default: label='left', closed='left'
In [303]: s.resample("B").last().dt.day_name()
Out[303]: 
1999-12-31       Sunday
2000-01-03          NaN
2000-01-04      Tuesday
2000-01-05    Wednesday
Freq: B, dtype: object

日曜日の値が前の金曜日に戻されていることに注意してください。日曜日の値を月曜日にプッシュする動作を得るには、代わりに以下を使用してください

In [304]: s.resample("B", label="right", closed="right").last().dt.day_name()
Out[304]: 
2000-01-03       Sunday
2000-01-04      Tuesday
2000-01-05    Wednesday
2000-01-06          NaN
Freq: B, dtype: object

axisパラメータは0または1に設定でき、DataFrameに対して指定された軸をリサンプリングできます。

kindは、「timestamp」または「period」に設定して、結果のインデックスをタイムスタンプ表現とタイムスパン表現の間で変換できます。デフォルトでは、resampleは入力表現を保持します。

期間データをリサンプリングするときは、conventionを「start」または「end」に設定できます(詳細は下記)。これは、低頻度の期間を高頻度の期間に変換する方法を指定します。

アップサンプリング#

アップサンプリングの場合、アップサンプリングの方法と、作成されるギャップを補間するためのlimitパラメータを指定できます。

# from secondly to every 250 milliseconds
In [305]: ts[:2].resample("250ms").asfreq()
Out[305]: 
2012-01-01 00:00:00.000    308.0
2012-01-01 00:00:00.250      NaN
2012-01-01 00:00:00.500      NaN
2012-01-01 00:00:00.750      NaN
2012-01-01 00:00:01.000    204.0
Freq: 250ms, dtype: float64

In [306]: ts[:2].resample("250ms").ffill()
Out[306]: 
2012-01-01 00:00:00.000    308
2012-01-01 00:00:00.250    308
2012-01-01 00:00:00.500    308
2012-01-01 00:00:00.750    308
2012-01-01 00:00:01.000    204
Freq: 250ms, dtype: int64

In [307]: ts[:2].resample("250ms").ffill(limit=2)
Out[307]: 
2012-01-01 00:00:00.000    308.0
2012-01-01 00:00:00.250    308.0
2012-01-01 00:00:00.500    308.0
2012-01-01 00:00:00.750      NaN
2012-01-01 00:00:01.000    204.0
Freq: 250ms, dtype: float64

スパースリサンプリング#

スパース時系列は、リサンプリングしようとしている時間に対してポイントが非常に少ないものです。スパース系列をナイーブにアップサンプリングすると、多数の中間値が生成される可能性があります。これらの値を埋めるためにメソッドを使用しない場合(例:fill_methodNoneの場合)、中間値はNaNで埋められます。

resampleは時間ベースのgroupbyであるため、以下はすべてNaNではないグループのみを効率的にリサンプリングするためのメソッドです。

In [308]: rng = pd.date_range("2014-1-1", periods=100, freq="D") + pd.Timedelta("1s")

In [309]: ts = pd.Series(range(100), index=rng)

シリーズの全範囲をリサンプリングする場合

In [310]: ts.resample("3min").sum()
Out[310]: 
2014-01-01 00:00:00     0
2014-01-01 00:03:00     0
2014-01-01 00:06:00     0
2014-01-01 00:09:00     0
2014-01-01 00:12:00     0
                       ..
2014-04-09 23:48:00     0
2014-04-09 23:51:00     0
2014-04-09 23:54:00     0
2014-04-09 23:57:00     0
2014-04-10 00:00:00    99
Freq: 3min, Length: 47521, dtype: int64

代わりに、次のようにポイントがあるグループのみをリサンプリングできます

In [311]: from functools import partial

In [312]: from pandas.tseries.frequencies import to_offset

In [313]: def round(t, freq):
   .....:     freq = to_offset(freq)
   .....:     td = pd.Timedelta(freq)
   .....:     return pd.Timestamp((t.value // td.value) * td.value)
   .....: 

In [314]: ts.groupby(partial(round, freq="3min")).sum()
Out[314]: 
2014-01-01     0
2014-01-02     1
2014-01-03     2
2014-01-04     3
2014-01-05     4
              ..
2014-04-06    95
2014-04-07    96
2014-04-08    97
2014-04-09    98
2014-04-10    99
Length: 100, dtype: int64

集約#

resample()メソッドは、pandas.api.typing.Resamplerインスタンスを返します。集約APIgroupby APIwindow APIと同様に、Resamplerは選択的にリサンプリングできます。

DataFrameをリサンプリングする場合、デフォルトでは同じ関数を使用してすべての列に作用します。

In [315]: df = pd.DataFrame(
   .....:     np.random.randn(1000, 3),
   .....:     index=pd.date_range("1/1/2012", freq="s", periods=1000),
   .....:     columns=["A", "B", "C"],
   .....: )
   .....: 

In [316]: r = df.resample("3min")

In [317]: r.mean()
Out[317]: 
                            A         B         C
2012-01-01 00:00:00 -0.033823 -0.121514 -0.081447
2012-01-01 00:03:00  0.056909  0.146731 -0.024320
2012-01-01 00:06:00 -0.058837  0.047046 -0.052021
2012-01-01 00:09:00  0.063123 -0.026158 -0.066533
2012-01-01 00:12:00  0.186340 -0.003144  0.074752
2012-01-01 00:15:00 -0.085954 -0.016287 -0.050046

標準のgetitemを使用して、特定の列または列を選択できます。

In [318]: r["A"].mean()
Out[318]: 
2012-01-01 00:00:00   -0.033823
2012-01-01 00:03:00    0.056909
2012-01-01 00:06:00   -0.058837
2012-01-01 00:09:00    0.063123
2012-01-01 00:12:00    0.186340
2012-01-01 00:15:00   -0.085954
Freq: 3min, Name: A, dtype: float64

In [319]: r[["A", "B"]].mean()
Out[319]: 
                            A         B
2012-01-01 00:00:00 -0.033823 -0.121514
2012-01-01 00:03:00  0.056909  0.146731
2012-01-01 00:06:00 -0.058837  0.047046
2012-01-01 00:09:00  0.063123 -0.026158
2012-01-01 00:12:00  0.186340 -0.003144
2012-01-01 00:15:00 -0.085954 -0.016287

関数をリストまたはdictで渡して集計を行い、DataFrameを出力できます。

In [320]: r["A"].agg(["sum", "mean", "std"])
Out[320]: 
                           sum      mean       std
2012-01-01 00:00:00  -6.088060 -0.033823  1.043263
2012-01-01 00:03:00  10.243678  0.056909  1.058534
2012-01-01 00:06:00 -10.590584 -0.058837  0.949264
2012-01-01 00:09:00  11.362228  0.063123  1.028096
2012-01-01 00:12:00  33.541257  0.186340  0.884586
2012-01-01 00:15:00  -8.595393 -0.085954  1.035476

リサンプリングされたDataFrameで、各列に適用する関数のリストを渡すことができます。これにより、階層インデックスを持つ集計結果が生成されます。

In [321]: r.agg(["sum", "mean"])
Out[321]: 
                             A            ...          C          
                           sum      mean  ...        sum      mean
2012-01-01 00:00:00  -6.088060 -0.033823  ... -14.660515 -0.081447
2012-01-01 00:03:00  10.243678  0.056909  ...  -4.377642 -0.024320
2012-01-01 00:06:00 -10.590584 -0.058837  ...  -9.363825 -0.052021
2012-01-01 00:09:00  11.362228  0.063123  ... -11.975895 -0.066533
2012-01-01 00:12:00  33.541257  0.186340  ...  13.455299  0.074752
2012-01-01 00:15:00  -8.595393 -0.085954  ...  -5.004580 -0.050046

[6 rows x 6 columns]

aggregateにdictを渡すことで、DataFrameの列に異なる集計を適用できます。

In [322]: r.agg({"A": "sum", "B": lambda x: np.std(x, ddof=1)})
Out[322]: 
                             A         B
2012-01-01 00:00:00  -6.088060  1.001294
2012-01-01 00:03:00  10.243678  1.074597
2012-01-01 00:06:00 -10.590584  0.987309
2012-01-01 00:09:00  11.362228  0.944953
2012-01-01 00:12:00  33.541257  1.095025
2012-01-01 00:15:00  -8.595393  1.035312

関数名は文字列にすることもできます。文字列が有効であるためには、リサンプリングされたオブジェクトに実装されている必要があります。

In [323]: r.agg({"A": "sum", "B": "std"})
Out[323]: 
                             A         B
2012-01-01 00:00:00  -6.088060  1.001294
2012-01-01 00:03:00  10.243678  1.074597
2012-01-01 00:06:00 -10.590584  0.987309
2012-01-01 00:09:00  11.362228  0.944953
2012-01-01 00:12:00  33.541257  1.095025
2012-01-01 00:15:00  -8.595393  1.035312

さらに、各列に対して複数の集計関数を個別に指定することもできます。

In [324]: r.agg({"A": ["sum", "std"], "B": ["mean", "std"]})
Out[324]: 
                             A                   B          
                           sum       std      mean       std
2012-01-01 00:00:00  -6.088060  1.043263 -0.121514  1.001294
2012-01-01 00:03:00  10.243678  1.058534  0.146731  1.074597
2012-01-01 00:06:00 -10.590584  0.949264  0.047046  0.987309
2012-01-01 00:09:00  11.362228  1.028096 -0.026158  0.944953
2012-01-01 00:12:00  33.541257  0.884586 -0.003144  1.095025
2012-01-01 00:15:00  -8.595393  1.035476 -0.016287  1.035312

もしDataFrameがdatetimeライクなインデックスを持っておらず、代わりにフレーム内のdatetimeライクな列に基づいてリサンプリングしたい場合は、onキーワードにそれを渡すことができます。

In [325]: df = pd.DataFrame(
   .....:     {"date": pd.date_range("2015-01-01", freq="W", periods=5), "a": np.arange(5)},
   .....:     index=pd.MultiIndex.from_arrays(
   .....:         [[1, 2, 3, 4, 5], pd.date_range("2015-01-01", freq="W", periods=5)],
   .....:         names=["v", "d"],
   .....:     ),
   .....: )
   .....: 

In [326]: df
Out[326]: 
                   date  a
v d                       
1 2015-01-04 2015-01-04  0
2 2015-01-11 2015-01-11  1
3 2015-01-18 2015-01-18  2
4 2015-01-25 2015-01-25  3
5 2015-02-01 2015-02-01  4

In [327]: df.resample("ME", on="date")[["a"]].sum()
Out[327]: 
            a
date         
2015-01-31  6
2015-02-28  4

同様に、MultiIndexのdatetimeライクなレベルでリサンプリングしたい場合は、その名前または位置をlevelキーワードに渡すことができます。

In [328]: df.resample("ME", level="d")[["a"]].sum()
Out[328]: 
            a
d            
2015-01-31  6
2015-02-28  4

グループの反復処理#

Resamplerオブジェクトを手に入れたら、グループ化されたデータの反復処理は非常に自然で、itertools.groupby()と同様に機能します。

In [329]: small = pd.Series(
   .....:     range(6),
   .....:     index=pd.to_datetime(
   .....:         [
   .....:             "2017-01-01T00:00:00",
   .....:             "2017-01-01T00:30:00",
   .....:             "2017-01-01T00:31:00",
   .....:             "2017-01-01T01:00:00",
   .....:             "2017-01-01T03:00:00",
   .....:             "2017-01-01T03:05:00",
   .....:         ]
   .....:     ),
   .....: )
   .....: 

In [330]: resampled = small.resample("h")

In [331]: for name, group in resampled:
   .....:     print("Group: ", name)
   .....:     print("-" * 27)
   .....:     print(group, end="\n\n")
   .....: 
Group:  2017-01-01 00:00:00
---------------------------
2017-01-01 00:00:00    0
2017-01-01 00:30:00    1
2017-01-01 00:31:00    2
dtype: int64

Group:  2017-01-01 01:00:00
---------------------------
2017-01-01 01:00:00    3
dtype: int64

Group:  2017-01-01 02:00:00
---------------------------
Series([], dtype: int64)

Group:  2017-01-01 03:00:00
---------------------------
2017-01-01 03:00:00    4
2017-01-01 03:05:00    5
dtype: int64

詳細については、グループの反復処理またはResampler.__iter__を参照してください。

ビンの開始を調整するためにoriginまたはoffsetを使用する#

グループ化のビンは、時系列の開始点の日の始まりに基づいて調整されます。これは、1日の倍数(30Dなど)または1日を均等に分割する頻度(90s1minなど)とうまく機能します。これにより、この基準を満たさない一部の頻度で矛盾が生じる可能性があります。この動作を変更するには、引数originを使用して固定のTimestampを指定できます。

例えば

In [332]: start, end = "2000-10-01 23:30:00", "2000-10-02 00:30:00"

In [333]: middle = "2000-10-02 00:00:00"

In [334]: rng = pd.date_range(start, end, freq="7min")

In [335]: ts = pd.Series(np.arange(len(rng)) * 3, index=rng)

In [336]: ts
Out[336]: 
2000-10-01 23:30:00     0
2000-10-01 23:37:00     3
2000-10-01 23:44:00     6
2000-10-01 23:51:00     9
2000-10-01 23:58:00    12
2000-10-02 00:05:00    15
2000-10-02 00:12:00    18
2000-10-02 00:19:00    21
2000-10-02 00:26:00    24
Freq: 7min, dtype: int64

ここで、originをデフォルト値('start_day')で使用すると、'2000-10-02 00:00:00'以降の結果が、時系列の開始点によって同一ではないことがわかります。

In [337]: ts.resample("17min", origin="start_day").sum()
Out[337]: 
2000-10-01 23:14:00     0
2000-10-01 23:31:00     9
2000-10-01 23:48:00    21
2000-10-02 00:05:00    54
2000-10-02 00:22:00    24
Freq: 17min, dtype: int64

In [338]: ts[middle:end].resample("17min", origin="start_day").sum()
Out[338]: 
2000-10-02 00:00:00    33
2000-10-02 00:17:00    45
Freq: 17min, dtype: int64

ここで、origin'epoch'に設定すると、'2000-10-02 00:00:00'以降の結果が、時系列の開始点に関係なく同一であることがわかります。

In [339]: ts.resample("17min", origin="epoch").sum()
Out[339]: 
2000-10-01 23:18:00     0
2000-10-01 23:35:00    18
2000-10-01 23:52:00    27
2000-10-02 00:09:00    39
2000-10-02 00:26:00    24
Freq: 17min, dtype: int64

In [340]: ts[middle:end].resample("17min", origin="epoch").sum()
Out[340]: 
2000-10-01 23:52:00    15
2000-10-02 00:09:00    39
2000-10-02 00:26:00    24
Freq: 17min, dtype: int64

必要に応じて、originにカスタムのタイムスタンプを使用できます。

In [341]: ts.resample("17min", origin="2001-01-01").sum()
Out[341]: 
2000-10-01 23:30:00     9
2000-10-01 23:47:00    21
2000-10-02 00:04:00    54
2000-10-02 00:21:00    24
Freq: 17min, dtype: int64

In [342]: ts[middle:end].resample("17min", origin=pd.Timestamp("2001-01-01")).sum()
Out[342]: 
2000-10-02 00:04:00    54
2000-10-02 00:21:00    24
Freq: 17min, dtype: int64

必要に応じて、デフォルトのoriginに追加されるoffset Timedeltaでビンを調整することもできます。これらの2つの例は、この時系列では同等です。

In [343]: ts.resample("17min", origin="start").sum()
Out[343]: 
2000-10-01 23:30:00     9
2000-10-01 23:47:00    21
2000-10-02 00:04:00    54
2000-10-02 00:21:00    24
Freq: 17min, dtype: int64

In [344]: ts.resample("17min", offset="23h30min").sum()
Out[344]: 
2000-10-01 23:30:00     9
2000-10-01 23:47:00    21
2000-10-02 00:04:00    54
2000-10-02 00:21:00    24
Freq: 17min, dtype: int64

最後の例では、origin'start'を使用していることに注意してください。その場合、originは時系列の最初の値に設定されます。

後方リサンプリング#

バージョン 1.3.0 で新規追加.

ビンの開始を調整する代わりに、指定されたfreqで後方リサンプリングを行うためにビンの終了を固定する必要がある場合があります。後方リサンプリングでは、最後の値が最後のビンの端点と見なされるため、デフォルトでclosed'right'に設定されます。

origin'end'に設定できます。特定のTimestampインデックスの値は、現在のTimestampからfreqを引いたものから現在のTimestampまでの右端を閉じたリサンプリング結果を表します。

In [345]: ts.resample('17min', origin='end').sum()
Out[345]: 
2000-10-01 23:35:00     0
2000-10-01 23:52:00    18
2000-10-02 00:09:00    27
2000-10-02 00:26:00    63
Freq: 17min, dtype: int64

さらに、'start_day'オプションとは対照的に、end_dayがサポートされています。これにより、最大Timestampの天井の真夜中が開始点として設定されます。

In [346]: ts.resample('17min', origin='end_day').sum()
Out[346]: 
2000-10-01 23:38:00     3
2000-10-01 23:55:00    15
2000-10-02 00:12:00    45
2000-10-02 00:29:00    45
Freq: 17min, dtype: int64

上記の結果では、次の計算のため、最後のビンの右端として2000-10-02 00:29:00が使用されます。

In [347]: ceil_mid = rng.max().ceil('D')

In [348]: freq = pd.offsets.Minute(17)

In [349]: bin_res = ceil_mid - freq * ((ceil_mid - rng.max()) // freq)

In [350]: bin_res
Out[350]: Timestamp('2000-10-02 00:29:00')

時間スパンの表現#

pandasでは、規則的な時間間隔はPeriodオブジェクトで表され、Periodオブジェクトのシーケンスは、便利な関数period_rangeで作成できるPeriodIndexに収集されます。

Period#

Periodは、時間のスパン(例:日、月、四半期など)を表します。以下のように、頻度エイリアスを使用してfreqキーワードでスパンを指定できます。freqPeriodのスパンを表すため、「-3D」のように負にすることはできません。

In [351]: pd.Period("2012", freq="Y-DEC")
Out[351]: Period('2012', 'Y-DEC')

In [352]: pd.Period("2012-1-1", freq="D")
Out[352]: Period('2012-01-01', 'D')

In [353]: pd.Period("2012-1-1 19:00", freq="h")
Out[353]: Period('2012-01-01 19:00', 'h')

In [354]: pd.Period("2012-1-1 19:00", freq="5h")
Out[354]: Period('2012-01-01 19:00', '5h')

Periodに整数を加算または減算すると、Periodが独自の頻度でシフトします。異なるfreq(スパン)を持つPeriod間では算術演算は許可されていません。

In [355]: p = pd.Period("2012", freq="Y-DEC")

In [356]: p + 1
Out[356]: Period('2013', 'Y-DEC')

In [357]: p - 3
Out[357]: Period('2009', 'Y-DEC')

In [358]: p = pd.Period("2012-01", freq="2M")

In [359]: p + 2
Out[359]: Period('2012-05', '2M')

In [360]: p - 1
Out[360]: Period('2011-11', '2M')

In [361]: p == pd.Period("2012-01", freq="3M")
Out[361]: False

Periodのfreqが毎日以上(Dhminsmsus、およびns)の場合、結果が同じfreqを持つことができる場合、offsetsおよびtimedeltaのようなものを追加できます。それ以外の場合は、ValueErrorが発生します。

In [362]: p = pd.Period("2014-07-01 09:00", freq="h")

In [363]: p + pd.offsets.Hour(2)
Out[363]: Period('2014-07-01 11:00', 'h')

In [364]: p + datetime.timedelta(minutes=120)
Out[364]: Period('2014-07-01 11:00', 'h')

In [365]: p + np.timedelta64(7200, "s")
Out[365]: Period('2014-07-01 11:00', 'h')
In [366]: p + pd.offsets.Minute(5)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
File period.pyx:1824, in pandas._libs.tslibs.period._Period._add_timedeltalike_scalar()

File timedeltas.pyx:278, in pandas._libs.tslibs.timedeltas.delta_to_nanoseconds()

File np_datetime.pyx:661, in pandas._libs.tslibs.np_datetime.convert_reso()

ValueError: Cannot losslessly convert units

The above exception was the direct cause of the following exception:

IncompatibleFrequency                     Traceback (most recent call last)
Cell In[366], line 1
----> 1 p + pd.offsets.Minute(5)

File period.pyx:1845, in pandas._libs.tslibs.period._Period.__add__()

File period.pyx:1826, in pandas._libs.tslibs.period._Period._add_timedeltalike_scalar()

IncompatibleFrequency: Input cannot be converted to Period(freq=h)

Periodに他の頻度がある場合は、同じoffsetsのみを追加できます。それ以外の場合は、ValueErrorが発生します。

In [367]: p = pd.Period("2014-07", freq="M")

In [368]: p + pd.offsets.MonthEnd(3)
Out[368]: Period('2014-10', 'M')
In [369]: p + pd.offsets.MonthBegin(3)
---------------------------------------------------------------------------
IncompatibleFrequency                     Traceback (most recent call last)
Cell In[369], line 1
----> 1 p + pd.offsets.MonthBegin(3)

File period.pyx:1847, in pandas._libs.tslibs.period._Period.__add__()

File period.pyx:1837, in pandas._libs.tslibs.period._Period._add_offset()

File period.pyx:1732, in pandas._libs.tslibs.period.PeriodMixin._require_matching_freq()

IncompatibleFrequency: Input has different freq=3M from Period(freq=M)

同じ頻度のPeriodインスタンスの差を取ると、それらの間の頻度単位の数が返されます。

In [370]: pd.Period("2012", freq="Y-DEC") - pd.Period("2002", freq="Y-DEC")
Out[370]: <10 * YearEnds: month=12>

PeriodIndexとperiod_range#

Periodオブジェクトの規則的なシーケンスは、便利な関数period_rangeを使用して構築できるPeriodIndexに収集できます。

In [371]: prng = pd.period_range("1/1/2011", "1/1/2012", freq="M")

In [372]: prng
Out[372]: 
PeriodIndex(['2011-01', '2011-02', '2011-03', '2011-04', '2011-05', '2011-06',
             '2011-07', '2011-08', '2011-09', '2011-10', '2011-11', '2011-12',
             '2012-01'],
            dtype='period[M]')

PeriodIndexコンストラクターも直接使用できます。

In [373]: pd.PeriodIndex(["2011-1", "2011-2", "2011-3"], freq="M")
Out[373]: PeriodIndex(['2011-01', '2011-02', '2011-03'], dtype='period[M]')

乗算された頻数を渡すと、乗算されたスパンを持つPeriodのシーケンスが出力されます。

In [374]: pd.period_range(start="2014-01", freq="3M", periods=4)
Out[374]: PeriodIndex(['2014-01', '2014-04', '2014-07', '2014-10'], dtype='period[3M]')

startまたはendPeriodオブジェクトである場合、PeriodIndexコンストラクターの頻度に一致する頻度を持つPeriodIndexのアンカーエンドポイントとして使用されます。

In [375]: pd.period_range(
   .....:     start=pd.Period("2017Q1", freq="Q"), end=pd.Period("2017Q2", freq="Q"), freq="M"
   .....: )
   .....: 
Out[375]: PeriodIndex(['2017-03', '2017-04', '2017-05', '2017-06'], dtype='period[M]')

DatetimeIndexと同様に、PeriodIndexを使用してpandasオブジェクトのインデックスを作成することもできます。

In [376]: ps = pd.Series(np.random.randn(len(prng)), prng)

In [377]: ps
Out[377]: 
2011-01   -2.916901
2011-02    0.514474
2011-03    1.346470
2011-04    0.816397
2011-05    2.258648
2011-06    0.494789
2011-07    0.301239
2011-08    0.464776
2011-09   -1.393581
2011-10    0.056780
2011-11    0.197035
2011-12    2.261385
2012-01   -0.329583
Freq: M, dtype: float64

PeriodIndexは、Periodと同じルールで加算と減算をサポートしています。

In [378]: idx = pd.period_range("2014-07-01 09:00", periods=5, freq="h")

In [379]: idx
Out[379]: 
PeriodIndex(['2014-07-01 09:00', '2014-07-01 10:00', '2014-07-01 11:00',
             '2014-07-01 12:00', '2014-07-01 13:00'],
            dtype='period[h]')

In [380]: idx + pd.offsets.Hour(2)
Out[380]: 
PeriodIndex(['2014-07-01 11:00', '2014-07-01 12:00', '2014-07-01 13:00',
             '2014-07-01 14:00', '2014-07-01 15:00'],
            dtype='period[h]')

In [381]: idx = pd.period_range("2014-07", periods=5, freq="M")

In [382]: idx
Out[382]: PeriodIndex(['2014-07', '2014-08', '2014-09', '2014-10', '2014-11'], dtype='period[M]')

In [383]: idx + pd.offsets.MonthEnd(3)
Out[383]: PeriodIndex(['2014-10', '2014-11', '2014-12', '2015-01', '2015-02'], dtype='period[M]')

PeriodIndexにはperiodという名前の独自のdtypeがあります。Period Dtypesを参照してください。

Period dtype#

PeriodIndexにはカスタムのperiod dtypeがあります。これは、タイムゾーン対応dtypedatetime64[ns, tz])と同様のpandas拡張dtypeです。

period dtypeはfreq属性を保持し、頻度文字列を使用して、period[D]period[M]のように、period[freq]で表されます。

In [384]: pi = pd.period_range("2016-01-01", periods=3, freq="M")

In [385]: pi
Out[385]: PeriodIndex(['2016-01', '2016-02', '2016-03'], dtype='period[M]')

In [386]: pi.dtype
Out[386]: period[M]

period dtypeは、.astype(...)で使用できます。これにより、.asfreq()のようにPeriodIndexfreqを変更したり、to_period()のようにDatetimeIndexPeriodIndexに変換したりできます。

# change monthly freq to daily freq
In [387]: pi.astype("period[D]")
Out[387]: PeriodIndex(['2016-01-31', '2016-02-29', '2016-03-31'], dtype='period[D]')

# convert to DatetimeIndex
In [388]: pi.astype("datetime64[ns]")
Out[388]: DatetimeIndex(['2016-01-01', '2016-02-01', '2016-03-01'], dtype='datetime64[ns]', freq='MS')

# convert to PeriodIndex
In [389]: dti = pd.date_range("2011-01-01", freq="ME", periods=3)

In [390]: dti
Out[390]: DatetimeIndex(['2011-01-31', '2011-02-28', '2011-03-31'], dtype='datetime64[ns]', freq='ME')

In [391]: dti.astype("period[M]")
Out[391]: PeriodIndex(['2011-01', '2011-02', '2011-03'], dtype='period[M]')

PeriodIndexの部分文字列インデックス#

PeriodIndexは、非単調インデックスを使用した部分文字列スライスをサポートするようになりました。

DatetimeIndexと同じ方法で、PeriodIndexを使用して、日付と文字列をSeriesおよびDataFrameに渡すことができます。詳細については、DatetimeIndex部分文字列インデックスを参照してください。

In [392]: ps["2011-01"]
Out[392]: -2.9169013294054507

In [393]: ps[datetime.datetime(2011, 12, 25):]
Out[393]: 
2011-12    2.261385
2012-01   -0.329583
Freq: M, dtype: float64

In [394]: ps["10/31/2011":"12/31/2011"]
Out[394]: 
2011-10    0.056780
2011-11    0.197035
2011-12    2.261385
Freq: M, dtype: float64

PeriodIndexよりも低い頻度を表す文字列を渡すと、部分的にスライスされたデータが返されます。

In [395]: ps["2011"]
Out[395]: 
2011-01   -2.916901
2011-02    0.514474
2011-03    1.346470
2011-04    0.816397
2011-05    2.258648
2011-06    0.494789
2011-07    0.301239
2011-08    0.464776
2011-09   -1.393581
2011-10    0.056780
2011-11    0.197035
2011-12    2.261385
Freq: M, dtype: float64

In [396]: dfp = pd.DataFrame(
   .....:     np.random.randn(600, 1),
   .....:     columns=["A"],
   .....:     index=pd.period_range("2013-01-01 9:00", periods=600, freq="min"),
   .....: )
   .....: 

In [397]: dfp
Out[397]: 
                         A
2013-01-01 09:00 -0.538468
2013-01-01 09:01 -1.365819
2013-01-01 09:02 -0.969051
2013-01-01 09:03 -0.331152
2013-01-01 09:04 -0.245334
...                    ...
2013-01-01 18:55  0.522460
2013-01-01 18:56  0.118710
2013-01-01 18:57  0.167517
2013-01-01 18:58  0.922883
2013-01-01 18:59  1.721104

[600 rows x 1 columns]

In [398]: dfp.loc["2013-01-01 10h"]
Out[398]: 
                         A
2013-01-01 10:00 -0.308975
2013-01-01 10:01  0.542520
2013-01-01 10:02  1.061068
2013-01-01 10:03  0.754005
2013-01-01 10:04  0.352933
...                    ...
2013-01-01 10:55 -0.865621
2013-01-01 10:56 -1.167818
2013-01-01 10:57 -2.081748
2013-01-01 10:58 -0.527146
2013-01-01 10:59  0.802298

[60 rows x 1 columns]

DatetimeIndexと同様に、エンドポイントは結果に含まれます。以下の例では、10:00から11:59までのデータをスライスしています。

In [399]: dfp["2013-01-01 10h":"2013-01-01 11h"]
Out[399]: 
                         A
2013-01-01 10:00 -0.308975
2013-01-01 10:01  0.542520
2013-01-01 10:02  1.061068
2013-01-01 10:03  0.754005
2013-01-01 10:04  0.352933
...                    ...
2013-01-01 11:55 -0.590204
2013-01-01 11:56  1.539990
2013-01-01 11:57 -1.224826
2013-01-01 11:58  0.578798
2013-01-01 11:59 -0.685496

[120 rows x 1 columns]

PeriodIndexによる頻度変換とリサンプリング#

PeriodおよびPeriodIndexの頻度は、asfreqメソッドを介して変換できます。12月に終わる2011会計年度から始めましょう。

In [400]: p = pd.Period("2011", freq="Y-DEC")

In [401]: p
Out[401]: Period('2011', 'Y-DEC')

これを月次頻度に変換できます。how パラメータを使用すると、開始月または終了月のどちらを返すかを指定できます。

In [402]: p.asfreq("M", how="start")
Out[402]: Period('2011-01', 'M')

In [403]: p.asfreq("M", how="end")
Out[403]: Period('2011-12', 'M')

便宜上、短縮形の ‘s’ と ‘e’ が用意されています。

In [404]: p.asfreq("M", "s")
Out[404]: Period('2011-01', 'M')

In [405]: p.asfreq("M", "e")
Out[405]: Period('2011-12', 'M')

「スーパー期間」への変換(例えば、年次頻度は四半期頻度のスーパー期間です)は、入力期間を含むスーパー期間を自動的に返します。

In [406]: p = pd.Period("2011-12", freq="M")

In [407]: p.asfreq("Y-NOV")
Out[407]: Period('2012', 'Y-NOV')

11月に年末を迎える年次頻度に変換したため、2011年12月の月次期間は実際には2012年のY-NOV期間に含まれることに注意してください。

固定された頻度での期間変換は、経済、ビジネス、その他の分野で一般的なさまざまな四半期データを取り扱う場合に特に便利です。多くの組織では、会計年度の開始月と終了月を基準として四半期を定義します。したがって、2011年の第1四半期は2010年に開始することも、2011年の数ヶ月後に開始することもできます。固定された頻度を使用することで、pandasはQ-JAN から Q-DEC までのすべての四半期頻度に対応します。

Q-DEC は通常の暦四半期を定義します。

In [408]: p = pd.Period("2012Q1", freq="Q-DEC")

In [409]: p.asfreq("D", "s")
Out[409]: Period('2012-01-01', 'D')

In [410]: p.asfreq("D", "e")
Out[410]: Period('2012-03-31', 'D')

Q-MAR は3月に会計年度末を定義します。

In [411]: p = pd.Period("2011Q4", freq="Q-MAR")

In [412]: p.asfreq("D", "s")
Out[412]: Period('2011-01-01', 'D')

In [413]: p.asfreq("D", "e")
Out[413]: Period('2011-03-31', 'D')

表現間の変換#

タイムスタンプ付きデータは、to_period を使用して PeriodIndex 形式のデータに変換でき、逆に to_timestamp を使用して変換できます。

In [414]: rng = pd.date_range("1/1/2012", periods=5, freq="ME")

In [415]: ts = pd.Series(np.random.randn(len(rng)), index=rng)

In [416]: ts
Out[416]: 
2012-01-31    1.931253
2012-02-29   -0.184594
2012-03-31    0.249656
2012-04-30   -0.978151
2012-05-31   -0.873389
Freq: ME, dtype: float64

In [417]: ps = ts.to_period()

In [418]: ps
Out[418]: 
2012-01    1.931253
2012-02   -0.184594
2012-03    0.249656
2012-04   -0.978151
2012-05   -0.873389
Freq: M, dtype: float64

In [419]: ps.to_timestamp()
Out[419]: 
2012-01-01    1.931253
2012-02-01   -0.184594
2012-03-01    0.249656
2012-04-01   -0.978151
2012-05-01   -0.873389
Freq: MS, dtype: float64

‘s’ と ‘e’ を使用して、期間の開始時または終了時のタイムスタンプを返すことができることを覚えておいてください。

In [420]: ps.to_timestamp("D", how="s")
Out[420]: 
2012-01-01    1.931253
2012-02-01   -0.184594
2012-03-01    0.249656
2012-04-01   -0.978151
2012-05-01   -0.873389
Freq: MS, dtype: float64

期間とタイムスタンプ間の変換により、いくつかの便利な算術関数を使用できます。次の例では、11月に年末を迎える四半期頻度を、四半期末の翌月末の午前9時に変換します。

In [421]: prng = pd.period_range("1990Q1", "2000Q4", freq="Q-NOV")

In [422]: ts = pd.Series(np.random.randn(len(prng)), prng)

In [423]: ts.index = (prng.asfreq("M", "e") + 1).asfreq("h", "s") + 9

In [424]: ts.head()
Out[424]: 
1990-03-01 09:00   -0.109291
1990-06-01 09:00   -0.637235
1990-09-01 09:00   -1.735925
1990-12-01 09:00    2.096946
1991-03-01 09:00   -1.039926
Freq: h, dtype: float64

範囲外のスパンの表現#

Timestamp の範囲外にあるデータがある場合は、タイムスタンプの制限を参照してください。その場合、PeriodIndexPeriodsSeries を使用して計算を実行できます。

In [425]: span = pd.period_range("1215-01-01", "1381-01-01", freq="D")

In [426]: span
Out[426]: 
PeriodIndex(['1215-01-01', '1215-01-02', '1215-01-03', '1215-01-04',
             '1215-01-05', '1215-01-06', '1215-01-07', '1215-01-08',
             '1215-01-09', '1215-01-10',
             ...
             '1380-12-23', '1380-12-24', '1380-12-25', '1380-12-26',
             '1380-12-27', '1380-12-28', '1380-12-29', '1380-12-30',
             '1380-12-31', '1381-01-01'],
            dtype='period[D]', length=60632)

int64 ベースの YYYYMMDD 表現から変換するには。

In [427]: s = pd.Series([20121231, 20141130, 99991231])

In [428]: s
Out[428]: 
0    20121231
1    20141130
2    99991231
dtype: int64

In [429]: def conv(x):
   .....:     return pd.Period(year=x // 10000, month=x // 100 % 100, day=x % 100, freq="D")
   .....: 

In [430]: s.apply(conv)
Out[430]: 
0    2012-12-31
1    2014-11-30
2    9999-12-31
dtype: period[D]

In [431]: s.apply(conv)[2]
Out[431]: Period('9999-12-31', 'D')

これらは簡単に PeriodIndex に変換できます。

In [432]: span = pd.PeriodIndex(s.apply(conv))

In [433]: span
Out[433]: PeriodIndex(['2012-12-31', '2014-11-30', '9999-12-31'], dtype='period[D]')

タイムゾーンの処理#

pandasは、pytz ライブラリ、dateutil ライブラリ、または標準ライブラリの datetime.timezone オブジェクトを使用して、さまざまなタイムゾーンのタイムスタンプを処理するための豊富なサポートを提供します。

タイムゾーンの操作#

デフォルトでは、pandasオブジェクトはタイムゾーンを認識しません。

In [434]: rng = pd.date_range("3/6/2012 00:00", periods=15, freq="D")

In [435]: rng.tz is None
Out[435]: True

これらの日付をタイムゾーンにローカライズする(特定のタイムゾーンをnaiveな日付に割り当てる)には、tz_localize メソッドまたは date_range()Timestamp、または DatetimeIndextz キーワード引数を使用できます。pytz または dateutil タイムゾーンオブジェクト、または Olson タイムゾーンデータベース文字列を渡すことができます。Olson タイムゾーン文字列は、デフォルトで pytz タイムゾーンオブジェクトを返します。dateutil タイムゾーンオブジェクトを返すには、文字列の前に dateutil/ を付加します。

  • pytz では、from pytz import common_timezones, all_timezones を使用して、一般的(およびあまり一般的でない)タイムゾーンのリストを見つけることができます。

  • dateutil は OS のタイムゾーンを使用するため、固定リストは利用できません。一般的なゾーンの場合、名前は pytz と同じです。

In [436]: import dateutil

# pytz
In [437]: rng_pytz = pd.date_range("3/6/2012 00:00", periods=3, freq="D", tz="Europe/London")

In [438]: rng_pytz.tz
Out[438]: <DstTzInfo 'Europe/London' LMT-1 day, 23:59:00 STD>

# dateutil
In [439]: rng_dateutil = pd.date_range("3/6/2012 00:00", periods=3, freq="D")

In [440]: rng_dateutil = rng_dateutil.tz_localize("dateutil/Europe/London")

In [441]: rng_dateutil.tz
Out[441]: tzfile('/usr/share/zoneinfo/Europe/London')

# dateutil - utc special case
In [442]: rng_utc = pd.date_range(
   .....:     "3/6/2012 00:00",
   .....:     periods=3,
   .....:     freq="D",
   .....:     tz=dateutil.tz.tzutc(),
   .....: )
   .....: 

In [443]: rng_utc.tz
Out[443]: tzutc()
# datetime.timezone
In [444]: rng_utc = pd.date_range(
   .....:     "3/6/2012 00:00",
   .....:     periods=3,
   .....:     freq="D",
   .....:     tz=datetime.timezone.utc,
   .....: )
   .....: 

In [445]: rng_utc.tz
Out[445]: datetime.timezone.utc

UTC タイムゾーンは dateutil では特殊なケースであり、dateutil.tz.tzutc のインスタンスとして明示的に構築する必要があることに注意してください。他のタイムゾーンオブジェクトも最初に明示的に構築できます。

In [446]: import pytz

# pytz
In [447]: tz_pytz = pytz.timezone("Europe/London")

In [448]: rng_pytz = pd.date_range("3/6/2012 00:00", periods=3, freq="D")

In [449]: rng_pytz = rng_pytz.tz_localize(tz_pytz)

In [450]: rng_pytz.tz == tz_pytz
Out[450]: True

# dateutil
In [451]: tz_dateutil = dateutil.tz.gettz("Europe/London")

In [452]: rng_dateutil = pd.date_range("3/6/2012 00:00", periods=3, freq="D", tz=tz_dateutil)

In [453]: rng_dateutil.tz == tz_dateutil
Out[453]: True

タイムゾーンを認識する pandas オブジェクトをあるタイムゾーンから別のタイムゾーンに変換するには、tz_convert メソッドを使用できます。

In [454]: rng_pytz.tz_convert("US/Eastern")
Out[454]: 
DatetimeIndex(['2012-03-05 19:00:00-05:00', '2012-03-06 19:00:00-05:00',
               '2012-03-07 19:00:00-05:00'],
              dtype='datetime64[ns, US/Eastern]', freq=None)

注意

pytz タイムゾーンを使用する場合、DatetimeIndex は、同じタイムゾーン入力に対して Timestamp とは異なるタイムゾーンオブジェクトを構築します。DatetimeIndex は、異なる UTC オフセットを持つ可能性があり、1つの pytz タイムゾーンインスタンスで簡潔に表現できない Timestamp オブジェクトのコレクションを保持できます。一方、1つの Timestamp は、特定の UTC オフセットを持つ1つの時点を表します。

In [455]: dti = pd.date_range("2019-01-01", periods=3, freq="D", tz="US/Pacific")

In [456]: dti.tz
Out[456]: <DstTzInfo 'US/Pacific' LMT-1 day, 16:07:00 STD>

In [457]: ts = pd.Timestamp("2019-01-01", tz="US/Pacific")

In [458]: ts.tz
Out[458]: <DstTzInfo 'US/Pacific' PST-1 day, 16:00:00 STD>

警告

ライブラリ間の変換には注意してください。一部のタイムゾーンでは、pytzdateutil のゾーン定義が異なります。これは、US/Eastern のような「標準」ゾーンよりも、珍しいタイムゾーンでより問題になります。

警告

タイムゾーンライブラリのバージョン間でタイムゾーン定義が同じと見なされない場合があることに注意してください。これは、あるバージョンを使用してローカライズされた保存データを、別のバージョンで操作する場合に問題を引き起こす可能性があります。このような状況に対処する方法については、こちらを参照してください。

警告

pytz タイムゾーンの場合、タイムゾーンオブジェクトを datetime.datetime コンストラクターに直接渡すのは正しくありません(例:datetime.datetime(2011, 1, 1, tzinfo=pytz.timezone('US/Eastern')))。代わりに、datetime は pytz タイムゾーンオブジェクトの localize メソッドを使用してローカライズする必要があります。

警告

将来の時間については、タイムゾーンからの UTC オフセットがそれぞれの政府によって変更される可能性があるため、タイムゾーンライブラリでは、タイムゾーン(および UTC)間の正しい変換は保証できないことに注意してください。

警告

2038-01-18 以降の日付を使用している場合、2038年問題によって引き起こされた基盤となるライブラリの現在の欠陥により、タイムゾーン対応の日付に対する夏時間(DST)調整は適用されません。基盤となるライブラリが修正されれば、DST トランジションが適用されます。

たとえば、英国夏時間(通常は GMT+1 になる)にある2つの日付の場合、次のアサートはどちらも true と評価されます。

In [459]: d_2037 = "2037-03-31T010101"

In [460]: d_2038 = "2038-03-31T010101"

In [461]: DST = "Europe/London"

In [462]: assert pd.Timestamp(d_2037, tz=DST) != pd.Timestamp(d_2037, tz="GMT")

In [463]: assert pd.Timestamp(d_2038, tz=DST) == pd.Timestamp(d_2038, tz="GMT")

内部的には、すべてのタイムスタンプは UTC で保存されます。タイムゾーンを認識する DatetimeIndex または Timestamp の値は、そのフィールド(日、時、分など)がタイムゾーンにローカライズされます。ただし、UTC 値が同じタイムスタンプは、異なるタイムゾーンにある場合でも等しいと見なされます。

In [464]: rng_eastern = rng_utc.tz_convert("US/Eastern")

In [465]: rng_berlin = rng_utc.tz_convert("Europe/Berlin")

In [466]: rng_eastern[2]
Out[466]: Timestamp('2012-03-07 19:00:00-0500', tz='US/Eastern')

In [467]: rng_berlin[2]
Out[467]: Timestamp('2012-03-08 01:00:00+0100', tz='Europe/Berlin')

In [468]: rng_eastern[2] == rng_berlin[2]
Out[468]: True

異なるタイムゾーンの Series 間の操作では、UTC Series が生成され、UTC タイムスタンプでデータが整列されます。

In [469]: ts_utc = pd.Series(range(3), pd.date_range("20130101", periods=3, tz="UTC"))

In [470]: eastern = ts_utc.tz_convert("US/Eastern")

In [471]: berlin = ts_utc.tz_convert("Europe/Berlin")

In [472]: result = eastern + berlin

In [473]: result
Out[473]: 
2013-01-01 00:00:00+00:00    0
2013-01-02 00:00:00+00:00    2
2013-01-03 00:00:00+00:00    4
Freq: D, dtype: int64

In [474]: result.index
Out[474]: 
DatetimeIndex(['2013-01-01 00:00:00+00:00', '2013-01-02 00:00:00+00:00',
               '2013-01-03 00:00:00+00:00'],
              dtype='datetime64[ns, UTC]', freq='D')

タイムゾーン情報を削除するには、tz_localize(None) または tz_convert(None) を使用します。tz_localize(None) はタイムゾーンを削除し、現地時間表現を生成します。tz_convert(None) は、UTC 時間に変換した後、タイムゾーンを削除します。

In [475]: didx = pd.date_range(start="2014-08-01 09:00", freq="h", periods=3, tz="US/Eastern")

In [476]: didx
Out[476]: 
DatetimeIndex(['2014-08-01 09:00:00-04:00', '2014-08-01 10:00:00-04:00',
               '2014-08-01 11:00:00-04:00'],
              dtype='datetime64[ns, US/Eastern]', freq='h')

In [477]: didx.tz_localize(None)
Out[477]: 
DatetimeIndex(['2014-08-01 09:00:00', '2014-08-01 10:00:00',
               '2014-08-01 11:00:00'],
              dtype='datetime64[ns]', freq=None)

In [478]: didx.tz_convert(None)
Out[478]: 
DatetimeIndex(['2014-08-01 13:00:00', '2014-08-01 14:00:00',
               '2014-08-01 15:00:00'],
              dtype='datetime64[ns]', freq='h')

# tz_convert(None) is identical to tz_convert('UTC').tz_localize(None)
In [479]: didx.tz_convert("UTC").tz_localize(None)
Out[479]: 
DatetimeIndex(['2014-08-01 13:00:00', '2014-08-01 14:00:00',
               '2014-08-01 15:00:00'],
              dtype='datetime64[ns]', freq=None)

Fold#

曖昧な時間に対して、pandasはキーワード専用引数 `fold` を明示的に指定することをサポートしています。夏時間から冬時間への移行時に、壁時計の時間が2回発生する場合があります。これは、夏時間から冬時間への移行時に、ある壁時計の時間が2回発生する場合があるためです。`fold` は、datetime-likeが、その曖昧な時間において、最初に発生した時間(0)か、2回目に発生した時間(1)かを示すものです。`fold` は、naiveな datetime.datetime (詳細は datetimeドキュメントを参照)からの構築、または Timestamp からの構築、またはコンポーネントからの構築(下記参照)でのみサポートされています。`dateutil` タイムゾーン(曖昧な日時を扱う dateutil のメソッドについては、dateutilドキュメントを参照)のみがサポートされています。なぜなら、`pytz` タイムゾーンは fold をサポートしていないためです(`pytz` が曖昧な日時をどのように扱うかの詳細は pytzドキュメントを参照)。`pytz` を使用して曖昧な日時をローカライズするには、Timestamp.tz_localize() を使用してください。一般的に、曖昧な日時をどのように処理するかを直接制御する必要がある場合は、Timestamp.tz_localize() に依存することをお勧めします。

In [480]: pd.Timestamp(
   .....:     datetime.datetime(2019, 10, 27, 1, 30, 0, 0),
   .....:     tz="dateutil/Europe/London",
   .....:     fold=0,
   .....: )
   .....: 
Out[480]: Timestamp('2019-10-27 01:30:00+0100', tz='dateutil//usr/share/zoneinfo/Europe/London')

In [481]: pd.Timestamp(
   .....:     year=2019,
   .....:     month=10,
   .....:     day=27,
   .....:     hour=1,
   .....:     minute=30,
   .....:     tz="dateutil/Europe/London",
   .....:     fold=1,
   .....: )
   .....: 
Out[481]: Timestamp('2019-10-27 01:30:00+0000', tz='dateutil//usr/share/zoneinfo/Europe/London')

ローカライズ時の曖昧な時間#

tz_localize は、タイムスタンプの UTC オフセットを決定できない場合があります。これは、ローカルタイムゾーンの夏時間(DST)によって、1日の中で同じ時間が2回発生する(「時計が後ろにずれる」)ためです。以下のオプションが利用可能です。

  • 'raise': pytz.AmbiguousTimeError を発生させます(デフォルトの動作)。

  • 'infer': タイムスタンプの単調性に基づいて、正しいオフセットを判断しようとします。

  • 'NaT': 曖昧な時間を NaT で置き換えます。

  • bool: True は夏時間を表し、False は夏時間でない時間を表します。時間のシーケンスに対して、bool 値の配列のようなものがサポートされています。

In [482]: rng_hourly = pd.DatetimeIndex(
   .....:     ["11/06/2011 00:00", "11/06/2011 01:00", "11/06/2011 01:00", "11/06/2011 02:00"]
   .....: )
   .....: 

これは曖昧な時間('11/06/2011 01:00')があるため失敗します。

In [483]: rng_hourly.tz_localize('US/Eastern')
---------------------------------------------------------------------------
AmbiguousTimeError                        Traceback (most recent call last)
Cell In[483], line 1
----> 1 rng_hourly.tz_localize('US/Eastern')

File ~/work/pandas/pandas/pandas/core/indexes/datetimes.py:293, in DatetimeIndex.tz_localize(self, tz, ambiguous, nonexistent)
    286 @doc(DatetimeArray.tz_localize)
    287 def tz_localize(
    288     self,
   (...)
    291     nonexistent: TimeNonexistent = "raise",
    292 ) -> Self:
--> 293     arr = self._data.tz_localize(tz, ambiguous, nonexistent)
    294     return type(self)._simple_new(arr, name=self.name)

File ~/work/pandas/pandas/pandas/core/arrays/_mixins.py:81, in ravel_compat.<locals>.method(self, *args, **kwargs)
     78 @wraps(meth)
     79 def method(self, *args, **kwargs):
     80     if self.ndim == 1:
---> 81         return meth(self, *args, **kwargs)
     83     flags = self._ndarray.flags
     84     flat = self.ravel("K")

File ~/work/pandas/pandas/pandas/core/arrays/datetimes.py:1088, in DatetimeArray.tz_localize(self, tz, ambiguous, nonexistent)
   1085     tz = timezones.maybe_get_tz(tz)
   1086     # Convert to UTC
-> 1088     new_dates = tzconversion.tz_localize_to_utc(
   1089         self.asi8,
   1090         tz,
   1091         ambiguous=ambiguous,
   1092         nonexistent=nonexistent,
   1093         creso=self._creso,
   1094     )
   1095 new_dates_dt64 = new_dates.view(f"M8[{self.unit}]")
   1096 dtype = tz_to_dtype(tz, unit=self.unit)

File tzconversion.pyx:371, in pandas._libs.tslibs.tzconversion.tz_localize_to_utc()

AmbiguousTimeError: Cannot infer dst time from 2011-11-06 01:00:00, try using the 'ambiguous' argument

これらの曖昧な時間を、以下を指定することで処理します。

In [484]: rng_hourly.tz_localize("US/Eastern", ambiguous="infer")
Out[484]: 
DatetimeIndex(['2011-11-06 00:00:00-04:00', '2011-11-06 01:00:00-04:00',
               '2011-11-06 01:00:00-05:00', '2011-11-06 02:00:00-05:00'],
              dtype='datetime64[ns, US/Eastern]', freq=None)

In [485]: rng_hourly.tz_localize("US/Eastern", ambiguous="NaT")
Out[485]: 
DatetimeIndex(['2011-11-06 00:00:00-04:00', 'NaT', 'NaT',
               '2011-11-06 02:00:00-05:00'],
              dtype='datetime64[ns, US/Eastern]', freq=None)

In [486]: rng_hourly.tz_localize("US/Eastern", ambiguous=[True, True, False, False])
Out[486]: 
DatetimeIndex(['2011-11-06 00:00:00-04:00', '2011-11-06 01:00:00-04:00',
               '2011-11-06 01:00:00-05:00', '2011-11-06 02:00:00-05:00'],
              dtype='datetime64[ns, US/Eastern]', freq=None)

ローカライズ時の存在しない時間#

DST の移行によって、ローカル時間が 1 時間進み、存在しないローカル時間が作成される(「時計が前に進む」)場合もあります。存在しない時間を持つ時系列のローカライズの動作は、nonexistent 引数で制御できます。以下のオプションが利用可能です。

  • 'raise': pytz.NonExistentTimeError を発生させます(デフォルトの動作)。

  • 'NaT': 存在しない時間を NaT で置き換えます。

  • 'shift_forward': 存在しない時間を最も近い実時間に繰り上げます。

  • 'shift_backward': 存在しない時間を最も近い実時間に繰り下げます。

  • timedelta オブジェクト: 存在しない時間を timedelta の期間だけシフトさせます。

In [487]: dti = pd.date_range(start="2015-03-29 02:30:00", periods=3, freq="h")

# 2:30 is a nonexistent time

存在しない時間のローカライズは、デフォルトではエラーが発生します。

In [488]: dti.tz_localize('Europe/Warsaw')
---------------------------------------------------------------------------
NonExistentTimeError                      Traceback (most recent call last)
Cell In[488], line 1
----> 1 dti.tz_localize('Europe/Warsaw')

File ~/work/pandas/pandas/pandas/core/indexes/datetimes.py:293, in DatetimeIndex.tz_localize(self, tz, ambiguous, nonexistent)
    286 @doc(DatetimeArray.tz_localize)
    287 def tz_localize(
    288     self,
   (...)
    291     nonexistent: TimeNonexistent = "raise",
    292 ) -> Self:
--> 293     arr = self._data.tz_localize(tz, ambiguous, nonexistent)
    294     return type(self)._simple_new(arr, name=self.name)

File ~/work/pandas/pandas/pandas/core/arrays/_mixins.py:81, in ravel_compat.<locals>.method(self, *args, **kwargs)
     78 @wraps(meth)
     79 def method(self, *args, **kwargs):
     80     if self.ndim == 1:
---> 81         return meth(self, *args, **kwargs)
     83     flags = self._ndarray.flags
     84     flat = self.ravel("K")

File ~/work/pandas/pandas/pandas/core/arrays/datetimes.py:1088, in DatetimeArray.tz_localize(self, tz, ambiguous, nonexistent)
   1085     tz = timezones.maybe_get_tz(tz)
   1086     # Convert to UTC
-> 1088     new_dates = tzconversion.tz_localize_to_utc(
   1089         self.asi8,
   1090         tz,
   1091         ambiguous=ambiguous,
   1092         nonexistent=nonexistent,
   1093         creso=self._creso,
   1094     )
   1095 new_dates_dt64 = new_dates.view(f"M8[{self.unit}]")
   1096 dtype = tz_to_dtype(tz, unit=self.unit)

File tzconversion.pyx:431, in pandas._libs.tslibs.tzconversion.tz_localize_to_utc()

NonExistentTimeError: 2015-03-29 02:30:00

存在しない時間を NaT に変換するか、時間をシフトさせます。

In [489]: dti
Out[489]: 
DatetimeIndex(['2015-03-29 02:30:00', '2015-03-29 03:30:00',
               '2015-03-29 04:30:00'],
              dtype='datetime64[ns]', freq='h')

In [490]: dti.tz_localize("Europe/Warsaw", nonexistent="shift_forward")
Out[490]: 
DatetimeIndex(['2015-03-29 03:00:00+02:00', '2015-03-29 03:30:00+02:00',
               '2015-03-29 04:30:00+02:00'],
              dtype='datetime64[ns, Europe/Warsaw]', freq=None)

In [491]: dti.tz_localize("Europe/Warsaw", nonexistent="shift_backward")
Out[491]: 
DatetimeIndex(['2015-03-29 01:59:59.999999999+01:00',
                         '2015-03-29 03:30:00+02:00',
                         '2015-03-29 04:30:00+02:00'],
              dtype='datetime64[ns, Europe/Warsaw]', freq=None)

In [492]: dti.tz_localize("Europe/Warsaw", nonexistent=pd.Timedelta(1, unit="h"))
Out[492]: 
DatetimeIndex(['2015-03-29 03:30:00+02:00', '2015-03-29 03:30:00+02:00',
               '2015-03-29 04:30:00+02:00'],
              dtype='datetime64[ns, Europe/Warsaw]', freq=None)

In [493]: dti.tz_localize("Europe/Warsaw", nonexistent="NaT")
Out[493]: 
DatetimeIndex(['NaT', '2015-03-29 03:30:00+02:00',
               '2015-03-29 04:30:00+02:00'],
              dtype='datetime64[ns, Europe/Warsaw]', freq=None)

タイムゾーンの Series 操作#

タイムゾーンがnaiveな値を持つ Series は、datetime64[ns] の dtype で表されます。

In [494]: s_naive = pd.Series(pd.date_range("20130101", periods=3))

In [495]: s_naive
Out[495]: 
0   2013-01-01
1   2013-01-02
2   2013-01-03
dtype: datetime64[ns]

タイムゾーンがawareな値を持つ Series は、datetime64[ns, tz] の dtype で表されます。ここで、tz はタイムゾーンです。

In [496]: s_aware = pd.Series(pd.date_range("20130101", periods=3, tz="US/Eastern"))

In [497]: s_aware
Out[497]: 
0   2013-01-01 00:00:00-05:00
1   2013-01-02 00:00:00-05:00
2   2013-01-03 00:00:00-05:00
dtype: datetime64[ns, US/Eastern]

これらの両方の Series のタイムゾーン情報は、.dt アクセサーを使用して操作できます。詳細は、dt アクセサーのセクション を参照してください。

たとえば、naive なタイムスタンプをローカライズして、タイムゾーン aware に変換するには次のようにします。

In [498]: s_naive.dt.tz_localize("UTC").dt.tz_convert("US/Eastern")
Out[498]: 
0   2012-12-31 19:00:00-05:00
1   2013-01-01 19:00:00-05:00
2   2013-01-02 19:00:00-05:00
dtype: datetime64[ns, US/Eastern]

タイムゾーンの情報は、astype メソッドを使用して操作することもできます。このメソッドは、異なるタイムゾーン aware の dtype 間で変換できます。

# convert to a new time zone
In [499]: s_aware.astype("datetime64[ns, CET]")
Out[499]: 
0   2013-01-01 06:00:00+01:00
1   2013-01-02 06:00:00+01:00
2   2013-01-03 06:00:00+01:00
dtype: datetime64[ns, CET]

注意

SeriesSeries.to_numpy() を使用すると、データの NumPy 配列が返されます。NumPy は現在、タイムゾーンをサポートしていないため(ローカルタイムゾーンで *表示* されていても!)、タイムゾーン aware なデータに対しては、タイムスタンプのオブジェクト配列が返されます。

In [500]: s_naive.to_numpy()
Out[500]: 
array(['2013-01-01T00:00:00.000000000', '2013-01-02T00:00:00.000000000',
       '2013-01-03T00:00:00.000000000'], dtype='datetime64[ns]')

In [501]: s_aware.to_numpy()
Out[501]: 
array([Timestamp('2013-01-01 00:00:00-0500', tz='US/Eastern'),
       Timestamp('2013-01-02 00:00:00-0500', tz='US/Eastern'),
       Timestamp('2013-01-03 00:00:00-0500', tz='US/Eastern')],
      dtype=object)

タイムスタンプのオブジェクト配列に変換することで、タイムゾーンの情報が保持されます。たとえば、Series に戻す場合は次のようになります。

In [502]: pd.Series(s_aware.to_numpy())
Out[502]: 
0   2013-01-01 00:00:00-05:00
1   2013-01-02 00:00:00-05:00
2   2013-01-03 00:00:00-05:00
dtype: datetime64[ns, US/Eastern]

ただし、オブジェクトの配列ではなく、実際の NumPy datetime64[ns] 配列(UTC に変換された値を持つ)が必要な場合は、dtype 引数を指定できます。

In [503]: s_aware.to_numpy(dtype="datetime64[ns]")
Out[503]: 
array(['2013-01-01T05:00:00.000000000', '2013-01-02T05:00:00.000000000',
       '2013-01-03T05:00:00.000000000'], dtype='datetime64[ns]')