「機械学習モデルにおける気象データの利用」

Using weather data in machine learning models

はじめに

天気は現実世界で起こる多くのことに影響を与える主要な要素です。実際、それは非常に重要なので、機械学習モデルを組み込むことでそれを取り込む予測モデルには通常恩恵をもたらします。

次のシナリオを考えてみてください:

  • 公共交通機関がシステム内の遅延や渋滞を予測しようとする
  • エネルギー供給業者が明日の太陽光発電量を見積もり、エネルギー取引のために使用したい
  • イベント主催者が参加者数を予測し、安全基準を満たすために確保する必要がある
  • 農場が来週の収穫作業をスケジュールする必要がある

上記のシナリオのどれにも天気を含めないモデルは、無意味であるか、あるいはできるだけ良くないと言えるでしょう。

驚くことに、天気予測自体に焦点を当てたオンラインリソースは多くありますが、天気データを効果的に特徴量として取得・使用する方法についてはほとんどありません。この記事はそれについて説明します。

概要

まず、モデリングに天気データを使用する際の課題、一般的に使用されるモデル、および提供者について紹介します。そして、ケーススタディを実行し、ニューヨークのタクシー乗車を予測するために提供者のデータを使用して機械学習モデルを構築します。

この記事の最後には、以下のことを学びます:

  • モデリングにおける天気データの課題
  • どのような天気モデルと提供者が存在するか
  • 時系列データのETLと特徴量構築の典型的な手順
  • SHAP値を使用した特徴量の重要度評価

この記事はデータサイエンスブログマラソンの一環として公開されました。

課題

測定と予測された天気

本番のMLモデルでは、(1)リアルタイムで予測を行うためのライブデータと(2)モデルをトレーニングするための大量の過去のデータの両方が必要です。

by Hadija on Unsplash

明らかに、ライブ予測を行う際には、将来起こることについての最新の見積もりである現在の天気予報を入力として使用します。例えば、明日の太陽光発電量を予測する際には、モデルに必要なのは予報が明日の天気についてどのように述べているかです。

モデルのトレーニングはどうなりますか?

モデルが現実世界でうまく機能するためには、トレーニングデータがライブデータを反映する必要があります。モデルのトレーニングには、過去の測定値または過去の予測値のいずれを使用するかという選択肢があります。過去の測定値は結果のみを反映し、つまり天気観測所が記録したものです。ただし、ライブモデルは測定値ではなく予測値を使用します。なぜなら、モデルが予測を行う時点ではまだ測定値が利用できないからです。

過去の予測値を入手できる可能性がある場合、ライブ予測時と同じ条件でモデルをトレーニングするため、常にそれを選択するべきです。

by American Public Power Association on Unsplash

次の例を考えてみてください:雲が多い場合、太陽光発電所はほとんど電力を生成しません。過去の測定値に基づいてトレーニングされたモデルは、雲のカバレッジが高いとほとんど電力が生成されないということを学びます。一方、過去の予測値に基づいてトレーニングされたモデルは、別の次元が存在することを学びます。数日先を予測する際、雲のカバレッジが高い場合でも、それが確実に曇っていることを意味するわけではありません。そのような場合、モデルはこの特徴量にある程度依存し、太陽光発電を予測する際に他の特徴量も考慮することができます。

フォーマット

天気データ =/= 天気データ。特定の天気データが少しでも有用であると判断されるには、多くの要素が関与します。主な要素には以下があります:

  • 粒度:毎時、3時間ごと、毎日の記録があるか?
  • 変数:必要な特徴が含まれているか?
  • 空間解像度:1つの記録が何平方キロメートルを指すか?
  • 予測期間:予測がどれくらい先まで行われるか?
  • 予測の更新:新しい予測がどのくらいの頻度で作成されるか?

さらに、データの形状やフォーマットは作業の手間を増やすことがあります。作成する必要のある追加のETL手順にはバグが導入される可能性があり、データの時間依存性はこの作業を非常に厄介なものにすることがあります。

ライブ vs. 古いデータ

1日以上、1週間以上前のデータは、CSVダンプ、FTPサーバー、または最良の場合は別のAPIエンドポイントで提供されることがありますが、ライブ予測エンドポイントとは異なるフィールドを持つことがよくあります。これにより、データの不一致が生じるリスクがあり、ETLの複雑さが増す可能性があります。

コスト

