Predicting Temperature in London¶

1. データ分析¶

ライブラリをインポートする

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import mlflow
import mlflow.sklearn
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor

import warnings
warnings.simplefilter('ignore', FutureWarning)
df = pd.DataFrame(pd.read_csv('london_weather.csv'))

df.describe()
date cloud_cover sunshine global_radiation max_temp mean_temp min_temp precipitation pressure snow_depth
count 1.534100e+04 15322.000000 15341.000000 15322.000000 15335.000000 15305.000000 15339.000000 15335.000000 15337.000000 13900.000000
mean 1.999567e+07 5.268242 4.350238 118.756951 15.388777 11.475511 7.559867 1.668634 101536.605594 0.037986
std 1.212176e+05 2.070072 4.028339 88.898272 6.554754 5.729709 5.326756 3.738540 1049.722604 0.545633
min 1.979010e+07 0.000000 0.000000 8.000000 -6.200000 -7.600000 -11.800000 0.000000 95960.000000 0.000000
25% 1.989070e+07 4.000000 0.500000 41.000000 10.500000 7.000000 3.500000 0.000000 100920.000000 0.000000
50% 2.000010e+07 6.000000 3.500000 95.000000 15.000000 11.400000 7.800000 0.000000 101620.000000 0.000000
75% 2.010070e+07 7.000000 7.200000 186.000000 20.300000 16.000000 11.800000 1.600000 102240.000000 0.000000
max 2.020123e+07 9.000000 16.000000 402.000000 37.900000 29.000000 22.300000 61.800000 104820.000000 22.000000
  • date 列を pd.to_datetime() に渡して、datetime データ型に変換します。 %Y%m%d 形式を使用します。
  • .groupby() を使用してデータを簡単にグループ化できるように、日付の年と月の列を作成することもできます。
  • lineplot() メソッドを使用して温度を視覚化できます。
  • heatmap() および .corr() 関数を使用すると、特徴間の相関関係を視覚化できます。
df['datetime'] = pd.to_datetime(df['date'], format = '%Y%m%d')

df.sample(10)
date cloud_cover sunshine global_radiation max_temp mean_temp min_temp precipitation pressure snow_depth datetime
1564 19830414 5.0 2.6 124.0 18.0 7.2 2.4 0.0 102930.0 0.0 1983-04-14
948 19810806 6.0 0.0 70.0 18.2 17.4 15.6 23.8 101690.0 0.0 1981-08-06
7478 19990623 6.0 5.9 219.0 23.0 16.9 12.1 0.0 102270.0 0.0 1999-06-23
1020 19811017 8.0 0.0 30.0 13.2 5.6 1.9 4.7 101580.0 0.0 1981-10-17
9556 20050301 8.0 0.2 41.0 5.9 2.4 -1.0 3.8 100550.0 0.0 2005-03-01
4149 19900512 6.0 3.8 169.0 17.2 13.0 10.0 0.0 101270.0 0.0 1990-05-12
11531 20100728 5.0 6.9 220.0 23.3 20.3 15.4 0.0 101710.0 NaN 2010-07-28
6000 19950606 7.0 0.5 105.0 20.1 14.4 11.0 0.1 102330.0 0.0 1995-06-06
8655 20020912 3.0 9.2 182.0 24.6 18.9 14.3 0.0 102520.0 0.0 2002-09-12
12399 20121212 6.0 0.9 21.0 6.7 -1.9 -4.1 0.0 102060.0 0.0 2012-12-12

欠損値をヒートマップで可視化してみます。

plt.figure(figsize=(8, 6))
sns.heatmap(df.isnull(), cmap="YlGnBu")

plt.show()

2. データの可視化¶

平均気温をプロットします。

fig = plt.subplots(figsize=(16, 6))
sns.lineplot(df, 
             x = 'datetime', 
             y = 'mean_temp', 
             alpha = .3,
            )
plt.show()

平均気温、最高気温、最低気温をそれぞれ年ごとにまとめます。

df_year_mean = df.groupby(pd.Grouper(key="datetime", freq="Y")).agg({'mean_temp':'mean'})
df_year_max = df.groupby(pd.Grouper(key="datetime", freq="Y")).agg({'max_temp':'max'})
df_year_min = df.groupby(pd.Grouper(key="datetime", freq="Y")).agg({'min_temp':'min'})
fig = plt.subplots(figsize=(12, 5))
sns.lineplot(df_year_max, x= 'datetime', y = 'max_temp')
sns.lineplot(df_year_mean, x= 'datetime', y = 'mean_temp')
sns.lineplot(df_year_min, x= 'datetime', y = 'min_temp')
<AxesSubplot: xlabel='datetime', ylabel='max_temp'>

特徴の相関図を出力します。

fig = plt.subplots(figsize=(10, 8))
sns.heatmap(df.corr(), annot=True)
plt.show()

3 機能の選択¶

ステップ 2 で作成した視覚化に基づいて、平均気温を予測するために適切な特徴を選択します。

フィルター機能¶

  • 文字列名のリストを作成することで、特徴をフィルタリングできます (例: weather_metrics = ["sunshine", "cloud cover"])。
  • .dropna() メソッドを使用して、ターゲット変数の使用できない値を必ず削除します。
feature_selection = ['sunshine',
                     'cloud_cover',
                     'max_temp',
                     'min_temp',
                     'precipitation',
                     'pressure']

target_var = 'mean_temp'

weather_metrics = ["sunshine", "cloud cover", 'global_radiation']
df = df.dropna()

4 データの前処理¶

