File size: 4,259 Bytes
64ab846
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import numpy as np
import pandas as pd
import yaml
import pickle
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import torch
from xgboost import XGBRegressor
from sklearn.metrics import mean_absolute_error, mean_squared_error
from pipelines.xgcast_pipeline import normalise_df


with open('config/params.yml') as file:
    config = yaml.safe_load(file)
with open('config/xgcast_params.yml') as file:
    model_params = yaml.safe_load(file)

pd.options.plotting.backend = "plotly"


datetime_col = config['datetime_col']
value_col = config['value_col']
datastream_name_col = config['datastream_name_col']

resampling_window = config['resampling_window']
resampling = int(resampling_window.split('h')[0])

num_predictions = config['num_predictions']


### Functions

def get_sensor_data(consortium_name, sensor_forecasted):
    sensor_data = pd.read_parquet(f'data//05_xgcast_input//tensiometers_{consortium_name}.parquet')
    sensor_data = sensor_data[sensor_data[datastream_name_col] == sensor_forecasted].set_index(datetime_col).sort_index()
    return sensor_data

def get_mean_and_std(consortium_name):
    mean_std_df = pd.read_parquet(f'data//05_xgcast_input//mean_std_{consortium_name}.parquet')
    return mean_std_df

def get_feature_cols(consortium_name):
    with open(f'data//05_xgcast_input//feature_cols_{consortium_name}.pickle', 'rb') as handle:
        feature_cols = pickle.load(handle)
    return feature_cols

def get_model(consortium_name, model_name):
    if model_name == 'xgboost':
        xgb_params = model_params['xgb_params']
        bst = XGBRegressor(objective='reg:absoluteerror', **xgb_params)
        bst.load_model(f'data//06_xgcast_output//xgcast_{consortium_name}.json')
        return bst
    else:
        print('Model not available.')

def get_predictions(consortium_name, model, sensor_data):
    sns_data = sensor_data.copy()

    mean_std_df = get_mean_and_std(consortium_name)
    feature_cols = get_feature_cols(consortium_name)

    sns_data = sns_data[feature_cols].sort_index()

    current_data_point = normalise_df(sns_data, mean_std_df)
    predictions = model.predict(current_data_point) * mean_std_df['std'][value_col] + mean_std_df['mean'][value_col]
    predictions = pd.DataFrame(predictions, columns=[f'prediction_next_{i+1}periods' for i in range(num_predictions)], index=sns_data.index)
    predictions = predictions.join(sns_data[[value_col, 'precipitation', 'irrigation']]).rename(columns={value_col: 'real_value'})
    return predictions

def plot_sensor_forecasted(sensor_forecasted, predictions, target_col, thresholds, additional_cols_plot):
    # BUILD PLOT
    fig = make_subplots(specs=[[{"secondary_y": True}]])
    fig.add_trace(
        go.Scatter(
            x=predictions.index,
            y=predictions[target_col],
            mode="lines",
            name="value",
        ),
        secondary_y=False
    )
    for col in predictions.columns:
        if 'prediction_next_' in col:
            fig.add_trace(
                go.Scatter(
                    x=predictions.index,
                    y=predictions[col],
                    mode="lines",
                    name=col,
                ),
                secondary_y=False
            )

    for col in additional_cols_plot:
        fig.add_trace(
            go.Bar(
                x=predictions.index,
                y=predictions[col],
                name=col,
            ),
            secondary_y=True
        )

    fig.add_hline(
        y=thresholds[0], line_width=3, line_dash="dash"
    )
    fig.add_hline(
        y=thresholds[1], line_width=3, line_dash="dash"
    )

    fig.update_layout(
        title=f"Tensiometer values for sensor {sensor_forecasted}",
        font=dict(
            family="Courier New, monospace",
            size=12
        )
    )
    # Set x-axis title
    fig.update_xaxes(title_text="datetime")
    # Set y-axes titles
    fig.update_yaxes(title_text="Tension (mbar)", secondary_y=False)
    if len(additional_cols_plot) > 0:
        fig.update_yaxes(title_text='Water amount (mm)', secondary_y=True)

    return fig