コストは、提供業者と必要な天気データの種類によって非常に異なる場合があります。たとえば、提供業者は各個別座標に対して料金を請求する場合があり、多くの場所が必要な場合に問題となる可能性があります。過去の天気予報を取得することは一般的に非常に困難で高額です。

天気モデル

数値天気予測モデルは、天気のさまざまな要素の物理的な振る舞いをシミュレートします。さまざまな形式(上記を参照)、対象とする地球の部分、および精度が異なります。

以下は最も広く使用されている天気モデルのクイックリストです:

  • GFS:最もよく知られた標準モデル、広く使用されており、グローバル
  • CFS:GFSよりも正確性が低く、長期の気候予測に使用され、グローバル
  • ECMWF:最も正確なが高価なモデル、グローバル
  • UM:英国向けの最も正確なモデルで、グローバルも利用可能
  • WRF:DIY地域の天気予報を生成するためのオープンソースコード
by Brian McGowan on Unsplash

プロバイダー

プロバイダーは、天気モデルからエンドユーザーにデータを提供するための存在です。しばしば標準天気モデルに加えて独自の予測モデルを持っています。以下はいくつかの有名なプロバイダーの一部です:

  • AccuWeather
  • MetOffice
  • OpenWeatherMap
  • AerisWeather
  • DWD(ドイツ)
  • Meteogroup(イギリス)

BlueSky API

機械学習のユースケースでは、上記のプロバイダーは歴史的な予測を提供していないか、データを取得して組み合わせるプロセスが手間や費用がかかることがあります。それに対して、blueskyapi.ioは、データのパイプライン作成を非常に簡単にするために、ライブデータと過去の予測の両方を同じ形式で取得するためのシンプルなAPIを提供しています。元のデータは、最も広く使用されている天気モデルであるGFSから取得されます。

事例:ニューヨークのタクシーライド

ニューヨークでタクシービジネスを経営しており、スタッフやフリート計画を最適化するためにタクシーライドの量を予測したいとします。ニューヨークの過去のタクシーデータにアクセスできるため、それを活用して機械学習モデルを作成することにします。

by Heather Shevlin on Unsplash

ここからダウンロードできるNYCのデータを使用します。

まずはいくつかのインポート:

import pandas as pd
import numpy as np
import holidays
import datetime
import pytz
from dateutil.relativedelta import relativedelta
from matplotlib import pyplot as plt
from statsmodels.tsa.seasonal import seasonal_decompose
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
import shap
import pyarrow

タクシーデータの前処理

timezone = pytz.timezone("US/Eastern")
dates = pd.date_range("2022-04", "2023-03", freq="MS", tz=timezone)

タクシーデータを取得するために、ファイルをループして、時間ごとのカウントを持つ集計データフレームを作成する必要があります。これには約20秒かかります。

aggregated_dfs = []
for date in dates:
    print(date)
    df = pd.read_parquet(
      f"./data/yellow_tripdata_{date.strftime('%Y-%m')}.parquet", 
      engine='pyarrow'
    )
    df["timestamp"] = pd.DatetimeIndex(
      df["tpep_pickup_datetime"], tz=timezone, ambiguous='NaT'
    ).floor("H")
    
    # データクリーニング、時々間違ったタイムスタンプが含まれています
    df = df[
        (df.timestamp >= date) & 
        (df.timestamp < date + relativedelta(months=1))
    ]
    aggregated_dfs.append(
      df.groupby(["timestamp"]).agg({"trip_distance": "count"}
    ).reset_index())
df = pd.concat(aggregated_dfs).reset_index(drop=True)
df.columns = ["timestamp", "count"]

データを見てみましょう。最初の2日間:

df.head(48).plot("timestamp", "count")

すべてのデータ:

fig, ax = plt.subplots()
fig.set_size_inches(20, 8)
ax.plot(df.timestamp, df["count"])
ax.xaxis.set_major_locator(plt.MaxNLocator(10))

興味深いことに、一部の休日の間にタクシーの乗車回数がかなり減少していることがわかります。時系列の観点からは、データに明確な傾向や異方性はありません。

タクシーデータの特徴エンジニアリング

次に、時系列予測で使用されるいくつかの典型的な特徴を追加します。

タイムスタンプの要素をエンコードする

df["hour"] = df["timestamp"].dt.hour
df["day_of_week"] = df["timestamp"].dt.day_of_week

休日をエンコードする

