# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# +
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib as mpl
import torch
from sklearn.metrics import mean_squared_error as mse

from fastai.basic_train import Learner
from fastai.callbacks import OneCycleScheduler
from fastai.basic_data import DatasetType

from dies.data import ds_from_df_from_dtypes,  scale_datasets, create_databunch
from dies.data import train_test_split_dataset_with_test_date, train_test_split_dataset
from dies.mlp import MultiLayerPeceptron
from dies.embedding import Embedding
from dies.utils_pytorch import dev_to_np, xavier_init_uniform
sns.set_context('poster')
sns.set_style('whitegrid')
mpl.rcParams["legend.loc"] = 'upper left'
# -

with pd.HDFStore('./data/GEFCOM_Z1.h5') as store:
    df = store['powerdata']

df.head(2)

# Drop columns with na values

df = df.fillna(df.mean())

df = df.dropna(axis=1)

df.head(2)

# Create proper timestamp

df.TimeUTC = pd.to_datetime(df.TimeUTC, infer_datetime_format=True, utc=True)
df.set_index('TimeUTC', inplace=True)

# Normalize output

df.PowerGeneration = df.PowerGeneration.apply(float) / df.MaxPowerGeneration.apply(float)
df.drop('MaxPowerGeneration', axis=1, inplace=True)

# Create features for timeseries

df['DayOfYear'] = df.index.dayofyear
df['Hour'] = df.index.hour

df.dtypes

ds = ds_from_df_from_dtypes(df, y_columns='PowerGeneration')

# Assure correct columns were selected

ds.x_columns, ds.cat_columns, ds.y_columns

ds_tr, ds_val, ds_te = train_test_split_dataset_with_test_date(ds, '2013-01-01')

# We can use y_ranges to scale the output in the area of the output. Here, it doesn't make much sense, as the output is already normalized, and it is rather for demonstrating functionality.

y_ranges = ds_tr.y_ranges

# Scale the input

scale_datasets(train_dataset=ds_tr, other_datasets=[ds_val, ds_te])

# Create databunch for fastai training

db = create_databunch(ds_tr, ds_val, ds_te, batch_size=128, device='cpu')

# Create MLP Model

input_size = ds_tr.x.shape[1]
sizes_cat = [ds_tr.cat[:,0].max()+1, ds_tr.cat[:,1].max()+1]

embedding_module = Embedding(sizes_cat, embedding_dropout=0.1)
ann_model = MultiLayerPeceptron(input_size, ann_structure=[12, 6, 1], 
                                embedding_module=embedding_module, 
                                dropout=0.1, y_ranges=y_ranges)
ann_model = ann_model.apply(xavier_init_uniform)

#  Train it

learn = Learner(
    db,
    ann_model,
    loss_func=torch.nn.MSELoss(),
)
cbs = [OneCycleScheduler(learn, lr_max=0.1)]

learn.fit(10, callbacks=cbs)

# Evaluation...Note, that through ```inverse_transform_input``` we can reverse the scaling of the input data.

df_test = ds_te.to_df(inverse_transform_input=True)
y_hat, _  = learn.get_preds(DatasetType.Test)
df_test['Y_hat'] = dev_to_np(y_hat)

plt.figure(figsize=(12,8))
plt.scatter(df_test.WindSpeed100m, df_test.PowerGeneration, label='Target')
plt.scatter(df_test.WindSpeed100m, df_test.Y_hat, label='Prediction')
plt.xlabel('Wind speed [m/s²]')
plt.ylabel('Normalized Power')
plt.legend()

print(f'Test nRMSE: {mse(df_test.PowerGeneration, df_test.Y_hat, squared=False)}')

StarcoderdataJupyterScriptsDedupFiltered