In [1]: import pandas as pd

In [2]: import matplotlib.pyplot as plt
このチュートリアルで使用するデータ
  • このチュートリアルでは、OpenAQ が提供し、py-openaq パッケージを使ってダウンロードされた、\(NO_2\) と 2.5マイクロメートル未満の粒子状物質に関する大気質データを使用します。air_quality_no2_long.csv" データセットは、パリの FR04014、アントワープの BETR801、ロンドンの London Westminster の測定ステーションにおける \(NO_2\) 値を提供します。

    生データへ
    In [3]: air_quality = pd.read_csv("data/air_quality_no2_long.csv")
    
    In [4]: air_quality = air_quality.rename(columns={"date.utc": "datetime"})
    
    In [5]: air_quality.head()
    Out[5]: 
        city country                   datetime location parameter  value   unit
    0  Paris      FR  2019-06-21 00:00:00+00:00  FR04014       no2   20.0  µg/m³
    1  Paris      FR  2019-06-20 23:00:00+00:00  FR04014       no2   21.8  µg/m³
    2  Paris      FR  2019-06-20 22:00:00+00:00  FR04014       no2   26.5  µg/m³
    3  Paris      FR  2019-06-20 21:00:00+00:00  FR04014       no2   24.9  µg/m³
    4  Paris      FR  2019-06-20 20:00:00+00:00  FR04014       no2   21.4  µg/m³
    
    In [6]: air_quality.city.unique()
    Out[6]: array(['Paris', 'Antwerpen', 'London'], dtype=object)
    

時系列データを簡単に扱う方法#

pandas の datetime プロパティの使用#

  • datetime 列の日付を、プレーンテキストではなく datetime オブジェクトとして扱いたい

    In [7]: air_quality["datetime"] = pd.to_datetime(air_quality["datetime"])
    
    In [8]: air_quality["datetime"]
    Out[8]: 
    0      2019-06-21 00:00:00+00:00
    1      2019-06-20 23:00:00+00:00
    2      2019-06-20 22:00:00+00:00
    3      2019-06-20 21:00:00+00:00
    4      2019-06-20 20:00:00+00:00
                      ...           
    2063   2019-05-07 06:00:00+00:00
    2064   2019-05-07 04:00:00+00:00
    2065   2019-05-07 03:00:00+00:00
    2066   2019-05-07 02:00:00+00:00
    2067   2019-05-07 01:00:00+00:00
    Name: datetime, Length: 2068, dtype: datetime64[ns, UTC]
    

    当初、datetime の値は文字列であり、いかなる datetime 操作 (例: 年、曜日などを抽出する) も提供しません。to_datetime 関数を適用することで、pandas は文字列を解釈し、これらを datetime (つまり datetime64[ns, UTC]) オブジェクトに変換します。pandas では、これらの datetime オブジェクトを標準ライブラリの datetime.datetime と同様に pandas.Timestamp と呼びます。

多くのデータセットは列の1つに datetime 情報を含んでいるため、pandas.read_csv()pandas.read_json() のような pandas の入力関数は、parse_dates パラメータに Timestamp として読み込む列のリストを指定することで、データを読み込む際に日付への変換を行うことができます。

pd.read_csv("../data/air_quality_no2_long.csv", parse_dates=["datetime"])

これらの pandas.Timestamp オブジェクトが役立つのはなぜでしょうか?いくつかの例でその付加価値を説明しましょう。

作業している時系列データセットの開始日と終了日はいつですか?

In [9]: air_quality["datetime"].min(), air_quality["datetime"].max()
Out[9]: 
(Timestamp('2019-05-07 01:00:00+0000', tz='UTC'),
 Timestamp('2019-06-21 00:00:00+0000', tz='UTC'))

日付に pandas.Timestamp を使用することで、日付情報を計算したり比較したりすることができます。したがって、これを使用して時系列の長さを取得できます。

In [10]: air_quality["datetime"].max() - air_quality["datetime"].min()
Out[10]: Timedelta('44 days 23:00:00')

