|
import numpy as np |
|
import matplotlib.pyplot as plt |
|
import os |
|
import pandas as pd |
|
import argparse |
|
|
|
|
|
def sample_plot(samples: np.ndarray, |
|
index: pd.PeriodIndex, |
|
prediction_intervals=(50.0, 90.0), |
|
color='g'): |
|
def alpha_for_percentile(p): |
|
return (p / 100.0) ** 0.3 |
|
|
|
for c in prediction_intervals: |
|
assert 0.0 <= c <= 100.0 |
|
|
|
ps = [50.0] + [ |
|
50.0 + f * c / 2.0 |
|
for c in prediction_intervals |
|
for f in [-1.0, +1.0] |
|
] |
|
percentiles_sorted = sorted(set(ps)) |
|
|
|
sample_idxs = [int(np.round((samples.shape[0] - 1) * p)) for p in percentiles_sorted] |
|
sorted_samples = np.sort(samples, axis=0) |
|
ps_data = [sorted_samples[idx, :] for idx in sample_idxs] |
|
|
|
i_p50 = len(percentiles_sorted) // 2 |
|
p50_data = ps_data[i_p50] |
|
p50_series = pd.Series(data=p50_data, index=index.to_timestamp()) |
|
p50_series.plot(color=color, ls="-", label=f"median") |
|
|
|
for i in range(len(percentiles_sorted) // 2): |
|
ptile = percentiles_sorted[i] |
|
alpha = alpha_for_percentile(ptile) |
|
plt.fill_between( |
|
index.to_timestamp(), |
|
ps_data[i], |
|
ps_data[-i - 1], |
|
facecolor=color, |
|
alpha=alpha, |
|
interpolate=True |
|
) |
|
|
|
|
|
def plot_prob_forecasts(ts_entry, samples, index, prediction_length, path): |
|
plot_length = 150 |
|
prediction_intervals = (50, 67, 95, 99) |
|
legend = ["observations", "median prediction"] + [f"{k}% prediction interval" for k in prediction_intervals][::-1] |
|
|
|
_, ax = plt.subplots(1, 1, figsize=(10, 7)) |
|
ts_entry[-plot_length:].plot(ax=ax) |
|
sample_plot(samples, index, prediction_intervals=prediction_intervals) |
|
ax.axvline(ts_entry.index[-prediction_length], color='r') |
|
plt.legend(legend, loc="upper left") |
|
if path is None: |
|
plt.show() |
|
plt.clf() |
|
else: |
|
plt.savefig('{}forecast.png'.format(path)) |
|
plt.close() |
|
|
|
|
|
def arg_parse(): |
|
parser = argparse.ArgumentParser() |
|
parser.add_argument("-p", |
|
"--prediction-length", |
|
type=int, |
|
required=True, |
|
help="Prediction length of the forecast") |
|
parser.add_argument("-f", |
|
"--freq", |
|
required=True, |
|
help="Prediction frequency of the forecast") |
|
parser.add_argument("-t", |
|
"--start-time", |
|
required=True, |
|
help="Start of the forecast") |
|
parser.add_argument("--target-path", |
|
required=True, |
|
help="Target NDArray path") |
|
parser.add_argument("--samples-path", |
|
required=True, |
|
help="Samples NDArray path") |
|
parser.add_argument("-o", |
|
"--output-dir", |
|
help="Plot output directory") |
|
|
|
return parser.parse_args() |
|
|
|
|
|
if __name__ == "__main__": |
|
args = arg_parse() |
|
target = np.load(args.target_path)['target'] |
|
start_date = pd.Period(args.start_time, freq=args.freq) |
|
samples = np.load(args.samples_path)['samples'] |
|
index = pd.period_range(start_date + target.shape[-1] - args.prediction_length, periods=args.prediction_length, |
|
freq=args.freq) |
|
ts = pd.Series(data=target, index=pd.period_range(start_date, periods=target.shape[-1], freq=start_date.freq)) |
|
|
|
if args.output_dir is not None: |
|
plot_log_path = args.output_dir |
|
directory = os.path.dirname(plot_log_path) |
|
if not os.path.exists(directory): |
|
os.makedirs(directory) |
|
else: |
|
plot_log_path = None |
|
|
|
print("Plotting time series predictions ...") |
|
plot_prob_forecasts(ts, samples, index, args.prediction_length, plot_log_path) |