Source code for optimization.model_synthetic_data_

"""
========================================================
Solver Applications in Optimization and Network Modeling
========================================================


The provided code constitutes a comprehensive framework for research and development in the fields of artificial intelligence and computational biology. Its architecture consists of specialized modules addressing key aspects of modeling, machine learning, and optimization, with an emphasis on code robustness and reusability.

From a technical perspective, the code includes:

Training Data Generation: Functionality for generating synthetic data and manipulating real datasets, with advanced options for controlled noise introduction and simulation of specific scenarios.

Machine Learning Model Development: Tools for constructing and customizing machine learning models, including deep neural network architectures and supervised and unsupervised learning algorithms.

Performance Evaluation: Capabilities for systematically evaluating model performance under various conditions, using statistical metrics and visualizations to analyze prediction quality and generalization ability.

Optimization Solver Comparison: Functionality for comparing different optimization methods used in solving specific problems, with tools for measuring convergence, computational efficiency, and scalability.

The underlying technical approach is based on the efficient implementation of algorithms and data structures, leveraging high-performance software libraries, and adopting software engineering practices such as modularity, encapsulation, and detailed documentation.




"""


import os
import warnings
from typing import Any, Callable, List, Tuple, Optional

import keras.backend as K
import numpy as np
import pandas as pd
import scipy.io as sio
import tensorflow as tf
import cvxpy as cp
from google.colab import drive
from keras import Model, backend as k, layers, regularizers
from keras.layers import (
    Activation, Concatenate, Conv1D, Conv2D, Dense, Dropout, Flatten, Input,
    Lambda, MaxPool1D, MaxPooling2D, ReLU, Reshape, BatchNormalization, Dot
)
from keras.models import Sequential
from matplotlib import pyplot as plt
from matplotlib.gridspec import GridSpec
from scipy.optimize import linprog
from sklearn.metrics import (
    mean_squared_error, mean_absolute_error, mean_absolute_percentage_error
)
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler, StandardScaler
from tensorflow.keras.callbacks import Callback
from tensorflow.python.ops.nn_ops import softmax
from IPython import display
from typing import List, Optional
# Metrics aliases for clarity
mse = mean_squared_error
mae = mean_absolute_error
mape = mean_absolute_percentage_error

# Suppress warnings
warnings.filterwarnings("ignore")


