Skip to content

runn.models.altspec_mono_nn

warning_manager = WarningManager() module-attribute #

AltSpecMonoNN(attributes=None, n_alt=None, alt_spec_attrs=None, shared_attrs=None, socioec_attrs=None, monotonicity_constraints=None, layers_dim=[25, 25], activation='relu', regularizer=None, regularization_rate=0.001, dropout=0.0, batch_norm=False, learning_rate=0.001, optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'], filename=None, warnings=True) #

Bases: DNN

Alternative-specific monotonic neural network model for choice modeling.

PARAMETER DESCRIPTION
attributes

List with the attributes names in the model, in the same order as in the input data. If None, the model cannot be initialized unless it is loaded from a file. Default: None.

TYPE: Optional[list] DEFAULT: None

n_alt

Number of alternatives in the choice set. If None, the model cannot be initialized unless it is loaded from a file. Default: None.

TYPE: Optional[int] DEFAULT: None

alt_spec_attrs

Dictionary with the alternative-specific attributes. The keys are the index of the alternative and the values are lists with the names of the alternative-specific attributes. The alternative-specific attributes must be a subset of the attributes defined in the model. If None, the model cannot be initialized unless it is loaded from a file. Default: None.

TYPE: Optional[Dict[int, list]] DEFAULT: None

shared_attrs

List with the names of the attributes that are shared across all alternatives. The shared attributes must be a subset of the attributes defined in the model. If None, the model cannot be initialized unless it is loaded from a file. Default: None.

TYPE: Optional[list] DEFAULT: None

socioec_attrs

List with the names of the socio-economic attributes of each decision maker. The socio-economic attributes must be a subset of the attributes defined in the model. If None, the model cannot be initialized unless it is loaded from a file. Default: None.

TYPE: Optional[list] DEFAULT: None

monotonicity_constraints

Dictionary with the attributes that must be monotonic. The keys are the attribute names and the values are the monotonicity constraints. The constraints can be either an integer or a dictionary. If an integer is provided, the possible values are -1, 0 or 1, which represent decreasing, no monotonicity and increasing monotonicity, respectively. If a dictionary is provided, the keys are the index of the alternative and the values are the monotonicity constraints for the attribute in that alternative. If no monotonicity constraints are provided for an attribute, the default value is 0 (no monotonicity). If None, no monotonicity constraints will be applied. Default: None.

TYPE: Optional[Dict[str, Union[int, Dict[int, int]]]] DEFAULT: None

layers_dim

List with the number of neurons in each hidden layer, the length of the list is the number of hidden layers. Default: [25, 25].

TYPE: list DEFAULT: [25, 25]

activation

Activation function to use in the hidden layers. Can be either a string or a list of strings. See https://keras.io/api/layers/activations/ for the available activations. Default: 'relu'.

TYPE: Union[str, list] DEFAULT: 'relu'

regularizer

Type of regularization to apply. Possible values: 'l1', 'l2' or 'l1_l2'. Default: None.

TYPE: Optional[str] DEFAULT: None

regularization_rate

Regularization rate if regularizer is not None. Default: 0.001.

TYPE: float DEFAULT: 0.001

learning_rate

Learning rate of the optimizer. Default: 0.001.

TYPE: float DEFAULT: 0.001

dropout

Dropout rate to use in the hidden layers. Can be either a float or a list of floats. If a float is provided, the same dropout rate will be used in all the hidden layers. Default: 0.0.

TYPE: Union[float, list] DEFAULT: 0.0

batch_norm

Whether to use batch normalization or not. Default: False.

TYPE: bool DEFAULT: False

optimizer

Optimizer to use. Can be either a string or a tf.keras.optimizers.Optimizer. Default: 'adam'.

TYPE: Union[str, Optimizer] DEFAULT: 'adam'

loss

Loss function to use. Can be either a string or a tf.keras.losses.Loss. Default: 'categorical_crossentropy'.

TYPE: Union[str, Loss] DEFAULT: 'categorical_crossentropy'

metrics

List of metrics to be evaluated by the model during training and testing. Each of this can be either a string or a tf.keras.metrics.Metric. Default: ['accuracy'].

TYPE: list DEFAULT: ['accuracy']

filename

Load a previously trained model from a file. If None, a new model will be initialized. When loading a model from a file, the previous parameters will be ignored. Default: None.

TYPE: Optional[str] DEFAULT: None

warnings

Whether to show warnings or not. Default: True.

TYPE: bool DEFAULT: True

Source code in runn/models/altspec_mono_nn.py
def __init__(
    self,
    attributes: Optional[list] = None,
    n_alt: Optional[int] = None,
    alt_spec_attrs: Optional[Dict[int, list]] = None,
    shared_attrs: Optional[list] = None,
    socioec_attrs: Optional[list] = None,
    monotonicity_constraints: Optional[Dict[str, Union[int, Dict[int, int]]]] = None,
    layers_dim: list = [25, 25],
    activation: Union[str, list] = "relu",
    regularizer: Optional[str] = None,
    regularization_rate: float = 0.001,
    dropout: Union[float, list] = 0.0,
    batch_norm: bool = False,
    learning_rate: float = 0.001,
    optimizer: Union[str, tf.keras.optimizers.Optimizer] = "adam",
    loss: Union[str, tf.keras.losses.Loss] = "categorical_crossentropy",
    metrics: list = ["accuracy"],
    filename: Optional[str] = None,
    warnings: bool = True,
) -> None:
    # Initialize the parameters of the base class (calls the __init__ method of the BaseModel class).
    super(DNN, self).__init__(
        attributes=attributes,
        n_alt=n_alt,
        layers_dim=layers_dim,
        regularizer=regularizer,
        regularization_rate=regularization_rate,
        learning_rate=learning_rate,
        optimizer=optimizer,
        loss=loss,
        metrics=metrics,
        filename=filename,
        warnings=warnings,
    )
    if filename is None:
        self._initialize_dnn_params(activation=activation, dropout=dropout, batch_norm=batch_norm)
        self._initialize_AltSpecMonoNN_params(
            alt_spec_attrs=alt_spec_attrs,
            shared_attrs=shared_attrs,
            socioec_attrs=socioec_attrs,
            monotonicity_constraints=monotonicity_constraints,
        )
        self._build()
    self._compile()

get_utility(x, name='AltSpecMonoNN_Utility') #

Get the utility of each alternative for a given set of observations.

PARAMETER DESCRIPTION
x

The input data. It can be a tf.Tensor, np.ndarray or pd.DataFrame.

TYPE: Union[Tensor, ndarray, DataFrame]

name

Name of the utility model. Default: 'AltSpecMonoNN_Utility'.

TYPE: str DEFAULT: 'AltSpecMonoNN_Utility'

RETURNS DESCRIPTION
ndarray

Numpy array with the utility of each alternative for each observation in the input data.

Source code in runn/models/altspec_mono_nn.py
def get_utility(
    self,
    x: Union[tf.Tensor, np.ndarray, pd.DataFrame],
    name: str = "AltSpecMonoNN_Utility",
) -> np.ndarray:
    """Get the utility of each alternative for a given set of observations.

    Args:
        x: The input data. It can be a tf.Tensor, np.ndarray or pd.DataFrame.
        name: Name of the utility model. Default: 'AltSpecMonoNN_Utility'.

    Returns:
        Numpy array with the utility of each alternative for each observation in the input data.
    """
    if self.fitted is False:
        raise Exception("The model is not fitted yet. Please call the 'fit' method first.")

    if isinstance(x, pd.DataFrame):
        x = x.values
    if isinstance(x, np.ndarray):
        x = tf.convert_to_tensor(x)

    utility_model = Model(inputs=self.keras_model.input, outputs=self.keras_model.get_layer("U").output, name=name)
    return utility_model(x)

load(path) #

Load the model from a file.

PARAMETER DESCRIPTION
path

Path to the file where the model is saved.

TYPE: str

Source code in runn/models/altspec_mono_nn.py
def load(self, path: str) -> None:
    """Load the model from a file.

    Args:
        path: Path to the file where the model is saved.
    """
    if not isinstance(path, str):
        raise ValueError("The 'path' parameter should be a string.")
    # Check that the str ends with .zip
    if not path.endswith(".zip"):
        raise ValueError("The 'path' parameter should be a .zip file.")
    else:
        # Remove the .zip extension
        aux_files = path[:-4]
        # Get the last index of the '/' character
        idx = aux_files.rfind("/")
        # Get the name of the file without the path
        aux_name = aux_files[idx + 1 :]

    try:
        # Extract the files inside an temporal auxiliary folder
        os.mkdir(aux_files)
        with ZipFile(path, "r") as zip:
            zip.extractall(path=aux_files)

        # Load model info
        with open(aux_files + "/" + aux_name + "_info.json", "r") as f:
            model_info = json.load(f)
        if model_info["model"] != "AltSpecMonoNN":
            msg = (
                "The model in the file is not a 'AltSpecMonoNN' model. The model cannot be loaded.",
                "Please try using the '{}' model instead.".format(model_info["model"]),
            )
            raise ValueError(msg)

        # Check runn version
        major, minor, patch = model_info["runn_version"].split(".")
        if (
            int(major) > int(runn.__version__.split(".")[0])
            or (
                int(major) == int(runn.__version__.split(".")[0])
                and int(minor) > int(runn.__version__.split(".")[1])
            )
            or (
                int(major) == int(runn.__version__.split(".")[0])
                and int(minor) == int(runn.__version__.split(".")[1])
                and int(patch) > int(runn.__version__.split(".")[2])
            )
        ):
            msg = (
                "The model was created with a newer version of runn ({}). "
                "Please update runn to version {} or higher.".format(model_info["runn_version"], runn.__version__)
            )
            raise IncompatibleVersionError(msg)

        # Load the parameters of the model
        (
            self.attributes,
            self.n_alt,
            self.alt_spec_attrs,
            self.shared_attrs,
            self.socioec_attrs,
            self.monotonicity_constraints,
            self.layers_dim,
            self.activation,
            self.regularizer,
            self.regularization_rate,
            self.dropout,
            self.batch_norm,
            self.learning_rate,
            self.optimizer,
            self.loss,
            self.metrics,
        ) = pickle.load(open(aux_files + "/" + aux_name + "_params.pkl", "rb"))
        self._initialize_AltSpecMonoNN_params(
            alt_spec_attrs=self.alt_spec_attrs,
            shared_attrs=self.shared_attrs,
            socioec_attrs=self.socioec_attrs,
            monotonicity_constraints=self.monotonicity_constraints,
        )

        # Load the keras model
        self._build()
        self.keras_model.load_weights(aux_files + "/" + aux_name + "_model.h5")

        # Load the history
        self.history = pickle.load(open(aux_files + "/" + aux_name + "_history.pkl", "rb"))
        self.fitted = model_info["fitted"]
    except Exception as e:
        raise e
    finally:
        # Delete the auxiliary folder
        for file in os.listdir(aux_files):
            os.remove(aux_files + "/" + file)
        os.rmdir(aux_files)

save(path='model.zip') #

Save the model to a file. The model must be fitted before saving it.

PARAMETER DESCRIPTION
path

Path to the file where the model will be saved. Default: 'model.zip'.

TYPE: str DEFAULT: 'model.zip'

Source code in runn/models/altspec_mono_nn.py
def save(self, path: str = "model.zip") -> None:
    """Save the model to a file. The model must be fitted before saving it.

    Args:
        path: Path to the file where the model will be saved. Default: 'model.zip'.
    """
    if not isinstance(path, str):
        raise ValueError("The 'path' parameter should be a string.")
    if path[-4:] != ".zip":
        path += ".zip"
    aux_files = path[:-4]
    if not self.fitted or self.keras_model is None:
        msg = "The model has not been fitted yet. Please call the 'fit' method first."
        raise ValueError(msg)

    files = []
    # Save model info as json
    model_info = {
        "model": "AltSpecMonoNN",
        "runn_version": runn.__version__,
        "creation_date": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        "fitted": self.fitted,
    }
    with open(aux_files + "_info.json", "w") as f:
        json.dump(model_info, f)
    files.append(aux_files + "_info.json")

    # Save the parameters of the model
    # Save all the parameters of the model in a pickle file except the keras model
    pickle.dump(
        [
            self.attributes,
            self.n_alt,
            self.alt_spec_attrs,
            self.shared_attrs,
            self.socioec_attrs,
            self.monotonicity_constraints,
            self.layers_dim,
            self.activation,
            self.regularizer,
            self.regularization_rate,
            self.dropout,
            self.batch_norm,
            self.learning_rate,
            self.optimizer,
            self.loss,
            self.metrics,
        ],
        open(aux_files + "_params.pkl", "wb"),
    )
    files.append(aux_files + "_params.pkl")

    # Save the keras model
    self.keras_model.save_weights(aux_files + "_model.h5")
    files.append(aux_files + "_model.h5")

    # Save the history
    pickle.dump(self.history, open(aux_files + "_history.pkl", "wb"))
    files.append(aux_files + "_history.pkl")

    # Compress all the files
    with ZipFile(path, "w") as zip:
        for file in files:
            zip.write(file, os.path.basename(file))

    # Delete the auxiliary files
    for file in files:
        os.remove(file)