us_holidays = holidays.UnitedStates()
df["date"] = df["timestamp"].dt.date
df["holiday_today"] = [ind in us_holidays for ind in df.date]
df["holiday_tomorrow"] = [ind + datetime.timedelta(days=1) in us_holidays for ind in df.date]
df["holiday_yesterday"] = [ind - datetime.timedelta(days=1) in us_holidays for ind in df.date]

BlueSkyの天気データ

ここで興味深い部分にやってきました: 天気データです。以下に、BlueSkyの天気APIを使用する方法について解説します。Pythonユーザーの場合、pipを使用してインストールできます:

pip install blueskyapi

ただし、cURLを使用することも可能です。

BlueSkyの基本的なAPIは無料です。APIキーをウェブサイトから取得することをお勧めします。これにより、APIから取得できるデータ量が増えます。

有料のサブスクリプションを使用すると、追加の天候変数、より頻繁な予測の更新、より細かい粒度などを取得できますが、このケーススタディでは必要ありません。

import blueskyapi
client = blueskyapi.Client()  # ここにAPIキーを使用してデータ制限を増やす

位置、予測距離、および興味のある天候変数を選択する必要があります。タクシーデータと一致するように、1年分の天気予報を取得しましょう。

# ニューヨーク
lat = 40.5
lon = 106.0

weather = client.forecast_history(
    lat=lat,
    lon=lon,
    min_forecast_moment="2022-04-01T00:00:00+00:00",
    max_forecast_moment="2023-04-01T00:00:00+00:00",
    forecast_distances=[3,6],  # 将来の時間
    columns=[
        'precipitation_rate_at_surface',
        'apparent_temperature_at_2m',
        'temperature_at_2m',
        'total_cloud_cover_at_convective_cloud_layer',
        'wind_speed_gust_at_surface',
        'categorical_rain_at_surface',
        'categorical_snow_at_surface'
    ],
)
weather.iloc[0]

天気データを取得するために必要なすべての手順はこれで終了です!

データの結合

天気データがタクシーデータに正しくマッピングされるようにする必要があります。そのためには、予測時点と予測距離を追加する必要があります:

weather["target_moment"] = weather.forecast_moment + pd.to_timedelta(
    weather.forecast_distance, unit="h"
)

データを結合する際の典型的な問題は、タイムスタンプのデータ型とタイムゾーンの認識です。正しく結合するためにタイムゾーンを一致させましょう。

df["timestamp"] = [timezone.normalize(ts).astimezone(pytz.utc) for ts in df["timestamp"]]
weather["target_moment"] = weather["target_moment"].dt.tz_localize('UTC')

最後のステップとして、タクシーデータのすべてのタイムスタンプに対して、最新の利用可能な天気予報を結合します。

d = pd.merge_asof(df, weather, left_on="timestamp", right_on="target_moment", direction="nearest")
d.iloc[0]

データセットは完了です!

モデル

モデリングする前に、ターゲット変数が定常であるか、データに欠損値や異常値があるかなど、さらにいくつかのチェックを行うことが通常は意味があります。しかし、このブログ投稿のために、抽出および作成した特徴量で、そのままの状態でランダムフォレストモデルに適合させるだけにします:

d = d[~d.isnull().any(axis=1)].reset_index(drop=True)
X = d[
    [
        "day_of_week", 
        "hour", 
        "holiday_today", 
        "holiday_tomorrow", 
        "holiday_yesterday", 
        "precipitation_rate_at_surface",
        "apparent_temperature_at_2m",
        "temperature_at_2m",
        "total_cloud_cover_at_convective_cloud_layer",
        "wind_speed_gust_at_surface",
        "categorical_rain_at_surface",
        "categorical_snow_at_surface"
    ]
]
y = d["count"]
X_train, X_test, y_train, y_test = train_test_split(
  X, y, test_size=0.33, random_state=42, shuffle=False
)
rf = RandomForestRegressor()
rf.fit(X_train, y_train)
pred_train = rf.predict(X_train)
plt.figure(figsize=(50,8))
plt.plot(y_train)
plt.plot(pred_train)
plt.show()

pred_test = rf.predict(X_test)
plt.figure(figsize=(50,8))
plt.plot(y_test.reset_index(drop=True))
plt.plot(pred_test)
plt.show()

予想通り、テストセットでは訓練セットに比べてかなりの精度が失われます。これは改善できる可能性がありますが、全体的に予測は合理的であり、非常に高い値になる場合には保守的な傾向があります。

