Skip to content

Example of use of Latent Class MNL

import os

os.environ["CUDA_VISIBLE_DEVICES"] = ""

import sys
from pathlib import Path

sys.path.append("../../")

import numpy as np
import pandas as pd

import tensorflow as tf

Let's use the Electricity Dataset used in this tutorial.

from choice_learn.datasets import load_electricity

elec_dataset = load_electricity(as_frame=False)
from choice_learn.models.simple_mnl import SimpleMNL
from choice_learn.models.latent_class_mnl import LatentClassSimpleMNL
lc_model = LatentClassSimpleMNL(n_latent_classes=3, fit_method="mle", optimizer="lbfgs", epochs=1000, tolerance=1e-20)
hist, results = lc_model.fit(elec_dataset, verbose=1)
print("Latent Class Model weights:")
print("Classes Logits:", lc_model.latent_logits)
for i in range(3):
    print("\n")
    print(f"Model Nb {i}, weights:", lc_model.models[i].weights)
nll = (lc_model.evaluate(elec_dataset) * len(elec_dataset)).numpy()
print(f"Negative Log-Likelihood: {nll}")

Latent Conditional Logit

We used a very simple MNL. Here we simulate the same MNL, by using the Conditional-Logit formulation.\ Don't hesitate to read the conditional-MNL tutorial to better understand how to use this formulation.

from choice_learn.models.latent_class_mnl import LatentClassConditionalLogit
lc_model_2 = LatentClassConditionalLogit(n_latent_classes=3,
                                       fit_method="mle",
                                       optimizer="lbfgs",
                                       epochs=1000,
                                       tolerance=1e-12)

For each feature, let's add a coefficient that is shared by all items:

lc_model_2.add_shared_coefficient(coefficient_name="pf",
                                  feature_name="pf",
                                  items_indexes=[0, 1, 2, 3])
lc_model_2.add_shared_coefficient(coefficient_name="cl",
                                  feature_name="cl",
                                    items_indexes=[0, 1, 2, 3])
lc_model_2.add_shared_coefficient(coefficient_name="loc",
                                  feature_name="loc",
                                  items_indexes=[0, 1, 2, 3])
lc_model_2.add_shared_coefficient(coefficient_name="wk",
                                feature_name="wk",
                                items_indexes=[0, 1, 2, 3])
lc_model_2.add_shared_coefficient(coefficient_name="tod",
                                  feature_name="tod",
                                  items_indexes=[0, 1, 2, 3])
lc_model_2.add_shared_coefficient(coefficient_name="seas",
                                  feature_name="seas",
                                  items_indexes=[0, 1, 2, 3])
# Fit
hist2 = lc_model_2.fit(elec_dataset, verbose=1)
print("Negative Log-Likelihood:", lc_model_2.evaluate(elec_dataset)*len(elec_dataset))
print("Latent Class Model weights:")
print("Classes Logits:", lc_model_2.latent_logits)
for i in range(3):
    print("\n")
    print(f"Model Nb {i}, weights:", lc_model_2.models[i].trainable_weights)

Just like any ChoiceModel you can get the probabilities:

lc_model.predict_probas(elec_dataset[:4])

If you want to use more complex formulations of Latent Class models, you can directly use the BaseLatentClassModel from choice_learn.models.base_model:

from choice_learn.models.latent_class_base_model import BaseLatentClassModel
manual_lc = BaseLatentClassModel(
                                 model_class=SimpleMNL,
                                 model_parameters={"add_exit_choice": False},
                                 n_latent_classes=3,
                                 fit_method="mle",
                                 epochs=1000,
                                 optimizer="lbfgs"
                                 )
manual_lc.instantiate(n_items=4,
                      n_shared_features=0,
                      n_items_features=6)
manual_hist = manual_lc.fit(elec_dataset, verbose=1)
manual_lc.evaluate(elec_dataset) * len(elec_dataset)

If you need to go deeper, you can look here to see different implementations that could help you.