結果は、標準 Python ライブラリの datetime.timedelta と同様の pandas.Timedelta オブジェクトであり、時間間隔を定義します。

ユーザーガイドへ

pandas がサポートする様々な時間概念は、時間関連の概念 に関するユーザーガイドのセクションで説明されています。

  • 測定月のデータのみを含む新しい列を DataFrame に追加したい

    In [11]: air_quality["month"] = air_quality["datetime"].dt.month
    
    In [12]: air_quality.head()
    Out[12]: 
        city country                  datetime  ... value   unit  month
    0  Paris      FR 2019-06-21 00:00:00+00:00  ...  20.0  µg/m³      6
    1  Paris      FR 2019-06-20 23:00:00+00:00  ...  21.8  µg/m³      6
    2  Paris      FR 2019-06-20 22:00:00+00:00  ...  26.5  µg/m³      6
    3  Paris      FR 2019-06-20 21:00:00+00:00  ...  24.9  µg/m³      6
    4  Paris      FR 2019-06-20 20:00:00+00:00  ...  21.4  µg/m³      6
    
    [5 rows x 8 columns]
    

    日付に Timestamp オブジェクトを使用することで、多くの時間関連プロパティが pandas によって提供されます。例えば month の他に、yearquarter などがあります。これらのすべてのプロパティは dt アクセサを通じてアクセス可能です。

ユーザーガイドへ

既存の日付プロパティの概要は、時刻と日付のコンポーネント概要表 に示されています。datetime のようなプロパティを返す dt アクセサに関する詳細については、dt アクセサ の専用セクションで説明されています。

  • 各測定場所における曜日ごとの平均 \(NO_2\) 濃度はどのくらいですか?

    In [13]: air_quality.groupby(
       ....:     [air_quality["datetime"].dt.weekday, "location"])["value"].mean()
       ....: 
    Out[13]: 
    datetime  location          
    0         BETR801               27.875000
              FR04014               24.856250
              London Westminster    23.969697
    1         BETR801               22.214286
              FR04014               30.999359
                                      ...    
    5         FR04014               25.266154
              London Westminster    24.977612
    6         BETR801               21.896552
              FR04014               23.274306
              London Westminster    24.859155
    Name: value, Length: 21, dtype: float64
    

    統計計算に関するチュートリアル で提供された groupby による分割-適用-結合パターンを覚えていますか?ここでは、各曜日ごと、そして各測定場所ごとに、指定された統計量 (例: \(NO_2\) の平均) を計算したいと考えています。曜日でグループ化するには、pandas の Timestamp の datetime プロパティである weekday (月曜日=0、日曜日=6) を使用します。これも dt アクセサでアクセスできます。場所と曜日の両方でグループ化することで、これらの各組み合わせで平均の計算を分割することができます。

    注意

    これらの例では非常に短い時系列データを使用しているため、分析結果は長期的な代表性のある結果を提供するものではありません!

  • すべてのステーションを合わせた時系列データの日中の典型的な \(NO_2\) パターンをプロットします。言い換えれば、各時間帯の平均値はどのくらいですか?

    In [14]: fig, axs = plt.subplots(figsize=(12, 4))
    
    In [15]: air_quality.groupby(air_quality["datetime"].dt.hour)["value"].mean().plot(
       ....:     kind='bar', rot=0, ax=axs
       ....: )
       ....: 
    Out[15]: <Axes: xlabel='datetime'>
    
    In [16]: plt.xlabel("Hour of the day");  # custom x label using Matplotlib
    
    In [17]: plt.ylabel("$NO_2 (µg/m^3)$");
    
    ../../_images/09_bar_chart.png

    前のケースと同様に、**1日の各時間ごと**に所定の統計量(例:平均\(NO_2\))を計算したいので、再び分割・適用・結合のアプローチを使用できます。この場合、pandasのTimestampのdatetimeプロパティhourを使用します。これはdtアクセサでもアクセス可能です。

インデックスとしての datetime#

再形成に関するチュートリアル で、各測定場所を別々の列としてデータテーブルを再形成するために pivot() が紹介されました。