[docs]def add_noise(data: np.ndarray, snr: float, mu: float = 0.0) -> np.ndarray: """ Generate noise to be added to a signal with a specified signal-to-noise ratio (SNR). Parameters ---------- data : np.ndarray The original signal data. snr : float The desired signal-to-noise ratio in decibels. mu : float, optional The mean value for the noise generation, default is 0.0. Returns ------- np.ndarray The generated noise array with the same shape as the input data. """ mean_signal = abs(np.mean(data)) signal_db = 10 * np.log10(mean_signal) noise_db = signal_db - snr noise_power = 10 ** (noise_db / 10) return np.random.normal(mu, np.sqrt(noise_power), data.shape)
[docs]def probability_vector(num_elements: int = 5) -> np.ndarray: """ Generate an array of size num_elements with elements rounded to two decimal places such that the sum is 1.0. Parameters ---------- num_elements : int, optional Number of elements in the generated array. Default is 5. Returns ------- np.ndarray A 1-D array of shape (num_elements, 1) with elements summing to 1.0. """ probabilities = np.empty(0) while probabilities.size != num_elements: random_probabilities = np.round( np.random.uniform(0.1, 1, num_elements), 2) if np.sum(random_probabilities) == 1.0: probabilities = random_probabilities return probabilities.reshape(num_elements, 1)
[docs]def random_matrix(num_ranges: int = 5, num_rows: int = 10) -> np.ndarray: """ Generate a matrix with uniformly distributed random values in the range [i-1, i], where i iterates from 1 to num_ranges, as columns, and num_rows rows. Parameters ---------- num_ranges : int, optional Number of different ranges to use for each column. Default is 5. num_rows : int, optional Number of rows in the generated matrix. Default is 10. Returns ------- np.ndarray A (num_rows, num_ranges) matrix of uniformly distributed random values. """ matrix = np.zeros((num_rows, num_ranges)) for i in range(1, num_ranges + 1): matrix[:, i - 1] = np.random.uniform(i - 1, i, num_rows) return matrix
[docs]class SoftmaxWeightConstraint(tf.keras.constraints.Constraint): """Constraint class that applies a softmax to the weights."""
[docs] def __init__(self, softmax_function: Callable[[tf.Tensor, int], tf.Tensor]): """ Initializes the constraint using a given softmax function. Parameters ---------- softmax_function : Callable[[tf.Tensor, int], tf.Tensor] The softmax function to be applied on the weights. """ self.softmax_function = softmax_function
[docs] def __call__(self, weights: tf.Tensor) -> tf.Tensor: """ Applies softmax on the weights along the specified axis. Parameters ---------- weights : tf.Tensor The tensor to which the softmax function will be applied. Returns ------- tf.Tensor The tensor with softmax applied. """ return self.softmax_function(weights, axis=0)
[docs] def get_config(self) -> dict: """ Gets the configuration of the constraint. Returns ------- dict A dictionary containing the configuration of the constraint. """ return {'softmax_function': self.softmax_function}
[docs]def minimize_l1_norm(y: np.ndarray, u: np.ndarray, s: int, solver: str = 'CPLEX') -> np.ndarray: """ Solve the optimization problem to find vector z that minimizes the L1 norm between y and the product of matrix u and vector z, with constraints that z sums to 1 and each entry in z is between 0 and 1 inclusive. Parameters ---------- y : np.ndarray The observed data vector (n by 1). u : np.ndarray The design matrix (n by s). s : int The length of the solution vector z. solver : str, optional The solver used for the optimization problem, default is 'CPLEX'. Returns ------- np.ndarray The solution vector z with shape (s, 1). """ z = cp.Variable((s, 1)) objective = cp.Minimize(cp.norm(y - u @ z, p=1)) constraints = [cp.sum(z) == 1, z >= 0, z <= 1] problem = cp.Problem(objective, constraints) problem.solve(solver=solver) Z_solution = z.value return Z_solution.reshape(s, 1)
[docs]class Evaluate: """ A class to handle the evaluation of models with respect to their Mean Absolute Percentage Error (MAPE) metrics on various noise levels, using different solvers for optimization problems. Attributes ---------- result_path : str The path where results should be saved. model_columns : List[str] List of column names for the models. solvers : np.ndarray An array of solver names. signal_to_noise_levels : List[Optional[int]] List of signal-to-noise ratios to be evaluated, including `None` for the original signal. """
[docs] def __init__(self, result_path: str = ''): """ Initialize the Evaluate class with default parameters. Parameters ---------- result_path : str, optional The path where results should be saved. Defaults to an empty string. """ self.model_columns: List[str] = [ 'NN(-1)', 'S(-1)', 'NN(1)', 'S(1)', 'NN(3)', 'S(3)', 'NN(5)', 'S(5)', 'NN(N)', 'S(N)' ] self.solvers: np.ndarray = np.array( ['CLARABEL', 'GUROBI', 'MOSEK', 'XPRESS', 'SCS']) self.signal_to_noise_levels: List[Optional[int] ] = [-1, 1, 3, 5, None]
[docs] def create_custom_model(self, input_size: int = 5, num_layers: int = 5, dropout_rate: float = 0.1, regularization_factor: float = 1e-4, learning_rate: float = 1e-3, loss: str = 'huber') -> Model: """ Create a custom Keras model with specified parameters and constraints. Parameters ---------- input_size : int, optional The size of the input layer. Default is 5. num_layers : int, optional The number of neurons in each dense layer. Default is 5. dropout_rate : float, optional The dropout rate for regularization. Default is 0.1. regularization_factor : float, optional The regularization factor for L1/L2 regularization. Default is 1e-4. learning_rate : float, optional The learning rate for the optimizer. Default is 1e-3. loss : str, optional The loss function selector. Default is 'huber'. Returns ------- Model A compiled Keras model. """ input_tensor = Input(shape=(input_size,)) loss = loss # Initialize the dense layer parameters dense_kwargs = { 'activation': 'relu', 'kernel_constraint': SoftmaxWeightConstraint(tf.nn.softmax) } # Build dense layers with constraints x = input_tensor for _ in range(num_layers): x = Dense(units=num_layers, **dense_kwargs)(x) x = Dropout(rate=dropout_rate)(x) # Output layer with softmax weight constraint and no bias output_tensor = Dense( units=1, activation=None, use_bias=False, kernel_constraint=SoftmaxWeightConstraint(tf.nn.softmax) )(x) # Create and compile the model model = Model(inputs=input_tensor, outputs=output_tensor) model.compile( loss = loss, optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate) ) return model
[docs] def ModelEval(self, output_path: str = '') -> Tuple[pd.DataFrame, pd.DataFrame]: """ Evaluate the model performance by measuring Mean Absolute Percentage Error (MAPE) on different levels of noise and save the results to Excel files. Parameters ---------- output_path : str, optional The directory path where Excel files will be saved. Defaults to an empty string. Returns ------- Tuple[pd.DataFrame, pd.DataFrame] A tuple containing two pandas DataFrames of MAPE for y and pi respectively. """ MAPE_y = pd.DataFrame(columns=self.model_columns) MAPE_pi = pd.DataFrame(columns=self.model_columns) for j in range(len(self.signal_to_noise_levels)): MSE_y: List[float] = [] MSE_pi: List[float] = [] for i in range(self.num_samples): true_pic = self.PIC[i] u = self.U[i] y = self.Y[j, i] modeloMax = self.create_custom_model() history = modeloMax.fit(u[0:400], y[0:400], epochs=100, batch_size=32, verbose=False, validation_split=0.3, steps_per_epoch=2) y_re = modeloMax.predict(u[400:], verbose=False) pic_re = modeloMax.layers[-1].get_weights()[0] y = self.Y[-1, i] MSE_y.append(mape(y[400:], y_re)) MSE_pi.append(mape(true_pic, pic_re)) MAPE_y[self.model_columns[j * 2]] = MSE_y MAPE_pi[self.model_columns[j * 2]] = MSE_pi MAPE_y.to_excel(f'{output_path}Modely.xlsx', index=False) MAPE_pi.to_excel(f'{output_path}Modelpi.xlsx', index=False) history_loss = pd.DataFrame(history.history) history_loss.to_excel(f'{output_path}hystory_loss'+self.loss+'.xlsx', index=False) return MAPE_y, MAPE_pi
[docs] def history_plot(self) -> pd.DataFrame: """ Plot the training history for different loss functions. Returns ------- pd.DataFrame A DataFrame containing the history of the model's loss and validation loss. """ # Obtener los datos de entrada y salida u = self.U[-1] y = self.Y[-1, 0] # Inicializar una lista para almacenar el historial de pérdidas history_loss = [] # Crear tres figuras independientes para cada función de pérdida fig, axs = plt.subplots(3, 1, figsize=(10, 18)) # Iterar sobre diferentes funciones de pérdida for i, loss_function in enumerate(['mse', 'mae', 'huber']): # Crear un modelo con la función de pérdida actual modeloMax = self.create_custom_model(loss=loss_function) # Entrenar el modelo y obtener el historial de pérdidas history = modeloMax.fit(u[0:400], y[0:400], epochs=100, batch_size=32, verbose=False, validation_split=0.3, steps_per_epoch=2) # Convertir el historial de pérdidas a un DataFrame y agregarlo a la lista history_loss.append(pd.DataFrame(history.history)) # Trazar la pérdida de entrenamiento y validación para la función de pérdida actual axs[i].plot(history_loss[-1]['loss'], label=loss_function) axs[i].plot(history_loss[-1]['val_loss'], label='val_' + loss_function) # Agregar leyendas y etiquetas de ejes para cada gráfico axs[i].legend() axs[i].set_xlabel('Epoch') axs[i].set_ylabel('Error') axs[i].set_title(f'Training and Validation Loss for {loss_function.upper()}') # Ajustar el espaciado entre subgráficos plt.tight_layout() # Mostrar las gráficas plt.show()
[docs] def evaluate_solver(self, solver: str, MAPE_y: pd.DataFrame, MAPE_pi: pd.DataFrame) -> Tuple[pd.DataFrame, pd.DataFrame]: """ Evaluate the solver performance by comparing the predicted results against the true values and update the Mean Absolute Percentage Error (MAPE) dataframes for y and pi variables. Parameters ---------- solver : str The name of the solver used for the optimization problem. MAPE_y : pd.DataFrame The DataFrame containing existing MAPE values for y. MAPE_pi : pd.DataFrame The DataFrame containing existing MAPE values for pi. Returns ------- Tuple[pd.DataFrame, pd.DataFrame] Updated MAPE dataframes for y and pi variables. """ for j, noise_level in enumerate(self.signal_to_noise_levels): MSE_s1: List[float] = [] MSE_s2: List[float] = [] solver_index = np.where(self.solvers == solver)[0][0] for i in range(self.num_samples): true_pic = self.PIC[i] u = self.U[i] y = self.Y[-1][i] z = self.Z[j][solver_index][i] MSE_s1.append(mean_absolute_percentage_error(y[400:], u[400:] @ z)) MSE_s2.append(mean_absolute_percentage_error(true_pic, z)) MAPE_y[self.model_columns[j * 2 + 1]] = MSE_s1 MAPE_pi[self.model_columns[j * 2 + 1]] = MSE_s2 return MAPE_y, MAPE_pi
[docs] def plot(self, solver: str, path: str = '') -> None: """ Plot the Mean Absolute Percentage Error (MAPE) for model predictions using a specified solver. Parameters ---------- solver : str The solver used for the optimization problem. path : str, optional The directory path where the data files are located. Defaults to an empty string. Raises ------ FileNotFoundError If the path does not contain the expected files. """ self.PIC = np.load(path + 'PIC.npy') self.U = np.load(path + 'U.npy') self.Y = np.load(path + 'Y.npy') self.Z = np.load(path + 'Z.npy') self.num_samples = self.U.shape[0] # Attempt to load existing MAPE results; calculate if not available try: MAPE_y = pd.read_excel(path + 'Modely.xlsx') MAPE_pi = pd.read_excel(path + 'Modelpi.xlsx') except FileNotFoundError: MAPE_y, MAPE_pi = self.ModelEval() # Evaluate using the specified solver MAPE_y, MAPE_pi = self.evaluate_solver(solver, MAPE_y, MAPE_pi) # Reverse the order of the columns for plotting MAPE_y = MAPE_y.loc[:, ::-1] MAPE_pi = MAPE_pi.loc[:, ::-1] # Set up plots fig = plt.figure(figsize=(19, 9)) gs = GridSpec(nrows=2, ncols=2) # Plot MAPE for y ax0 = fig.add_subplot(gs[:, 0]) ax0.set_yscale('log') ax0.set_ylabel('MAPE', fontsize=20) ax0.set_xlabel('Noise levels', fontsize=20) MAPE_y.boxplot(ax=ax0, boxprops=dict(color='blue'), medianprops=dict(color='orangered'), whiskerprops=dict(color='blue')) ax0.tick_params(axis='x', labelsize=20, rotation=45) ax0.tick_params(axis='y', labelsize=20) ax0.set_ylim([1e-12, 1e0]) # Plot MAPE for pi ax1 = fig.add_subplot(gs[:, 1]) ax1.set_yscale('log') ax1.set_ylabel('MAPE', fontsize=20) ax1.set_xlabel('Noise levels', fontsize=20) MAPE_pi.boxplot(ax=ax1, boxprops=dict(color='blue'), medianprops=dict(color='orangered'), whiskerprops=dict(color='blue')) ax1.tick_params(axis='x', labelsize=20, rotation=45) ax1.tick_params(axis='y', labelsize=20) ax1.set_ylim([1e-11, 1e1]) # Display the plots plt.show()
[docs] def data_generate(self, M: int = 10, N: int = 120, s: int = 5) -> None: """ Generate data sets for the optimization problem with given parameters M, N, and s. Parameters ---------- M : int, optional Number of samples to generate. Default is 10. N : int, optional The number of observations for each sample. Default is 120. s : int, optional The number of elements in the PIC vector. Default is 5. Side effects ------------ Saves arrays to disk (`PIC.npy`, `Z.npy`, `U.npy`, `Y.npy`). Prints the shapes of the generated arrays to the console. """ columns = ['CLARABEL', 'GUROBI', 'MOSEK', 'XPRESS', 'SCS'] SNR = [-1, 1, 3, 5, None] PIC = np.zeros((M, s, 1)) U = np.zeros((M, N, s)) Y = np.zeros((len(SNR), M, N, 1)) Z = np.zeros((len(SNR), len(columns), M, s, 1)) for j in range(M): pic = probability_vector(s) u = random_matrix(s, N) for k, snr_level in enumerate(SNR): y = u @ pic if snr_level is not None: y += add_noise(y, snr_level) U[j] = u PIC[j] = pic Y[k, j] = y for i, solver in enumerate(columns): z = minimize_l1_norm(y, u, s, solver=solver) Z[k, i, j] = z np.save('PIC.npy', PIC) np.save('Z.npy', Z) np.save('U.npy', U) np.save('Y.npy', Y) print(np.array(PIC).shape, np.array(Z).shape, np.array(U).shape, np.array(Y).shape)
[docs]class FlyEvaluate: """ A class designed to evaluate a population growth model for fruit flies, and compare the performance of different solvers. """
[docs] def __init__(self, N: int = 100, C: int = 500, t: int = 1) -> None: """ Initialize FlyEvaluate with default parameters. Parameters ---------- N : int, optional Number of simulation runs. Default is 100. C : int, optional Number of cycles in the simulation. Default is 500. t : int, optional Time lag in the model. Default is 1. """ self.C = C self.N = N self.t = t self.solver = np.array([ 'CLARABEL', 'GUROBI', 'MOSEK', 'XPRESS', 'SCS' ])
[docs] def parameters(self) -> Tuple[float, float, float, float, float, float, float]: """ Generate parameters for the growth model using random normal distributions. Returns ------- Tuple[float, float, float, float, float, float, float] A tuple of parameters (P, d, N0, od, op, e1, e2). """ P = np.random.normal(2, 2**2) d = np.random.normal(-1.8, 0.4**2) N0 = np.random.normal(6, 0.5**2) od = np.random.normal(-0.75, 1**2) op = np.random.normal(-0.5, 1**2) e1 = 1 e2 = 1 return P, d, N0, od, op, e1, e2
[docs] def fly_data( self, P: float, N0: float, d: float, e2: float, e1: float, C: int) -> Tuple[np.ndarray, np.ndarray]: """ Generate data for the fly population growth and corresponding weight matrices. Parameters ---------- P : float Growth rate. N0 : float Initial population. d : float Death rate. e2 : float Error term for the death rate. e1 : float Error term for the growth rate. C : int Number of cycles. Returns ------- Tuple[np.ndarray, np.ndarray] Tuple of N (fly population) and W (weights) both as numpy arrays. """ N: List[float] = [0] * self.t N.append(N0) W: List[List[float]] = [] for i in range(self.t, C - 1): N.append(P * N[i - self.t] * np.exp(-N[i - self.t] / N0) * e1 + N[i] * np.exp(d * e2)) aux = [0.0] * (self.t + 1) aux[0] = np.exp(d * e2) aux[-1] = P * np.exp(-N[i - self.t] / N0) * e1 W.append(aux) return np.array(N), np.array(W)
[docs] def generate(self) -> None: """ Generate and save data for fly population growth, as well as the optimization problems for different solvers. """ N=[];W=[];Y=[];X=[] Z=np.ones((self.solver.shape[0],self.N,self.C-1,self.t+1))*1000 for j in range(self.N): #Z.append([]) p,d,n0,_,_,e1,e2=self.parameters() n,w=self.Flydata(p,n0,d,e2,e1,self.C) suma=0 y=[] xx=[] for i in range(self.t,self.C-1): #Z[j].append([]) x=[] for k in range(i,i-self.t-1,-1): suma=suma+1 x.append(n[k]) x=np.array([x]) Ps=x.T@x Qs=-2*(n[i+1]*x).T y.append(n[i+1]) r0=n[i+1]*n[i+1] for s in range(len(self.solver)): #Z[j][i-self.t].append([]) z=cp.Variable(self.t+1) #obj=cp.Minimize(0.5*cp.quad_form(z,Ps)+Qs.T@z+r0) #prob=cp.Problem(obj) #z=cp.Variable((s,1)) obj=cp.Minimize(cp.norm(y-x@z,p=2)) prob=cp.Problem(obj) #prob.solve(solver=solver) try: prob.solve(solver=self.solver[s]) #Z[s][j][i]=np.array(z.value) Z[s][j][i-self.t]=z.value except: Z[s][j][i-self.t]=np.array([0,0]) #print(Z[j][i-self.t][s]) xx.append(x[0]) W.append(w) Y.append(y) X.append(xx) W=np.array(W) Z=np.array(Z)[:, :,:-1,:] Y=np.array(Y) X=np.array(X) np.save('FW.npy',W) np.save('FZ.npy',Z) np.save('FY.npy',Y) np.save('FX.npy',X) print(W.shape,Z.shape,Y.shape,X.shape)
[docs] def model_op(self, loss: str ='huber') -> Model: """ Create a Keras model with a set of dense layers and custom regularization. Parameters: - loss (str): The loss function selector. Defaults to 'huber'. Returns: - Model: A compiled Keras model. """ input_tensor = Input(shape=(2,)) regularization_strength = 1e-1 learning_rate = 1e-3 layer = input_tensor for i in range(1, 5): layer = Dense( 32, activation='selu', kernel_regularizer=regularizers.L1L2( l1=regularization_strength, l2=regularization_strength ), name=f'Dense_{i}' )(layer) weights = Dense( 2, activation='selu', kernel_regularizer=regularizers.L1L2( l1=regularization_strength, l2=regularization_strength ), name='W' )(layer) output_tensor = tf.reduce_sum(tf.multiply(weights, input_tensor), axis=-1) output_tensor = Reshape((1,))(output_tensor) model = Model(inputs=input_tensor, outputs=output_tensor) model.compile(loss = loss, optimizer=tf.keras.optimizers.Adam(learning_rate)) return model
[docs] def model_eval(self, path: str = '') -> Tuple[pd.DataFrame, pd.DataFrame]: """ Evaluate the model and compute Mean Absolute Percentage Error (MAPE) for predictions. Parameters: - path (str): The directory path to load and save data files. Defaults to an empty string. Returns: - Tuple[pd.DataFrame, pd.DataFrame]: A tuple containing two pandas DataFrames with MAPE for predictions and weights. """ columns = ['Red', 'Solver'] mape_y = pd.DataFrame(columns=columns) mape_w = pd.DataFrame(columns=columns) fy = np.load(path + 'FY.npy', allow_pickle=True) fx = np.load(path + 'FX.npy', allow_pickle=True) fw = np.load(path + 'FW.npy', allow_pickle=True) mse_r1 = [] mse_r2 = [] for j in range(fx.shape[0]): model_max = self.model_op() history = model_max.fit( fx[j, 0:400], fy[j][0:400], epochs=400, batch_size=32, verbose=False, validation_split=0.3 ) ye = model_max.predict(fx[j, 400:], verbose=False) mse_r2.append(mape(fy[j, 400:], ye)) weights_model = tf.keras.Model( inputs=model_max.inputs, outputs=model_max.get_layer('W').output ) mse_r1.append( mape(fw[j, 400:], weights_model.predict(fx[j, 400:], verbose=False)) ) mape_w[columns[0]] = mse_r1 mape_y[columns[0]] = mse_r2 mape_y.to_excel(path + 'Modelfly_y.xlsx', index=False) mape_w.to_excel(path + 'Modelfly_w.xlsx', index=False) return mape_w, mape_y
[docs] def evaluate_solver( self, solver: str, MAPE_y: pd.DataFrame, MAPE_pi: pd.DataFrame ) -> Tuple[pd.DataFrame, pd.DataFrame]: """ Evaluate the solver performance and update the Mean Absolute Percentage Error (MAPE) dataframes. Parameters ---------- solver : str The name of the solver used for the optimization problem. MAPE_y : pd.DataFrame DataFrame containing MAPE values for y. MAPE_pi : pd.DataFrame DataFrame containing MAPE values for pi. Returns ------- Tuple[pd.DataFrame, pd.DataFrame] Updated MAPE dataframes for y and pi variables. """ columns = ['NN', 'Solver'] fz = np.load(path + 'FZ.npy') fz = np.nan_to_num(fz, nan=1000) fy = np.load(path + 'FY.npy') fx = np.load(path + 'FX.npy') fw = np.load(path + 'FW.npy') mape_w.drop('Solver', axis=1, inplace=True) mape_y.drop('Solver', axis=1, inplace=True) solver_names = self.solver for k in range(len(solver_names)): mse_s1 = [] mse_s2 = [] for j in range(fx.shape[0]): ys = [] for i in range(fz[0, j, 400:].shape[0]): ys.append(fx[j, 400 + i]@fz[k, j, 400 + i]) mse_s2.append(mape(fy[j, 400:], ys)) mse_s1.append(mape(fw[j, 400:], fz[k, j, 400:])) mape_w[solver_names[k]] = mse_s1 mape_y[solver_names[k]] = mse_s2 return mape_w, mape_y
[docs] def plot_results(self, path: str = '') -> None: """ Plot the Mean Absolute Percentage Error (MAPE) results obtained from the evaluations of the model and solver. Parameters ---------- path : str, optional The directory path from which the data files are to be loaded. Default is an empty string. Returns ------- None """ try: mape_y = pd.read_excel(path + 'Modelfly_y.xlsx') mape_w = pd.read_excel(path + 'Modelfly_w.xlsx') except FileNotFoundError: mape_y, mape_w = self.model_eval(path) mape_y, mape_w = self.solver_eval(mape_y, mape_w, path) fig = plt.figure(figsize=(19, 9)) gs = GridSpec(nrows=2, ncols=2) ax0 = fig.add_subplot(gs[:, 0]) ax0.set_yscale('log') ax0.set_ylabel('MAPE', fontsize=20) ax0.set_xlabel('Noise levels', fontsize=20) mape_y.boxplot(ax=ax0, boxprops=dict(color='blue'), medianprops=dict(color='orangered'), whiskerprops=dict(color='blue')) ax0.tick_params(axis='x', labelsize=20, rotation=45) ax0.tick_params(axis='y', labelsize=20) ax0.set_ylim([1e-14, 1e+16]) ax1 = fig.add_subplot(gs[:, 1]) ax1.set_yscale('log') ax1.set_ylabel('MAPE', fontsize=20) ax1.set_xlabel('Noise levels', fontsize=20) mape_w.boxplot(ax=ax1, boxprops=dict(color='blue'), medianprops=dict(color='orangered'), whiskerprops=dict(color='blue')) ax1.tick_params(axis='x', labelsize=20, rotation=45) ax1.tick_params(axis='y', labelsize=20) ax1.set_ylim([1e-22, 1e+18]) plt.show()
[docs] def history_plot_loss(self, path: str = '') -> pd.DataFrame: """ Plot the history of loss and validation loss for different loss functions. Parameters ---------- path : str, optional The directory path where the data files are to be loaded from. Defaults to an empty string. Returns ------- pd.DataFrame A DataFrame with the history of the model's loss and validation loss. """ fy = np.load(path + 'FY.npy', allow_pickle=True) fx = np.load(path + 'FX.npy', allow_pickle=True) history_loss = [] fig, axs = plt.subplots(1, 2, figsize=(20, 20)) for loss_name in ['mse', 'mae', 'huber']: model_max = self.model_op(loss = loss_name) history = model_max.fit( fx[0, 0:400], fy[0][0:400], epochs=400, batch_size=32, verbose=False, validation_split=0.3 ) history_loss = pd.DataFrame(history.history) axs[0].plot(history_loss['loss'], label=loss_name) axs[1].plot(history_loss['val_loss'], label='val_' + loss_name) axs[0].legend() axs[1].legend() axs[0].set_xlabel('Epoch') axs[0].set_ylabel('Error') axs[1].set_xlabel('Epoch') axs[1].set_ylabel('Error') plt.show() return history_loss