imputer を使用して欠損値を考慮し、スケーラーを使用して特徴を正規化します。適切なタイミングでデータをトレーニング サンプルとテスト サンプルに分割します。
これらの前処理ステップはパイプラインに入れる必要があります。

データの代入と正規化¶

  • train_test_split() メソッドを使用してデータを分割します。
  • SimpleImputer() メソッドは値を代入できます。
  • StandardScaler() メソッドは値を正規化できます。データの代入と正規化を、トレーニングとテストセットに必ず個別に適用します。
  • これらのステップをpreprocess_data 関数に組み込みます。

欠損値の数を確認します。

df.isnull().sum()
date                0
cloud_cover         0
sunshine            0
global_radiation    0
max_temp            0
mean_temp           0
min_temp            0
precipitation       0
pressure            0
snow_depth          0
datetime            0
dtype: int64

関数を定義します

def preprocess_df(df, feature_selection, target_var):
    """
    データフレームを X と y に分割し、train と test を連続して実行します
    次に、train と test の両方を代入してスケーリングします
    トレインとテスト ET を返します
    """
    X = df[feature_selection]    
    y = df[target_var]
    
    X_train, X_test, y_train, y_test = train_test_split(X, y)


    imputer = SimpleImputer(strategy="mean")

    X_train = imputer.fit_transform(X_train)
    X_test  = imputer.transform(X_test)
    
    scaler = StandardScaler()
    
    X_train = scaler.fit_transform(X_train)
    X_test = scaler.transform(X_test)


    return X_train, X_test, y_train, y_test

定義した関数を使用してX,y ををれぞれ train と test に分離します。

X_train, X_test, y_train, y_test = preprocess_df(df, feature_selection, target_var)

5 機械学習のトレーニングと評価¶

線形回帰、デシジョン ツリー、ランダム フォレスト回帰の 3 つの回帰モデルに適合する関数を作成し、MLflow を使用してログに記録します。

機械学習モデルのトレーニングと評価¶

  • テストサンプルを予測し、.predict() および .mean_squared_error() メソッドを使用して predict_and_evaluate() を評価する関数を作成します。
  • for ループを完了して、max_Depth_parameters を使用して少なくとも 5 つの異なる実験を実行します。
  • with mlflow.start_run() メソッドを使用して MLflow 実験を実行します。
  • log_param() および log_metric() メソッドを使用してパラメータとメトリクスをログに記録します。

関数を定義

def predict_and_evaluate(model, x_test, y_test):
    """
    テスト セットから値を予測し、二乗平均平方根誤差を計算して返します。
    """
    # Complete this function
    y_pred = model.predict(x_test)
    rmse = np.sqrt(mean_squared_error(y_test, y_pred))
    
    return rmse
EXPERIMENT_NAME = "temp_prediction"
EXPERIMENT_ID = mlflow.create_experiment(EXPERIMENT_NAME)
max_depth_parameters = [1, 2, 5, 10, 20]

for idx, depth in enumerate(max_depth_parameters):
    parameters = {
                'max_depth': depth,
                'random_state': 1
                }    
    RUN_NAME = f"run_{idx}"
    
    with mlflow.start_run(experiment_id=EXPERIMENT_ID, run_name=RUN_NAME):

        lr = LinearRegression().fit(X_train, y_train)
        dt = DecisionTreeRegressor(random_state=3, max_depth=depth).fit(X_train, y_train)
        rf = RandomForestRegressor(random_state=3, max_depth=depth).fit(X_train, y_train)
        
        mlflow.sklearn.log_model(lr, "lr")
        mlflow.sklearn.log_model(dt, "dt")
        mlflow.sklearn.log_model(rf, "rf")
        
        lr_rmse = predict_and_evaluate(lr, X_test, y_test)
        dt_rmse = predict_and_evaluate(dt, X_test, y_test)
        rf_rmse = predict_and_evaluate(rf, X_test, y_test)
        
        mlflow.log_param("max_depth", depth)
        mlflow.log_metric("rmse_lr", lr_rmse)
        mlflow.log_metric("rmse_dt", dt_rmse)
        mlflow.log_metric("rmse_rf", rf_rmse)
experiment_results = mlflow.search_runs(experiment_names=[EXPERIMENT_NAME])
select_col = ['metrics.rmse_rf', 'metrics.rmse_lr', 'metrics.rmse_dt','params.max_depth']
ex_selected = experiment_results[select_col]
ex_selected
metrics.rmse_rf metrics.rmse_lr metrics.rmse_dt params.max_depth
0 0.890582 0.906798 1.286103 20
1 0.876378 0.906798 1.055993 10
2 1.093600 0.906798 1.272120 5
3 2.258520 0.906798 2.362033 2
4 3.352830 0.906798 3.456210 1
5 0.892092 0.906798 1.287195 20
6 0.877652 0.906798 1.056883 10
7 1.097111 0.906798 1.272120 5
8 2.267905 0.906798 2.362033 2
9 3.374730 0.906798 3.456210 1

データフレームを見やすく加工します。

pd.DataFrame({
    'RandomForestRegression': experiment_results['metrics.rmse_rf'],
    'LinerRegression': experiment_results['metrics.rmse_lr'],
    'DecisionTreeRegression': experiment_results['metrics.rmse_dt'],
    
    'MaxDepth': experiment_results['params.max_depth']
                                   })
RandomForestRegression LinerRegression DecisionTreeRegression MaxDepth
0 0.892092 0.906798 1.287195 20
1 0.877652 0.906798 1.056883 10
2 1.097111 0.906798 1.272120 5
3 2.267905 0.906798 2.362033 2
4 3.374730 0.906798 3.456210 1