In [18]: no_2 = air_quality.pivot(index="datetime", columns="location", values="value")

In [19]: no_2.head()
Out[19]: 
location                   BETR801  FR04014  London Westminster
datetime                                                       
2019-05-07 01:00:00+00:00     50.5     25.0                23.0
2019-05-07 02:00:00+00:00     45.0     27.7                19.0
2019-05-07 03:00:00+00:00      NaN     50.4                19.0
2019-05-07 04:00:00+00:00      NaN     61.9                16.0
2019-05-07 05:00:00+00:00      NaN     72.4                 NaN

データをピボットすることで、datetime 情報がテーブルのインデックスになりました。一般的に、列をインデックスに設定するには set_index 関数を使用できます。

datetime インデックス (つまり DatetimeIndex) を使用すると、強力な機能が提供されます。例えば、時系列プロパティを取得するために dt アクセサは必要なく、これらのプロパティはインデックスで直接利用できます。

In [20]: no_2.index.year, no_2.index.weekday
Out[20]: 
(Index([2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019,
        ...
        2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019],
       dtype='int32', name='datetime', length=1033),
 Index([1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        ...
        3, 3, 3, 3, 3, 3, 3, 3, 3, 4],
       dtype='int32', name='datetime', length=1033))

その他の利点としては、特定の期間のデータ抽出が便利になったり、プロット上の時間軸が調整されたりすることです。これをデータに適用してみましょう。

  • 5月20日から5月21日の終わりまでの各ステーションにおける \(NO_2\) 値のプロットを作成します。

    In [21]: no_2["2019-05-20":"2019-05-21"].plot();
    
    ../../_images/09_time_section.png

    datetime にパースできる文字列を提供することで、DatetimeIndex 上でデータの特定の部分を選択できます。

ユーザーガイドへ

DatetimeIndex と文字列を使用したスライスに関する詳細情報は、時系列インデックス付け のセクションで提供されています。

時系列データを別の頻度にリサンプリングする#

  • 現在の時間単位の時系列値を、各ステーションにおける月ごとの最大値に集計します。

    In [22]: monthly_max = no_2.resample("ME").max()
    
    In [23]: monthly_max
    Out[23]: 
    location                   BETR801  FR04014  London Westminster
    datetime                                                       
    2019-05-31 00:00:00+00:00     74.5     97.0                97.0
    2019-06-30 00:00:00+00:00     52.5     84.7                52.0
    

    datetime インデックスを持つ時系列データにおける非常に強力なメソッドは、時系列を別の頻度(例:秒単位のデータを5分単位のデータに変換する)に resample() する機能です。

resample() メソッドは groupby 操作に似ています

  • これは、目標の頻度を定義する文字列 (例: M, 5H など) を使用して、時間ベースのグループ化を提供します。

  • これは、meanmax などの集約関数を必要とします。

ユーザーガイドへ

時系列の頻度を定義するために使用されるエイリアスの概要は、オフセットエイリアス概要表 に示されています。

定義されると、時系列の頻度は freq 属性によって提供されます。

In [24]: monthly_max.index.freq
Out[24]: <MonthEnd>
  • 各観測所の日平均 \(NO_2\) 値のプロットを作成します。

    In [25]: no_2.resample("D").mean().plot(style="-o", figsize=(10, 5));
    
    ../../_images/09_resample_mean.png
ユーザーガイドへ

時系列 リサンプリング の強力さに関する詳細は、リサンプリング に関するユーザーガイドのセクションで提供されています。

覚えておいてください

  • 有効な日付文字列は、to_datetime 関数を使用するか、読み取り関数の一部として datetime オブジェクトに変換できます。

  • pandas の datetime オブジェクトは、dt アクセサを使用して、計算、論理演算、および便利な日付関連プロパティをサポートします。

  • DatetimeIndex はこれらの日付関連プロパティを含み、便利なスライスをサポートします。

  • Resample は、時系列の頻度を変更するための強力なメソッドです。

ユーザーガイドへ

時系列に関する完全な概要は、時系列と日付機能 のページに記載されています。