0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ARIMAモデルで簡単予測!カテエネの過去データから売電料金の未来を予測

Posted at

売電料金減ってる・・・?

ソーラーパネルを積んで数年経ちますが、昔に比べて売電料金が減っている気がする。
とはいえ、過去のデータを取っていないので、具体的にどうなっているのか・・・と考えた時に、カテエネのサイトから見れるのではと思いました。
カテエネを見ると、過去3年分くらいまではCSVで取得できるようでした。
これを使って、過去のデータを解析するとともに、将来の売電料金を予想させてみました。

カテエネからのCSVダウンロード方法

ログインして、 使用量・料金実績 をクリック
スクリーンショット 2024-07-02 15.13.57.png

料金と使用量 をクリック
スクリーンショット 2024-07-02 15.14.03.png

データダウンロード をクリック
スクリーンショット 2024-07-02 15.14.41.png

売電契約を選択し、全ての期間 にチェックしてダウンロードをクリック
image.png

カテエネから取得できるCSVのデータ

  • 過去3年分がまとまったCSVがダウンロードできる
  • Shift_JISエンコード
  • 1行目には不要な説明があるので読み飛ばした方が良い

将来を予測させるためのモデル

時系列データの解析に適したモデルとしてARIMAモデルを使用しました。ARIMAは過去のデータに基づいて将来を予測する統計モデルで、特にトレンドや季節性を持つデータに対して有効です。
SARIMAモデル(季節性ARIMA)は、季節性のパターンを考慮する点でARIMAよりも適していますが、今回は単純なARIMAモデルを試しました。

コード

pandas matplotlib statsmodels をインストールし、以下のようなコードを書いて実行します

import os

import matplotlib.font_manager as fm
import matplotlib.pyplot as plt
import pandas as pd
from statsmodels.tsa.arima.model import ARIMA

DATA_DIR = 'data'  # CSVファイルが保存されているディレクトリ
DIST_DIR = 'dist'  # 出力ディレクトリ
TARGET_COLUMN = '再生可能エネルギーからの電力受給契約'
DATE_COLUMN = 0
PRICE_COLUMN = 12

def load_and_filter_csv_files(directory):
    """
    ディレクトリ内のすべてのCSVファイルを読み込み、
    特定の条件に一致するデータをフィルタリングして結合します。

    Parameters:
    directory (str): CSVファイルが保存されているディレクトリのパス。

    Returns:
    DataFrame: フィルタリングされたデータを含むデータフレーム。
    """
    all_data = pd.DataFrame()
    for filename in os.listdir(directory):
        if filename.endswith('.csv'):
            filepath = os.path.join(directory, filename)
            try:
                df = pd.read_csv(filepath, encoding='shift_jis', skiprows=1, header=0)
                df = df.dropna(subset=[df.columns[DATE_COLUMN], df.columns[PRICE_COLUMN], df.columns[5]])
                df = df[df[df.columns[5]] == TARGET_COLUMN]
                filtered_df = df.iloc[:, [DATE_COLUMN, PRICE_COLUMN]]
                all_data = pd.concat([all_data, filtered_df])
            except Exception as e:
                print(f"Error reading {filename}: {e}")
    return all_data

def preprocess_data(df):
    """
    データフレームを前処理し、日付をインデックスに設定し、頻度情報を追加します。

    Parameters:
    df (DataFrame): 前処理するデータフレーム。

    Returns:
    DataFrame: 前処理されたデータフレーム。
    """
    df.columns = ['date', 'price']
    df['date'] = pd.to_datetime(df['date'], format='%Y%m')
    df['price'] = df['price'].astype(str).str.replace(',', '').astype(float)
    df.sort_values('date', inplace=True)
    df.set_index('date', inplace=True)
    df.index.freq = 'MS'
    return df

def train_arima_model(df):
    """
    ARIMAモデルをトレーニングします。

    Parameters:
    df (DataFrame): トレーニングに使用するデータフレーム。

    Returns:
    ARIMAResultsWrapper: トレーニングされたARIMAモデル。
    """
    model = ARIMA(df['price'], order=(5, 1, 0))
    model_fit = model.fit()
    return model_fit

def predict_future_prices(model_fit, df, months=12):
    """
    トレーニングされたARIMAモデルを使用して、将来の売電料金を予測します。

    Parameters:
    model_fit (ARIMAResultsWrapper): トレーニングされたARIMAモデル。
    df (DataFrame): 元のデータフレーム。
    months (int): 予測する月数。

    Returns:
    DataFrame: 予測された売電料金を含むデータフレーム。
    """
    forecast = model_fit.get_forecast(steps=months)
    forecast_dates = [df.index.max() + pd.DateOffset(months=i) for i in range(1, months + 1)]
    future_df = pd.DataFrame({'date': forecast_dates, 'predicted_price': forecast.predicted_mean})
    return future_df

def plot_predictions(df, future_df):
    """
    実際の売電料金と予測された売電料金をプロットし、画像として保存します。

    Parameters:
    df (DataFrame): 実際の売電料金を含むデータフレーム。
    future_df (DataFrame): 予測された売電料金を含むデータフレーム。
    """
    if not os.path.exists(DIST_DIR):
        os.makedirs(DIST_DIR)
    output_file = os.path.join(DIST_DIR, 'price_prediction.png')

    # 日本語フォントの設定
    font_path = '/System/Library/Fonts/ヒラギノ角ゴシック W3.ttc'  # macOSの例
    prop = fm.FontProperties(fname=font_path)

    plt.figure(figsize=(10, 6))
    plt.plot(df.index, df['price'], label='実際の売電料金')
    plt.plot(future_df['date'], future_df['predicted_price'], label='予測売電料金', linestyle='--')
    plt.xlabel('日付', fontproperties=prop)
    plt.ylabel('売電料金 (円)', fontproperties=prop)
    plt.title('売電料金の予測', fontproperties=prop)
    plt.legend(prop=prop)
    plt.grid(True)
    plt.savefig(output_file)
    plt.show()

def predict():
    """
    データを読み込み、前処理し、ARIMAモデルをトレーニングし、
    将来の売電料金を予測してプロットします。
    """
    # データの読み込みとフィルタリング
    all_data = load_and_filter_csv_files(DATA_DIR)
    if all_data.empty:
        print("No data found.")
        return

    # データの前処理
    processed_data = preprocess_data(all_data)

    # モデルのトレーニング
    model_fit = train_arima_model(processed_data)

    # 将来の売電料金を予測
    future_predictions = predict_future_prices(model_fit, processed_data, months=12)

    # 予測結果をグラフとして出力
    plot_predictions(processed_data, future_predictions)

rye なら、predict[project.scripts] に定義すれば以下のように実行できます

$ rye run predict

実行するとグラフ画像が作成されて表示されます

予測させてみた実際のデータ

price_prediction.png
雪国なので冬の売電はかなり落ち込みますね
過去3年のデータしか無いのでイマイチですが・・・
たぶん1月はもっと低いはず
SARIMAのほうが良かったかな・・・

まとめ

グラフを見ると、ここ3年くらいでは売電は過剰に減っているという感じでも無さそうでした。

予測に関しては、より長期的なデータや、気候変動、電力市場の変化などの外部要因も考慮に入れることで、さらに精度の高い予測が可能になるかもしれません。
また、SARIMAモデルなど、他の時系列モデルも今度試してみようと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?