print("MAPE is", round(mean_absolute_percentage_error(y_test,pred_test) * 100, 2), "%")

MAPEは17.16%です

天気なしのモデル

天気データを追加したことでモデルが改善されたかどうかを確認するために、天気データを除いたベンチマークモデルと比較してみましょう:

X = d[
    [
        "day_of_week", 
        "hour", 
        "holiday_today", 
        "holiday_tomorrow", 
        "holiday_yesterday"
    ]
]
y = d["count"] 
X_train, X_test, y_train, y_test = train_test_split(
  X, y, test_size=0.33, random_state=42, shuffle=False
)
rf0 = RandomForestRegressor(random_state=42)
rf0.fit(X_train, y_train)
pred_train = rf0.predict(X_train)
pred_test = rf0.predict(X_test)
print("MAPE is", round(mean_absolute_percentage_error(y_test,pred_test) * 100, 2), "%")

MAPEは17.76%です

天候データを追加することで、タクシーの乗車予測のMAPEが0.6%改善しました。このパーセンテージは多くはないかもしれませんが、ビジネスの運営によってはこの改善が重要な影響を与える可能性があります。

特徴の重要度

メトリックの次に、特徴の重要度を見てみましょう。私たちはSHAPパッケージを使用します。このパッケージは、各特徴の個別のマージナルな寄与をモデルに説明するためにshap値を使用しており、つまり、他の特徴に比べて個別の特徴がどれだけ寄与するかを確認します。

explainer = shap.Explainer(rf)
shap_values = explainer(X_test)

これには数分かかります。なぜなら、すべての特徴に対して「もし特徴が欠けていたら、それが全体の予測精度にどのように影響するか」という「もしも」のシナリオを実行しているからです。

shap.plots.beeswarm(shap_values)

最も重要な説明変数は、一日の時間と週の日でした。これは完全に理にかなっています。タクシーの乗車数は一日や週によって非常に周期的に変動し、需要も大きく異なります。一部の天候データも有用でした。寒い時にはタクシーの利用が増えます。ただし、温度はタクシーの需要の一般的な年間季節効果の代理変数となる可能性もあります。他の重要な特徴は風の突風で、突風が多いとタクシーの利用が少なくなります。ここでの仮説は、嵐の天候では交通量が少ないため、タクシーの利用が少ないというものです。

さらなるモデルの改善

  • 既存のデータからさらに多くの特徴を作成することを検討してください。たとえば、前日や前週のターゲット変数の遅延。
  • モデルの頻繁な再学習により、常にトレンドを捉えることができます。これは実際の世界でモデルを使用する際に大きな影響を与えます。
  • NYの交通渋滞データなど、より多くの外部データの追加を検討してください。
  • Facebook Prophetなどの他の時系列モデルやツールも検討してください。
by Clint Patterson on Unsplash

結論

以上です!天候を使用した実用的なモデルを作成しました。

この記事では、さまざまなセクターにおける予測モデルでの天候データの重要性、それを効果的に使用するための課題、利用可能な数値天気予報モデルとプロバイダーについて議論し、BlueSky APIを費用対効果の高い効率的な方法として強調しました。ニューヨークのタクシー乗車予測のケーススタディを通じて、この記事では天候データを機械学習に使用する実践的なデモンストレーションを提供し、次の基本的なスキルを習得するための手順を学びました:

  • 時系列データの典型的なETLおよび特徴構築のステップ
  • BlueSky APIを介した天候データのETLおよび特徴構築
  • 時系列モデル用の単純なランダムフォレストモデルの適合と評価
  • shap値を使用した特徴の重要度の評価

キーポイント

  1. 天候データを既存の機械学習モデルに統合することは非常に複雑な場合がありますが、BlueSky APIなどの近代的な天候データサービスは、作業量を大幅に削減します。
  2. BlueSkyの天候データのモデルへの統合は、ニューヨークのタクシーケーススタディで予測精度を向上させ、天候が日々の業務に実用的な役割を果たしていることを示しています。
  3. 小売業、農業、エネルギー、交通など、多くのセクターが同様またはそれ以上の利益を得ているため、予測精度を向上させ、運用効率とリソースの割り当てを向上させるために、良好な天気予測統合が必要です。

よくある質問

この記事に表示されるメディアはAnalytics Vidhyaの所有ではなく、著者の裁量で使用されています。

We will continue to update VoAGI; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more