Clustering of count data 🔍

Published

March 27, 2025

1 Introduction

The Poisson lognormal (PLN) model can be extended to uncover clustering structures in count data. Two main approaches are available:

  • Supervised clustering: when cluster labels are known for some samples (PlnLDA, documentation).
  • Unsupervised clustering: when cluster labels are unknown (PlnMixture, documentation).

We illustrate both using a single-cell RNA-seq dataset provided by the load_scrna function of the package. Each row represents a cell and each column a gene. Cell types are included as labels and used in the supervised setting.

2 Data Loading and Structure

from pyPLNmodels import load_scrna
rna = load_scrna(dim=20)
print("Data keys:", rna.keys())
Returning scRNA dataset of size (400, 20)
Data keys: dict_keys(['endog', 'labels', 'labels_1hot'])

2.1 Count Matrix (endog)

endog = rna["endog"]
print(endog.head())
     FTL  MALAT1   FTH1  TMSB4X   CD74  SPP1   APOE    B2M   ACTB  HLA-DRA  \
0    5.0    39.0   14.0    39.0   11.0   0.0    0.0   88.0   49.0      0.0
1    8.0    52.0   38.0   186.0   17.0   0.0    0.0  152.0  167.0      3.0
2   76.0    29.0   38.0    71.0   37.0   3.0    2.0   21.0    7.0     12.0
3  354.0   151.0  236.0   184.0  287.0   0.0  238.0  255.0   27.0    243.0
4    0.0    55.0   10.0    37.0    8.0   1.0    0.0   23.0   49.0      1.0

   APOC1  MT-CO1  TMSB10  EEF1A1  HLA-DRB1  HLA-DPA1  HLA-DPB1  MT-CO2  LYZ  \
0    0.0    29.0    22.0    34.0       0.0       0.0       1.0    21.0  0.0
1    0.0   109.0    65.0   128.0       2.0       4.0       1.0   172.0  1.0
2    3.0    46.0     7.0    11.0       0.0       7.0      17.0    16.0  0.0
3  196.0   118.0    45.0    98.0      66.0     115.0     160.0    27.0  6.0
4    0.0    11.0    25.0    10.0       1.0       2.0       2.0     6.0  0.0

   RPLP1
0   14.0
1  124.0
2   20.0
3   40.0
4   18.0  

2.2 Cell Types (labels)

cell_type = rna["labels"]
print("Cell types:", cell_type.unique())
print(cell_type.head())
print("Sample counts:", cell_type.value_counts())
Cell types: ['T_cells_CD4+' 'Macrophages' 'T_cells_CD8+']
0    T_cells_CD4+
1    T_cells_CD4+
2     Macrophages
3     Macrophages
4    T_cells_CD4+
Name: standard_true_celltype_v5, dtype: object
Sample counts: standard_true_celltype_v5
T_cells_CD8+    162
T_cells_CD4+    139
Macrophages      99
Name: count, dtype: int64

3 Supervised Clustering with PlnLDA

This method performs a Poisson lognormal discriminant analysis (PLN-LDA), similar to classical LDA but adapted to count data via a latent Gaussian layer.

3.1 Model Formulation

Let \(c_i\) denote the known cluster label for sample \(i\):

\[ \begin{align} Z_i| c_i = k &\sim \mathcal{N}(X_i^\top B + \mu_{k}, \Sigma), \\ Y_{ij} &\sim \mathcal{P}(\exp(o_{ij} + Z_{ij})) \end{align} \]

3.2 Train-Test Split

We separate the data into training and test sets. The training set is used to fit the model, while the test set is used for evaluation.

train_prop = 0.8
n_train = int(endog.shape[0] * train_prop)
endog_train, endog_test = endog[:n_train], endog[n_train:]
cell_type_train, cell_type_test = cell_type[:n_train], cell_type[n_train:]

3.3 Fitting the PLN-LDA Model

from pyPLNmodels import PlnLDA
lda = PlnLDA(endog_train, clusters=cell_type_train).fit()
print(lda)
Setting the offsets to zero.
Fitting a PlnLDA model with full covariance.
Intializing parameters ...
Initialization finished.
Maximum number of iterations (400)  reached in 5.1 seconds.
Last  criterion = 5.4e-06 . Required tolerance = 1e-06
A multivariate PlnLDA with full covariance.
======================================================================
     Loglike   Dimension    Nb param         BIC         AIC         ICL
   -17914.56          20         210  18520.2362  18124.5625      8088.1

======================================================================
* Useful attributes
    .latent_variables .latent_positions .coef .covariance .precision .model_parameters .latent_parameters .optim_details
* Useful methods
    .transform() .show() .predict() .sigma() .projected_latent_variables() .plot_correlation_circle() .biplot() .viz() .pca_pairplot() .plot_expected_vs_true()
* Additional attributes for PlnLDA are:
    .clusters .latent_positions_clusters
* Additional methods for PlnLDA are:
    .predict_clusters() .transform_new() .viz_transformed()
Upper bound on the fitting time:   0%|          | 0/400 [00:00<?, ?it/s]Upper bound on the fitting time:   4%|▍         | 16/400 [00:00<00:02, 149.84it/s]Upper bound on the fitting time:   8%|▊         | 31/400 [00:00<00:02, 142.82it/s]Upper bound on the fitting time:  12%|█▏        | 46/400 [00:00<00:02, 140.25it/s]Upper bound on the fitting time:  15%|█▌        | 61/400 [00:00<00:02, 139.95it/s]Upper bound on the fitting time:  19%|█▉        | 75/400 [00:00<00:02, 139.81it/s]Upper bound on the fitting time:  22%|██▎       | 90/400 [00:00<00:02, 140.00it/s]Upper bound on the fitting time:  26%|██▋       | 105/400 [00:00<00:02, 140.47it/s]Upper bound on the fitting time:  30%|███       | 120/400 [00:00<00:01, 140.04it/s]Upper bound on the fitting time:  34%|███▍      | 135/400 [00:00<00:01, 140.12it/s]Upper bound on the fitting time:  38%|███▊      | 150/400 [00:01<00:01, 141.21it/s]Upper bound on the fitting time:  41%|████▏     | 165/400 [00:01<00:01, 141.50it/s]Upper bound on the fitting time:  45%|████▌     | 180/400 [00:01<00:01, 140.84it/s]Upper bound on the fitting time:  49%|████▉     | 195/400 [00:01<00:01, 141.95it/s]Upper bound on the fitting time:  52%|█████▎    | 210/400 [00:01<00:01, 141.48it/s]Upper bound on the fitting time:  56%|█████▋    | 225/400 [00:01<00:01, 142.38it/s]Upper bound on the fitting time:  60%|██████    | 240/400 [00:01<00:01, 141.77it/s]Upper bound on the fitting time:  64%|██████▍   | 255/400 [00:01<00:01, 139.89it/s]Upper bound on the fitting time:  68%|██████▊   | 270/400 [00:01<00:00, 141.59it/s]Upper bound on the fitting time:  71%|███████▏  | 285/400 [00:02<00:00, 142.26it/s]Upper bound on the fitting time:  75%|███████▌  | 300/400 [00:02<00:00, 143.03it/s]Upper bound on the fitting time:  79%|███████▉  | 315/400 [00:02<00:00, 142.51it/s]Upper bound on the fitting time:  82%|████████▎ | 330/400 [00:02<00:00, 141.17it/s]Upper bound on the fitting time:  86%|████████▋ | 345/400 [00:02<00:00, 142.74it/s]Upper bound on the fitting time:  90%|█████████ | 360/400 [00:02<00:00, 143.32it/s]Upper bound on the fitting time:  94%|█████████▍| 375/400 [00:02<00:00, 143.68it/s]Upper bound on the fitting time:  98%|█████████▊| 390/400 [00:02<00:00, 142.67it/s]Upper bound on the fitting time: 100%|██████████| 400/400 [00:02<00:00, 141.64it/s]

You can also define the model using R-style formulas as follows:

data_train = {"endog_train": endog_train, "clusters_train": cell_type_train}
_ = PlnLDA.from_formula("endog_train ~ 0 | clusters_train", data=data_train)
Setting the offsets to zero.

Use a pipe | to separate the exogenous variables from the clusters. See the dedicated tutorial for more details on how to specify a model.

3.4 Predicting on Test Set

pred_test = lda.predict_clusters(endog_test)
Setting the offsets to zero.
Doing a VE step.
Done!
Setting the offsets to zero.
Doing a VE step.
Done!
Setting the offsets to zero.
Doing a VE step.
Done!
Upper bound on the fitting time:   0%|          | 0/50 [00:00<?, ?it/s]Upper bound on the fitting time:  46%|████▌     | 23/50 [00:00<00:00, 227.00it/s]Upper bound on the fitting time: 100%|██████████| 50/50 [00:00<00:00, 252.06it/s]Upper bound on the fitting time: 100%|██████████| 50/50 [00:00<00:00, 246.48it/s]
Upper bound on the fitting time:   0%|          | 0/50 [00:00<?, ?it/s]Upper bound on the fitting time:  48%|████▊     | 24/50 [00:00<00:00, 239.33it/s]Upper bound on the fitting time: 100%|██████████| 50/50 [00:00<00:00, 253.10it/s]
Upper bound on the fitting time:   0%|          | 0/50 [00:00<?, ?it/s]Upper bound on the fitting time:  48%|████▊     | 24/50 [00:00<00:00, 239.00it/s]Upper bound on the fitting time: 100%|██████████| 50/50 [00:00<00:00, 254.24it/s]
from pyPLNmodels import plot_confusion_matrix
plot_confusion_matrix(pred_test, cell_type_test)

You can enhance performance by incorporating additional variables or increasing the number of samples in your dataset.

3.5 Visualizing the Latent Space

The .transform_new() method transforms unseen endogenous data into the latent space via LDA.

lda.viz_transformed(lda.transform_new(endog_test), colors=cell_type_test)
Setting the offsets to zero.
Doing a VE step.
Done!
Setting the offsets to zero.
Doing a VE step.
Done!
Setting the offsets to zero.
Doing a VE step.
Done!
Upper bound on the fitting time:   0%|          | 0/50 [00:00<?, ?it/s]Upper bound on the fitting time:  48%|████▊     | 24/50 [00:00<00:00, 236.82it/s]Upper bound on the fitting time: 100%|██████████| 50/50 [00:00<00:00, 251.32it/s]
Upper bound on the fitting time:   0%|          | 0/50 [00:00<?, ?it/s]Upper bound on the fitting time:  48%|████▊     | 24/50 [00:00<00:00, 239.10it/s]Upper bound on the fitting time: 100%|██████████| 50/50 [00:00<00:00, 251.14it/s]
Upper bound on the fitting time:   0%|          | 0/50 [00:00<?, ?it/s]Upper bound on the fitting time:  48%|████▊     | 24/50 [00:00<00:00, 239.81it/s]Upper bound on the fitting time: 100%|██████████| 50/50 [00:00<00:00, 254.93it/s]

lda.viz_transformed(lda.transform_new(endog_train), colors=cell_type_train)
Setting the offsets to zero.
Doing a VE step.
Done!
Setting the offsets to zero.
Doing a VE step.
Done!
Setting the offsets to zero.
Doing a VE step.
Done!
Upper bound on the fitting time:   0%|          | 0/50 [00:00<?, ?it/s]Upper bound on the fitting time:  36%|███▌      | 18/50 [00:00<00:00, 175.52it/s]Upper bound on the fitting time:  72%|███████▏  | 36/50 [00:00<00:00, 164.75it/s]Upper bound on the fitting time: 100%|██████████| 50/50 [00:00<00:00, 163.14it/s]
Upper bound on the fitting time:   0%|          | 0/50 [00:00<?, ?it/s]Upper bound on the fitting time:  34%|███▍      | 17/50 [00:00<00:00, 167.57it/s]Upper bound on the fitting time:  68%|██████▊   | 34/50 [00:00<00:00, 160.04it/s]Upper bound on the fitting time: 100%|██████████| 50/50 [00:00<00:00, 158.71it/s]
Upper bound on the fitting time:   0%|          | 0/50 [00:00<?, ?it/s]Upper bound on the fitting time:  32%|███▏      | 16/50 [00:00<00:00, 152.98it/s]Upper bound on the fitting time:  64%|██████▍   | 32/50 [00:00<00:00, 154.21it/s]Upper bound on the fitting time:  96%|█████████▌| 48/50 [00:00<00:00, 156.66it/s]Upper bound on the fitting time: 100%|██████████| 50/50 [00:00<00:00, 154.42it/s]

3.5.1 Optional: Exogenous Variables

You can include exogenous variables in the model; however, they will not be used for making predictions. When predicting on new data, ensure that the corresponding covariates for the samples are provided.

import torch
dumb_lda = PlnLDA(endog_train, exog=torch.randn(endog_train.shape[0], 2), clusters=cell_type_train).fit()
_ = dumb_lda.predict_clusters(endog_test, exog=torch.randn(endog_test.shape[0], 2))
Setting the offsets to zero.
Fitting a PlnLDA model with full covariance.
Intializing parameters ...
Initialization finished.
Maximum number of iterations (400)  reached in 3.1 seconds.
Last  criterion = 5.4e-06 . Required tolerance = 1e-06
Setting the offsets to zero.
Doing a VE step.
Done!
Setting the offsets to zero.
Doing a VE step.
Done!
Setting the offsets to zero.
Doing a VE step.
Done!
Upper bound on the fitting time:   0%|          | 0/400 [00:00<?, ?it/s]Upper bound on the fitting time:   4%|▍         | 16/400 [00:00<00:02, 153.49it/s]Upper bound on the fitting time:   8%|▊         | 32/400 [00:00<00:02, 144.53it/s]Upper bound on the fitting time:  12%|█▏        | 47/400 [00:00<00:02, 142.45it/s]Upper bound on the fitting time:  16%|█▌        | 62/400 [00:00<00:02, 143.26it/s]Upper bound on the fitting time:  19%|█▉        | 77/400 [00:00<00:02, 144.01it/s]Upper bound on the fitting time:  23%|██▎       | 92/400 [00:00<00:02, 144.73it/s]Upper bound on the fitting time:  27%|██▋       | 107/400 [00:00<00:02, 142.55it/s]Upper bound on the fitting time:  30%|███       | 122/400 [00:00<00:01, 142.42it/s]Upper bound on the fitting time:  34%|███▍      | 137/400 [00:00<00:01, 142.61it/s]Upper bound on the fitting time:  38%|███▊      | 152/400 [00:01<00:01, 141.40it/s]Upper bound on the fitting time:  42%|████▏     | 167/400 [00:01<00:01, 139.42it/s]Upper bound on the fitting time:  45%|████▌     | 181/400 [00:01<00:01, 139.55it/s]Upper bound on the fitting time:  49%|████▉     | 196/400 [00:01<00:01, 140.32it/s]Upper bound on the fitting time:  53%|█████▎    | 211/400 [00:01<00:01, 117.56it/s]Upper bound on the fitting time:  56%|█████▌    | 224/400 [00:01<00:01, 114.71it/s]Upper bound on the fitting time:  59%|█████▉    | 236/400 [00:01<00:01, 111.61it/s]Upper bound on the fitting time:  62%|██████▏   | 249/400 [00:01<00:01, 116.36it/s]Upper bound on the fitting time:  66%|██████▌   | 262/400 [00:01<00:01, 118.59it/s]Upper bound on the fitting time:  69%|██████▉   | 275/400 [00:02<00:01, 120.66it/s]Upper bound on the fitting time:  72%|███████▏  | 288/400 [00:02<00:00, 119.41it/s]Upper bound on the fitting time:  75%|███████▌  | 301/400 [00:02<00:00, 121.88it/s]Upper bound on the fitting time:  79%|███████▉  | 315/400 [00:02<00:00, 125.03it/s]Upper bound on the fitting time:  82%|████████▏ | 328/400 [00:02<00:00, 125.42it/s]Upper bound on the fitting time:  86%|████████▌ | 342/400 [00:02<00:00, 127.08it/s]Upper bound on the fitting time:  89%|████████▉ | 356/400 [00:02<00:00, 128.32it/s]Upper bound on the fitting time:  92%|█████████▏| 369/400 [00:02<00:00, 127.73it/s]Upper bound on the fitting time:  96%|█████████▌| 382/400 [00:02<00:00, 120.51it/s]Upper bound on the fitting time:  99%|█████████▉| 395/400 [00:03<00:00, 120.38it/s]Upper bound on the fitting time: 100%|██████████| 400/400 [00:03<00:00, 128.04it/s]
Upper bound on the fitting time:   0%|          | 0/50 [00:00<?, ?it/s]Upper bound on the fitting time:  34%|███▍      | 17/50 [00:00<00:00, 164.47it/s]Upper bound on the fitting time:  70%|███████   | 35/50 [00:00<00:00, 173.14it/s]Upper bound on the fitting time: 100%|██████████| 50/50 [00:00<00:00, 166.62it/s]
Upper bound on the fitting time:   0%|          | 0/50 [00:00<?, ?it/s]Upper bound on the fitting time:  34%|███▍      | 17/50 [00:00<00:00, 168.85it/s]Upper bound on the fitting time:  68%|██████▊   | 34/50 [00:00<00:00, 167.52it/s]Upper bound on the fitting time: 100%|██████████| 50/50 [00:00<00:00, 168.85it/s]
Upper bound on the fitting time:   0%|          | 0/50 [00:00<?, ?it/s]Upper bound on the fitting time:  36%|███▌      | 18/50 [00:00<00:00, 175.03it/s]Upper bound on the fitting time:  72%|███████▏  | 36/50 [00:00<00:00, 163.42it/s]Upper bound on the fitting time: 100%|██████████| 50/50 [00:00<00:00, 166.40it/s]

⚠️ Exogenous variables must be full rank, and an intercept will be added to account for the cluster bias.. Avoid one-hot encodings without intercept removal.

4 Unsupervised Clustering with PlnMixture

When no labels are known, PlnMixture fits a latent mixture model to identify subpopulations in an unsupervised way.

4.1 Model Formulation

\[ \begin{align} c_i &\sim \mathcal{M}(1, \pi), \\ Z_i \mid c_i=k &\sim \mathcal{N}(X_i^\top B + \mu_k, \Sigma_k), \\ Y_{ij} &\sim \mathcal{P}(\exp(o_{ij} + Z_{ij})) \end{align} \]

Covariance matrices \(\Sigma_k\) are assumed diagonal.

4.2 Model Fitting

from pyPLNmodels import PlnMixture
mixture = PlnMixture(endog, n_cluster=3).fit()
print(mixture)
Setting the offsets to zero.
Fitting a PlnMixture model with diagonal covariances and 3 clusters.
Intialization ...
Fitting a PlnDiag model with full covariance.
Intializing parameters ...
Initialization finished.
Maximum number of iterations (150)  reached in 1.1 seconds.
Last  criterion = 0.01074308 . Required tolerance = 1e-06
Finished!
Maximum number of iterations (400)  reached in 7.9 seconds.
Last  criterion = 5.37e-06 . Required tolerance = 1e-06
A multivariate PlnMixture with diagonal covariances and 3 clusters.
======================================================================
     Loglike   Dimension    Nb param         BIC         AIC         ICL  Silhouette
   -24320.81          20         120   24680.294  24440.8062    11699.42  0.42445526

======================================================================
* Useful attributes
    .latent_variables .latent_positions .coef .covariance .precision .model_parameters .latent_parameters .optim_details
* Useful methods
    .transform() .show() .predict() .sigma() .projected_latent_variables() .plot_correlation_circle() .biplot() .viz() .pca_pairplot() .plot_expected_vs_true()
* Additional attributes for PlnMixture are:
    .covariances .cluster_bias .latent_prob .n_cluster .weights
* Additional methods for PlnMixture are:
    .predict_clusters()
Upper bound on the fitting time:   0%|          | 0/150 [00:00<?, ?it/s]Upper bound on the fitting time:  10%|█         | 15/150 [00:00<00:00, 148.57it/s]Upper bound on the fitting time:  20%|██        | 30/150 [00:00<00:00, 143.86it/s]Upper bound on the fitting time:  30%|███       | 45/150 [00:00<00:00, 140.68it/s]Upper bound on the fitting time:  40%|████      | 60/150 [00:00<00:00, 137.21it/s]Upper bound on the fitting time:  49%|████▉     | 74/150 [00:00<00:00, 137.09it/s]Upper bound on the fitting time:  59%|█████▊    | 88/150 [00:00<00:00, 134.97it/s]Upper bound on the fitting time:  68%|██████▊   | 102/150 [00:00<00:00, 133.99it/s]Upper bound on the fitting time:  77%|███████▋  | 116/150 [00:00<00:00, 133.94it/s]Upper bound on the fitting time:  87%|████████▋ | 130/150 [00:00<00:00, 133.65it/s]Upper bound on the fitting time:  96%|█████████▌| 144/150 [00:01<00:00, 131.89it/s]Upper bound on the fitting time: 100%|██████████| 150/150 [00:01<00:00, 134.88it/s]
Upper bound on the fitting time:   0%|          | 0/400 [00:00<?, ?it/s]Upper bound on the fitting time:   2%|▏         | 7/400 [00:00<00:06, 63.03it/s]Upper bound on the fitting time:   4%|▎         | 14/400 [00:00<00:07, 54.87it/s]Upper bound on the fitting time:   5%|▌         | 21/400 [00:00<00:06, 57.55it/s]Upper bound on the fitting time:   7%|▋         | 27/400 [00:00<00:06, 53.73it/s]Upper bound on the fitting time:   8%|▊         | 34/400 [00:00<00:06, 56.73it/s]Upper bound on the fitting time:  10%|█         | 40/400 [00:00<00:06, 53.46it/s]Upper bound on the fitting time:  12%|█▏        | 46/400 [00:00<00:06, 55.24it/s]Upper bound on the fitting time:  13%|█▎        | 52/400 [00:00<00:06, 56.47it/s]Upper bound on the fitting time:  14%|█▍        | 58/400 [00:01<00:06, 54.06it/s]Upper bound on the fitting time:  16%|█▌        | 64/400 [00:01<00:06, 55.63it/s]Upper bound on the fitting time:  18%|█▊        | 70/400 [00:01<00:06, 53.45it/s]Upper bound on the fitting time:  19%|█▉        | 76/400 [00:01<00:06, 51.78it/s]Upper bound on the fitting time:  20%|██        | 82/400 [00:01<00:06, 50.88it/s]Upper bound on the fitting time:  22%|██▏       | 89/400 [00:01<00:05, 53.90it/s]Upper bound on the fitting time:  24%|██▍       | 95/400 [00:01<00:05, 51.75it/s]Upper bound on the fitting time:  25%|██▌       | 101/400 [00:01<00:05, 51.00it/s]Upper bound on the fitting time:  27%|██▋       | 107/400 [00:02<00:05, 50.88it/s]Upper bound on the fitting time:  28%|██▊       | 113/400 [00:02<00:05, 52.09it/s]Upper bound on the fitting time:  30%|███       | 120/400 [00:02<00:05, 55.61it/s]Upper bound on the fitting time:  32%|███▏      | 126/400 [00:02<00:04, 55.30it/s]Upper bound on the fitting time:  33%|███▎      | 133/400 [00:02<00:04, 56.93it/s]Upper bound on the fitting time:  35%|███▌      | 140/400 [00:02<00:04, 58.12it/s]Upper bound on the fitting time:  37%|███▋      | 147/400 [00:02<00:04, 59.19it/s]Upper bound on the fitting time:  38%|███▊      | 154/400 [00:02<00:04, 59.96it/s]Upper bound on the fitting time:  40%|████      | 161/400 [00:02<00:04, 56.11it/s]Upper bound on the fitting time:  42%|████▏     | 167/400 [00:03<00:04, 56.20it/s]Upper bound on the fitting time:  44%|████▎     | 174/400 [00:03<00:03, 57.99it/s]Upper bound on the fitting time:  45%|████▌     | 181/400 [00:03<00:03, 60.72it/s]Upper bound on the fitting time:  47%|████▋     | 188/400 [00:03<00:03, 62.82it/s]Upper bound on the fitting time:  49%|████▉     | 195/400 [00:03<00:03, 63.23it/s]Upper bound on the fitting time:  50%|█████     | 202/400 [00:03<00:03, 64.62it/s]Upper bound on the fitting time:  52%|█████▏    | 209/400 [00:03<00:02, 65.68it/s]Upper bound on the fitting time:  54%|█████▍    | 216/400 [00:03<00:02, 66.51it/s]Upper bound on the fitting time:  56%|█████▌    | 223/400 [00:03<00:02, 66.57it/s]Upper bound on the fitting time:  57%|█████▊    | 230/400 [00:03<00:02, 66.64it/s]Upper bound on the fitting time:  59%|█████▉    | 237/400 [00:04<00:02, 67.06it/s]Upper bound on the fitting time:  61%|██████    | 244/400 [00:04<00:02, 67.31it/s]Upper bound on the fitting time:  63%|██████▎   | 251/400 [00:04<00:02, 67.61it/s]Upper bound on the fitting time:  64%|██████▍   | 258/400 [00:04<00:02, 67.69it/s]Upper bound on the fitting time:  66%|██████▋   | 265/400 [00:04<00:01, 67.92it/s]Upper bound on the fitting time:  68%|██████▊   | 272/400 [00:04<00:01, 67.61it/s]Upper bound on the fitting time:  70%|██████▉   | 279/400 [00:04<00:01, 67.54it/s]Upper bound on the fitting time:  72%|███████▏  | 286/400 [00:04<00:01, 66.82it/s]Upper bound on the fitting time:  73%|███████▎  | 293/400 [00:04<00:01, 66.59it/s]Upper bound on the fitting time:  75%|███████▌  | 300/400 [00:05<00:01, 67.13it/s]Upper bound on the fitting time:  77%|███████▋  | 307/400 [00:05<00:01, 66.98it/s]Upper bound on the fitting time:  78%|███████▊  | 314/400 [00:05<00:01, 66.18it/s]Upper bound on the fitting time:  80%|████████  | 321/400 [00:05<00:01, 66.16it/s]Upper bound on the fitting time:  82%|████████▏ | 328/400 [00:05<00:01, 65.70it/s]Upper bound on the fitting time:  84%|████████▍ | 335/400 [00:05<00:00, 66.09it/s]Upper bound on the fitting time:  86%|████████▌ | 342/400 [00:05<00:00, 62.16it/s]Upper bound on the fitting time:  87%|████████▋ | 349/400 [00:05<00:00, 60.22it/s]Upper bound on the fitting time:  89%|████████▉ | 356/400 [00:05<00:00, 59.65it/s]Upper bound on the fitting time:  91%|█████████ | 363/400 [00:06<00:00, 60.44it/s]Upper bound on the fitting time:  92%|█████████▎| 370/400 [00:06<00:00, 59.52it/s]Upper bound on the fitting time:  94%|█████████▍| 376/400 [00:06<00:00, 58.72it/s]Upper bound on the fitting time:  96%|█████████▌| 383/400 [00:06<00:00, 59.67it/s]Upper bound on the fitting time:  98%|█████████▊| 390/400 [00:06<00:00, 60.25it/s]Upper bound on the fitting time:  99%|█████████▉| 397/400 [00:06<00:00, 62.28it/s]Upper bound on the fitting time: 100%|██████████| 400/400 [00:06<00:00, 60.22it/s]

4.2.1 Optional: With Covariates

_ = PlnMixture(endog, exog=torch.randn(endog.shape[0], 2), n_cluster=3)
Setting the offsets to zero.

⚠️ exogenous variables must be full rank, and an intercept will be added to account for the cluster bias. Avoid one-hot encodings without intercept removal.

4.2.2 Extracting Weights

print(mixture.weights)
tensor([0.5004, 0.2524, 0.2472], dtype=torch.float64)

4.3 Visualizing and Evaluating Clusters

One can access the clusters of the samples using the .clusters attribute:

clusters = mixture.clusters

Some useful visualization and information about clusters are displayed using the .show() method:

mixture.show()

One can visualize the latent variables using the .viz() method. By default, the latent variables are colored by the inferred clusters, but other colors can be specified using the colors argument.

mixture.viz()

You can compare the inferred clusters with the actual cell types, although retrieving the exact cell types is not expected since the method is unsupervised.

To visualize the clustering results, use the following:

mixture.viz(colors=cell_type)

You can also assess the clustering performance with a confusion matrix:

plot_confusion_matrix(clusters, cell_type)

4.4 Predicting on New Data

You can predict unseen data using the .predict_clusters() method.

new_clusters = mixture.predict_clusters(endog)
Setting the offsets to zero.
Doing a VE step.
Intialization ...
Fitting a PlnDiag model with full covariance.
Intializing parameters ...
Initialization finished.
Maximum number of iterations (150)  reached in 0.9 seconds.
Last  criterion = 0.01074308 . Required tolerance = 1e-06
Finished!
Done!
Upper bound on the fitting time:   0%|          | 0/150 [00:00<?, ?it/s]Upper bound on the fitting time:  12%|█▏        | 18/150 [00:00<00:00, 173.63it/s]Upper bound on the fitting time:  24%|██▍       | 36/150 [00:00<00:00, 161.42it/s]Upper bound on the fitting time:  35%|███▌      | 53/150 [00:00<00:00, 158.89it/s]Upper bound on the fitting time:  46%|████▌     | 69/150 [00:00<00:00, 158.62it/s]Upper bound on the fitting time:  57%|█████▋    | 86/150 [00:00<00:00, 159.27it/s]Upper bound on the fitting time:  69%|██████▊   | 103/150 [00:00<00:00, 161.42it/s]Upper bound on the fitting time:  80%|████████  | 120/150 [00:00<00:00, 163.95it/s]Upper bound on the fitting time:  91%|█████████▏| 137/150 [00:00<00:00, 164.91it/s]Upper bound on the fitting time: 100%|██████████| 150/150 [00:00<00:00, 162.84it/s]
Upper bound on the fitting time:   0%|          | 0/30 [00:00<?, ?it/s]Upper bound on the fitting time:  33%|███▎      | 10/30 [00:00<00:00, 94.00it/s]Upper bound on the fitting time:  67%|██████▋   | 20/30 [00:00<00:00, 89.72it/s]Upper bound on the fitting time:  97%|█████████▋| 29/30 [00:00<00:00, 86.96it/s]Upper bound on the fitting time: 100%|██████████| 30/30 [00:00<00:00, 86.93it/s]

The number of clusters has been arbitrary set to \(3\). A more data-driven approach is given by the PlnMixtureCollection in the next section.

4.5 Use PlnMixtureCollection for selecting the optimal number of clusters

To explore multiple cluster solutions, use PlnMixtureCollection:

from pyPLNmodels import PlnMixtureCollection
collection = PlnMixtureCollection(endog, n_clusters=range(2, 8)).fit()
Setting the offsets to zero.
Adjusting 6 PlnMixture models.

Fitting a PlnMixture model with diagonal covariances and 2 clusters.
Intialization ...
Fitting a PlnDiag model with full covariance.
Intializing parameters ...
Initialization finished.
Maximum number of iterations (150)  reached in 1.1 seconds.
Last  criterion = 0.01074308 . Required tolerance = 1e-06
Finished!
Maximum number of iterations (400)  reached in 6.8 seconds.
Last  criterion = 5.36e-06 . Required tolerance = 1e-06
Fitting a PlnMixture model with diagonal covariances and 3 clusters.
Intialization ...
Fitting a PlnDiag model with full covariance.
Intializing parameters ...
Initialization finished.
Maximum number of iterations (150)  reached in 1.2 seconds.
Last  criterion = 0.01074308 . Required tolerance = 1e-06
Finished!
Maximum number of iterations (400)  reached in 7.7 seconds.
Last  criterion = 5.37e-06 . Required tolerance = 1e-06
Fitting a PlnMixture model with diagonal covariances and 4 clusters.
Intialization ...
Fitting a PlnDiag model with full covariance.
Intializing parameters ...
Initialization finished.
Maximum number of iterations (150)  reached in 1.0 seconds.
Last  criterion = 0.01074308 . Required tolerance = 1e-06
Finished!
Maximum number of iterations (400)  reached in 7.9 seconds.
Last  criterion = 5.37e-06 . Required tolerance = 1e-06
Fitting a PlnMixture model with diagonal covariances and 5 clusters.
Intialization ...
Fitting a PlnDiag model with full covariance.
Intializing parameters ...
Initialization finished.
Maximum number of iterations (150)  reached in 1.0 seconds.
Last  criterion = 0.01074308 . Required tolerance = 1e-06
Finished!
Maximum number of iterations (400)  reached in 7.7 seconds.
Last  criterion = 5.37e-06 . Required tolerance = 1e-06
Fitting a PlnMixture model with diagonal covariances and 6 clusters.
Intialization ...
Fitting a PlnDiag model with full covariance.
Intializing parameters ...
Initialization finished.
Maximum number of iterations (150)  reached in 1.0 seconds.
Last  criterion = 0.01074308 . Required tolerance = 1e-06
Finished!
Maximum number of iterations (400)  reached in 7.8 seconds.
Last  criterion = 5.37e-06 . Required tolerance = 1e-06
Fitting a PlnMixture model with diagonal covariances and 7 clusters.
Intialization ...
Fitting a PlnDiag model with full covariance.
Intializing parameters ...
Initialization finished.
Maximum number of iterations (150)  reached in 1.0 seconds.
Last  criterion = 0.01074308 . Required tolerance = 1e-06
Finished!
Maximum number of iterations (400)  reached in 8.6 seconds.
Last  criterion = 5.37e-06 . Required tolerance = 1e-06
======================================================================

DONE!
Best model (lower BIC): n_cluster 7
    Best model(lower AIC): n_cluster  7

======================================================================
Upper bound on the fitting time:   0%|          | 0/150 [00:00<?, ?it/s]Upper bound on the fitting time:  11%|█▏        | 17/150 [00:00<00:00, 162.39it/s]Upper bound on the fitting time:  23%|██▎       | 34/150 [00:00<00:00, 154.52it/s]Upper bound on the fitting time:  33%|███▎      | 50/150 [00:00<00:00, 150.40it/s]Upper bound on the fitting time:  44%|████▍     | 66/150 [00:00<00:00, 152.47it/s]Upper bound on the fitting time:  55%|█████▍    | 82/150 [00:00<00:00, 149.67it/s]Upper bound on the fitting time:  65%|██████▍   | 97/150 [00:00<00:00, 135.74it/s]Upper bound on the fitting time:  74%|███████▍  | 111/150 [00:00<00:00, 136.05it/s]Upper bound on the fitting time:  83%|████████▎ | 125/150 [00:00<00:00, 135.74it/s]Upper bound on the fitting time:  93%|█████████▎| 139/150 [00:00<00:00, 134.61it/s]Upper bound on the fitting time: 100%|██████████| 150/150 [00:01<00:00, 140.35it/s]
Upper bound on the fitting time:   0%|          | 0/400 [00:00<?, ?it/s]Upper bound on the fitting time:   2%|▏         | 8/400 [00:00<00:05, 72.12it/s]Upper bound on the fitting time:   4%|▍         | 16/400 [00:00<00:05, 71.00it/s]Upper bound on the fitting time:   6%|▌         | 24/400 [00:00<00:05, 69.76it/s]Upper bound on the fitting time:   8%|▊         | 31/400 [00:00<00:05, 66.83it/s]Upper bound on the fitting time:  10%|▉         | 38/400 [00:00<00:05, 62.89it/s]Upper bound on the fitting time:  11%|█▏        | 45/400 [00:00<00:05, 62.09it/s]Upper bound on the fitting time:  13%|█▎        | 52/400 [00:00<00:05, 61.23it/s]Upper bound on the fitting time:  15%|█▍        | 59/400 [00:00<00:05, 62.70it/s]Upper bound on the fitting time:  17%|█▋        | 67/400 [00:01<00:05, 65.69it/s]Upper bound on the fitting time:  19%|█▉        | 75/400 [00:01<00:04, 68.18it/s]Upper bound on the fitting time:  20%|██        | 82/400 [00:01<00:04, 67.49it/s]Upper bound on the fitting time:  22%|██▎       | 90/400 [00:01<00:04, 70.70it/s]Upper bound on the fitting time:  25%|██▍       | 99/400 [00:01<00:04, 74.28it/s]Upper bound on the fitting time:  27%|██▋       | 107/400 [00:01<00:03, 74.03it/s]Upper bound on the fitting time:  29%|██▉       | 115/400 [00:01<00:03, 75.40it/s]Upper bound on the fitting time:  31%|███       | 124/400 [00:01<00:03, 77.14it/s]Upper bound on the fitting time:  33%|███▎      | 132/400 [00:01<00:03, 76.62it/s]Upper bound on the fitting time:  35%|███▌      | 140/400 [00:01<00:03, 76.56it/s]Upper bound on the fitting time:  37%|███▋      | 148/400 [00:02<00:03, 77.06it/s]Upper bound on the fitting time:  39%|███▉      | 156/400 [00:02<00:03, 76.93it/s]Upper bound on the fitting time:  41%|████      | 164/400 [00:02<00:03, 77.10it/s]Upper bound on the fitting time:  43%|████▎     | 172/400 [00:02<00:02, 77.53it/s]Upper bound on the fitting time:  45%|████▌     | 180/400 [00:02<00:02, 76.82it/s]Upper bound on the fitting time:  47%|████▋     | 188/400 [00:02<00:02, 76.12it/s]Upper bound on the fitting time:  49%|████▉     | 196/400 [00:02<00:02, 77.11it/s]Upper bound on the fitting time:  51%|█████     | 204/400 [00:02<00:02, 77.08it/s]Upper bound on the fitting time:  53%|█████▎    | 212/400 [00:02<00:02, 76.23it/s]Upper bound on the fitting time:  55%|█████▌    | 220/400 [00:03<00:02, 75.66it/s]Upper bound on the fitting time:  57%|█████▋    | 228/400 [00:03<00:02, 75.55it/s]Upper bound on the fitting time:  59%|█████▉    | 236/400 [00:03<00:02, 74.89it/s]Upper bound on the fitting time:  61%|██████    | 244/400 [00:03<00:02, 74.88it/s]Upper bound on the fitting time:  63%|██████▎   | 252/400 [00:03<00:01, 76.12it/s]Upper bound on the fitting time:  65%|██████▌   | 260/400 [00:03<00:01, 76.96it/s]Upper bound on the fitting time:  67%|██████▋   | 268/400 [00:03<00:01, 77.82it/s]Upper bound on the fitting time:  69%|██████▉   | 276/400 [00:03<00:01, 76.66it/s]Upper bound on the fitting time:  71%|███████   | 284/400 [00:03<00:01, 70.51it/s]Upper bound on the fitting time:  73%|███████▎  | 292/400 [00:04<00:01, 64.84it/s]Upper bound on the fitting time:  75%|███████▍  | 299/400 [00:04<00:01, 61.15it/s]Upper bound on the fitting time:  76%|███████▋  | 306/400 [00:04<00:01, 60.59it/s]Upper bound on the fitting time:  78%|███████▊  | 313/400 [00:04<00:01, 60.95it/s]Upper bound on the fitting time:  80%|████████  | 320/400 [00:04<00:01, 63.13it/s]Upper bound on the fitting time:  82%|████████▏ | 328/400 [00:04<00:01, 66.74it/s]Upper bound on the fitting time:  84%|████████▍ | 336/400 [00:04<00:00, 69.23it/s]Upper bound on the fitting time:  86%|████████▌ | 344/400 [00:04<00:00, 69.71it/s]Upper bound on the fitting time:  88%|████████▊ | 352/400 [00:04<00:00, 69.51it/s]Upper bound on the fitting time:  90%|████████▉ | 359/400 [00:05<00:00, 69.23it/s]Upper bound on the fitting time:  92%|█████████▏| 366/400 [00:05<00:00, 68.86it/s]Upper bound on the fitting time:  93%|█████████▎| 373/400 [00:05<00:00, 66.38it/s]Upper bound on the fitting time:  95%|█████████▌| 381/400 [00:05<00:00, 68.15it/s]Upper bound on the fitting time:  97%|█████████▋| 389/400 [00:05<00:00, 69.41it/s]Upper bound on the fitting time:  99%|█████████▉| 397/400 [00:05<00:00, 69.90it/s]Upper bound on the fitting time: 100%|██████████| 400/400 [00:05<00:00, 70.82it/s]
Upper bound on the fitting time:   0%|          | 0/150 [00:00<?, ?it/s]Upper bound on the fitting time:   9%|▊         | 13/150 [00:00<00:01, 129.09it/s]Upper bound on the fitting time:  17%|█▋        | 26/150 [00:00<00:00, 126.37it/s]Upper bound on the fitting time:  26%|██▌       | 39/150 [00:00<00:00, 126.16it/s]Upper bound on the fitting time:  35%|███▍      | 52/150 [00:00<00:00, 126.06it/s]Upper bound on the fitting time:  43%|████▎     | 65/150 [00:00<00:00, 127.14it/s]Upper bound on the fitting time:  53%|█████▎    | 79/150 [00:00<00:00, 128.81it/s]Upper bound on the fitting time:  62%|██████▏   | 93/150 [00:00<00:00, 131.52it/s]Upper bound on the fitting time:  71%|███████▏  | 107/150 [00:00<00:00, 127.00it/s]Upper bound on the fitting time:  80%|████████  | 120/150 [00:00<00:00, 126.44it/s]Upper bound on the fitting time:  89%|████████▊ | 133/150 [00:01<00:00, 126.04it/s]Upper bound on the fitting time:  97%|█████████▋| 146/150 [00:01<00:00, 117.56it/s]Upper bound on the fitting time: 100%|██████████| 150/150 [00:01<00:00, 123.25it/s]
Upper bound on the fitting time:   0%|          | 0/400 [00:00<?, ?it/s]Upper bound on the fitting time:   2%|▏         | 6/400 [00:00<00:07, 53.70it/s]Upper bound on the fitting time:   3%|▎         | 12/400 [00:00<00:06, 56.95it/s]Upper bound on the fitting time:   4%|▍         | 18/400 [00:00<00:06, 57.51it/s]Upper bound on the fitting time:   6%|▌         | 24/400 [00:00<00:06, 57.36it/s]Upper bound on the fitting time:   8%|▊         | 30/400 [00:00<00:06, 53.68it/s]Upper bound on the fitting time:   9%|▉         | 36/400 [00:00<00:07, 51.79it/s]Upper bound on the fitting time:  10%|█         | 42/400 [00:00<00:07, 50.90it/s]Upper bound on the fitting time:  12%|█▏        | 48/400 [00:00<00:07, 50.23it/s]Upper bound on the fitting time:  14%|█▎        | 54/400 [00:01<00:07, 48.73it/s]Upper bound on the fitting time:  15%|█▍        | 59/400 [00:01<00:06, 48.98it/s]Upper bound on the fitting time:  16%|█▋        | 66/400 [00:01<00:06, 53.46it/s]Upper bound on the fitting time:  18%|█▊        | 73/400 [00:01<00:05, 56.09it/s]Upper bound on the fitting time:  20%|██        | 80/400 [00:01<00:05, 57.65it/s]Upper bound on the fitting time:  22%|██▏       | 87/400 [00:01<00:05, 59.27it/s]Upper bound on the fitting time:  24%|██▎       | 94/400 [00:01<00:05, 60.08it/s]Upper bound on the fitting time:  25%|██▌       | 101/400 [00:01<00:05, 58.17it/s]Upper bound on the fitting time:  27%|██▋       | 107/400 [00:01<00:05, 57.90it/s]Upper bound on the fitting time:  28%|██▊       | 113/400 [00:02<00:04, 57.43it/s]Upper bound on the fitting time:  30%|███       | 120/400 [00:02<00:04, 58.48it/s]Upper bound on the fitting time:  32%|███▏      | 127/400 [00:02<00:04, 61.26it/s]Upper bound on the fitting time:  34%|███▎      | 134/400 [00:02<00:04, 63.05it/s]Upper bound on the fitting time:  36%|███▌      | 142/400 [00:02<00:03, 65.81it/s]Upper bound on the fitting time:  38%|███▊      | 150/400 [00:02<00:03, 67.80it/s]Upper bound on the fitting time:  40%|███▉      | 158/400 [00:02<00:03, 69.35it/s]Upper bound on the fitting time:  42%|████▏     | 166/400 [00:02<00:03, 70.70it/s]Upper bound on the fitting time:  44%|████▎     | 174/400 [00:02<00:03, 71.83it/s]Upper bound on the fitting time:  46%|████▌     | 182/400 [00:03<00:03, 72.05it/s]Upper bound on the fitting time:  48%|████▊     | 190/400 [00:03<00:02, 72.55it/s]Upper bound on the fitting time:  50%|████▉     | 198/400 [00:03<00:02, 72.78it/s]Upper bound on the fitting time:  52%|█████▏    | 206/400 [00:03<00:02, 73.18it/s]Upper bound on the fitting time:  54%|█████▎    | 214/400 [00:03<00:02, 72.85it/s]Upper bound on the fitting time:  56%|█████▌    | 222/400 [00:03<00:02, 72.97it/s]Upper bound on the fitting time:  57%|█████▊    | 230/400 [00:03<00:02, 73.35it/s]Upper bound on the fitting time:  60%|█████▉    | 238/400 [00:03<00:02, 73.23it/s]Upper bound on the fitting time:  62%|██████▏   | 246/400 [00:03<00:02, 73.36it/s]Upper bound on the fitting time:  64%|██████▎   | 254/400 [00:04<00:01, 73.38it/s]Upper bound on the fitting time:  66%|██████▌   | 262/400 [00:04<00:01, 73.50it/s]Upper bound on the fitting time:  68%|██████▊   | 270/400 [00:04<00:01, 72.77it/s]Upper bound on the fitting time:  70%|██████▉   | 278/400 [00:04<00:01, 72.78it/s]Upper bound on the fitting time:  72%|███████▏  | 286/400 [00:04<00:01, 72.91it/s]Upper bound on the fitting time:  74%|███████▎  | 294/400 [00:04<00:01, 67.25it/s]Upper bound on the fitting time:  75%|███████▌  | 301/400 [00:04<00:01, 63.21it/s]Upper bound on the fitting time:  77%|███████▋  | 308/400 [00:04<00:01, 58.71it/s]Upper bound on the fitting time:  78%|███████▊  | 314/400 [00:04<00:01, 57.53it/s]Upper bound on the fitting time:  80%|████████  | 321/400 [00:05<00:01, 58.56it/s]Upper bound on the fitting time:  82%|████████▏ | 327/400 [00:05<00:01, 58.67it/s]Upper bound on the fitting time:  83%|████████▎ | 333/400 [00:05<00:01, 58.36it/s]Upper bound on the fitting time:  85%|████████▍ | 339/400 [00:05<00:01, 57.96it/s]Upper bound on the fitting time:  86%|████████▋ | 345/400 [00:05<00:00, 56.09it/s]Upper bound on the fitting time:  88%|████████▊ | 352/400 [00:05<00:00, 57.98it/s]Upper bound on the fitting time:  90%|████████▉ | 358/400 [00:05<00:00, 57.85it/s]Upper bound on the fitting time:  91%|█████████ | 364/400 [00:05<00:00, 58.06it/s]Upper bound on the fitting time:  93%|█████████▎| 371/400 [00:05<00:00, 59.38it/s]Upper bound on the fitting time:  94%|█████████▍| 378/400 [00:06<00:00, 61.04it/s]Upper bound on the fitting time:  96%|█████████▋| 385/400 [00:06<00:00, 62.74it/s]Upper bound on the fitting time:  98%|█████████▊| 392/400 [00:06<00:00, 62.86it/s]Upper bound on the fitting time: 100%|██████████| 400/400 [00:06<00:00, 66.09it/s]Upper bound on the fitting time: 100%|██████████| 400/400 [00:06<00:00, 62.77it/s]
Upper bound on the fitting time:   0%|          | 0/150 [00:00<?, ?it/s]Upper bound on the fitting time:  11%|█         | 16/150 [00:00<00:00, 159.86it/s]Upper bound on the fitting time:  21%|██▏       | 32/150 [00:00<00:00, 150.89it/s]Upper bound on the fitting time:  32%|███▏      | 48/150 [00:00<00:00, 151.60it/s]Upper bound on the fitting time:  43%|████▎     | 64/150 [00:00<00:00, 149.76it/s]Upper bound on the fitting time:  53%|█████▎    | 79/150 [00:00<00:00, 148.43it/s]Upper bound on the fitting time:  64%|██████▍   | 96/150 [00:00<00:00, 152.98it/s]Upper bound on the fitting time:  75%|███████▍  | 112/150 [00:00<00:00, 154.12it/s]Upper bound on the fitting time:  85%|████████▌ | 128/150 [00:00<00:00, 154.37it/s]Upper bound on the fitting time:  96%|█████████▌| 144/150 [00:00<00:00, 155.95it/s]Upper bound on the fitting time: 100%|██████████| 150/150 [00:00<00:00, 153.48it/s]
Upper bound on the fitting time:   0%|          | 0/400 [00:00<?, ?it/s]Upper bound on the fitting time:   2%|▏         | 7/400 [00:00<00:05, 68.36it/s]Upper bound on the fitting time:   4%|▎         | 14/400 [00:00<00:05, 66.41it/s]Upper bound on the fitting time:   5%|▌         | 21/400 [00:00<00:05, 64.65it/s]Upper bound on the fitting time:   7%|▋         | 28/400 [00:00<00:05, 64.40it/s]Upper bound on the fitting time:   9%|▉         | 35/400 [00:00<00:05, 64.16it/s]Upper bound on the fitting time:  10%|█         | 42/400 [00:00<00:05, 63.89it/s]Upper bound on the fitting time:  12%|█▏        | 49/400 [00:00<00:05, 63.52it/s]Upper bound on the fitting time:  14%|█▍        | 56/400 [00:00<00:05, 62.49it/s]Upper bound on the fitting time:  16%|█▌        | 63/400 [00:00<00:05, 63.00it/s]Upper bound on the fitting time:  18%|█▊        | 70/400 [00:01<00:05, 63.48it/s]Upper bound on the fitting time:  19%|█▉        | 77/400 [00:01<00:05, 63.22it/s]Upper bound on the fitting time:  21%|██        | 84/400 [00:01<00:05, 62.90it/s]Upper bound on the fitting time:  23%|██▎       | 91/400 [00:01<00:04, 63.41it/s]Upper bound on the fitting time:  24%|██▍       | 98/400 [00:01<00:04, 63.37it/s]Upper bound on the fitting time:  26%|██▋       | 105/400 [00:01<00:04, 63.27it/s]Upper bound on the fitting time:  28%|██▊       | 112/400 [00:01<00:04, 63.06it/s]Upper bound on the fitting time:  30%|██▉       | 119/400 [00:01<00:04, 62.85it/s]Upper bound on the fitting time:  32%|███▏      | 126/400 [00:01<00:04, 60.91it/s]Upper bound on the fitting time:  33%|███▎      | 133/400 [00:02<00:04, 58.70it/s]Upper bound on the fitting time:  35%|███▍      | 139/400 [00:02<00:04, 54.33it/s]Upper bound on the fitting time:  36%|███▋      | 145/400 [00:02<00:05, 50.25it/s]Upper bound on the fitting time:  38%|███▊      | 151/400 [00:02<00:04, 50.12it/s]Upper bound on the fitting time:  39%|███▉      | 157/400 [00:02<00:04, 49.43it/s]Upper bound on the fitting time:  40%|████      | 162/400 [00:02<00:04, 49.12it/s]Upper bound on the fitting time:  42%|████▏     | 167/400 [00:02<00:04, 47.41it/s]Upper bound on the fitting time:  43%|████▎     | 172/400 [00:02<00:04, 46.13it/s]Upper bound on the fitting time:  44%|████▍     | 177/400 [00:03<00:04, 46.48it/s]Upper bound on the fitting time:  46%|████▌     | 182/400 [00:03<00:04, 47.42it/s]Upper bound on the fitting time:  47%|████▋     | 187/400 [00:03<00:04, 47.86it/s]Upper bound on the fitting time:  48%|████▊     | 193/400 [00:03<00:04, 50.88it/s]Upper bound on the fitting time:  50%|████▉     | 199/400 [00:03<00:03, 52.24it/s]Upper bound on the fitting time:  51%|█████▏    | 205/400 [00:03<00:03, 53.29it/s]Upper bound on the fitting time:  53%|█████▎    | 211/400 [00:03<00:03, 52.16it/s]Upper bound on the fitting time:  54%|█████▍    | 217/400 [00:03<00:03, 50.05it/s]Upper bound on the fitting time:  56%|█████▌    | 224/400 [00:03<00:03, 53.96it/s]Upper bound on the fitting time:  58%|█████▊    | 231/400 [00:04<00:02, 56.70it/s]Upper bound on the fitting time:  60%|█████▉    | 238/400 [00:04<00:02, 58.58it/s]Upper bound on the fitting time:  61%|██████▏   | 245/400 [00:04<00:02, 59.76it/s]Upper bound on the fitting time:  63%|██████▎   | 252/400 [00:04<00:02, 60.78it/s]Upper bound on the fitting time:  65%|██████▍   | 259/400 [00:04<00:02, 61.14it/s]Upper bound on the fitting time:  66%|██████▋   | 266/400 [00:04<00:02, 61.89it/s]Upper bound on the fitting time:  68%|██████▊   | 273/400 [00:04<00:02, 62.05it/s]Upper bound on the fitting time:  70%|███████   | 280/400 [00:04<00:02, 59.04it/s]Upper bound on the fitting time:  72%|███████▏  | 286/400 [00:04<00:01, 58.64it/s]Upper bound on the fitting time:  73%|███████▎  | 292/400 [00:05<00:01, 58.82it/s]Upper bound on the fitting time:  75%|███████▍  | 299/400 [00:05<00:01, 60.68it/s]Upper bound on the fitting time:  76%|███████▋  | 306/400 [00:05<00:01, 61.76it/s]Upper bound on the fitting time:  78%|███████▊  | 313/400 [00:05<00:01, 62.30it/s]Upper bound on the fitting time:  80%|████████  | 320/400 [00:05<00:01, 61.84it/s]Upper bound on the fitting time:  82%|████████▏ | 327/400 [00:05<00:01, 62.17it/s]Upper bound on the fitting time:  84%|████████▎ | 334/400 [00:05<00:01, 62.09it/s]Upper bound on the fitting time:  85%|████████▌ | 341/400 [00:05<00:00, 62.77it/s]Upper bound on the fitting time:  87%|████████▋ | 348/400 [00:05<00:00, 62.73it/s]Upper bound on the fitting time:  89%|████████▉ | 355/400 [00:06<00:00, 62.71it/s]Upper bound on the fitting time:  90%|█████████ | 362/400 [00:06<00:00, 61.92it/s]Upper bound on the fitting time:  92%|█████████▏| 369/400 [00:06<00:00, 61.33it/s]Upper bound on the fitting time:  94%|█████████▍| 376/400 [00:06<00:00, 61.18it/s]Upper bound on the fitting time:  96%|█████████▌| 383/400 [00:06<00:00, 58.72it/s]Upper bound on the fitting time:  97%|█████████▋| 389/400 [00:06<00:00, 55.50it/s]Upper bound on the fitting time:  99%|█████████▉| 395/400 [00:06<00:00, 53.89it/s]Upper bound on the fitting time: 100%|██████████| 400/400 [00:06<00:00, 57.98it/s]
Upper bound on the fitting time:   0%|          | 0/150 [00:00<?, ?it/s]Upper bound on the fitting time:  11%|█         | 16/150 [00:00<00:00, 151.54it/s]Upper bound on the fitting time:  21%|██▏       | 32/150 [00:00<00:00, 145.00it/s]Upper bound on the fitting time:  32%|███▏      | 48/150 [00:00<00:00, 147.73it/s]Upper bound on the fitting time:  42%|████▏     | 63/150 [00:00<00:00, 147.01it/s]Upper bound on the fitting time:  52%|█████▏    | 78/150 [00:00<00:00, 141.62it/s]Upper bound on the fitting time:  62%|██████▏   | 93/150 [00:00<00:00, 143.96it/s]Upper bound on the fitting time:  73%|███████▎  | 110/150 [00:00<00:00, 149.50it/s]Upper bound on the fitting time:  85%|████████▍ | 127/150 [00:00<00:00, 154.41it/s]Upper bound on the fitting time:  96%|█████████▌| 144/150 [00:00<00:00, 157.18it/s]Upper bound on the fitting time: 100%|██████████| 150/150 [00:00<00:00, 150.46it/s]
Upper bound on the fitting time:   0%|          | 0/400 [00:00<?, ?it/s]Upper bound on the fitting time:   2%|▏         | 7/400 [00:00<00:06, 65.35it/s]Upper bound on the fitting time:   4%|▎         | 14/400 [00:00<00:06, 63.78it/s]Upper bound on the fitting time:   5%|▌         | 21/400 [00:00<00:05, 63.98it/s]Upper bound on the fitting time:   7%|▋         | 28/400 [00:00<00:05, 63.76it/s]Upper bound on the fitting time:   9%|▉         | 35/400 [00:00<00:05, 63.47it/s]Upper bound on the fitting time:  10%|█         | 42/400 [00:00<00:05, 63.78it/s]Upper bound on the fitting time:  12%|█▏        | 49/400 [00:00<00:05, 63.85it/s]Upper bound on the fitting time:  14%|█▍        | 56/400 [00:00<00:05, 62.42it/s]Upper bound on the fitting time:  16%|█▌        | 63/400 [00:00<00:05, 62.73it/s]Upper bound on the fitting time:  18%|█▊        | 70/400 [00:01<00:05, 62.51it/s]Upper bound on the fitting time:  19%|█▉        | 77/400 [00:01<00:05, 62.35it/s]Upper bound on the fitting time:  21%|██        | 84/400 [00:01<00:05, 62.67it/s]Upper bound on the fitting time:  23%|██▎       | 91/400 [00:01<00:04, 62.82it/s]Upper bound on the fitting time:  24%|██▍       | 98/400 [00:01<00:04, 61.21it/s]Upper bound on the fitting time:  26%|██▋       | 105/400 [00:01<00:05, 56.88it/s]Upper bound on the fitting time:  28%|██▊       | 111/400 [00:01<00:05, 55.72it/s]Upper bound on the fitting time:  29%|██▉       | 117/400 [00:01<00:05, 54.91it/s]Upper bound on the fitting time:  31%|███       | 123/400 [00:02<00:05, 54.44it/s]Upper bound on the fitting time:  32%|███▏      | 129/400 [00:02<00:05, 54.00it/s]Upper bound on the fitting time:  34%|███▍      | 135/400 [00:02<00:04, 53.35it/s]Upper bound on the fitting time:  35%|███▌      | 141/400 [00:02<00:04, 52.85it/s]Upper bound on the fitting time:  37%|███▋      | 147/400 [00:02<00:04, 52.99it/s]Upper bound on the fitting time:  38%|███▊      | 154/400 [00:02<00:04, 56.47it/s]Upper bound on the fitting time:  40%|████      | 161/400 [00:02<00:04, 58.31it/s]Upper bound on the fitting time:  42%|████▏     | 168/400 [00:02<00:03, 59.56it/s]Upper bound on the fitting time:  44%|████▍     | 175/400 [00:02<00:03, 60.27it/s]Upper bound on the fitting time:  46%|████▌     | 182/400 [00:03<00:03, 61.36it/s]Upper bound on the fitting time:  47%|████▋     | 189/400 [00:03<00:03, 61.99it/s]Upper bound on the fitting time:  49%|████▉     | 196/400 [00:03<00:03, 62.60it/s]Upper bound on the fitting time:  51%|█████     | 203/400 [00:03<00:03, 62.90it/s]Upper bound on the fitting time:  52%|█████▎    | 210/400 [00:03<00:03, 60.57it/s]Upper bound on the fitting time:  54%|█████▍    | 217/400 [00:03<00:03, 57.78it/s]Upper bound on the fitting time:  56%|█████▌    | 223/400 [00:03<00:03, 56.97it/s]Upper bound on the fitting time:  57%|█████▋    | 229/400 [00:03<00:03, 54.77it/s]Upper bound on the fitting time:  59%|█████▉    | 235/400 [00:03<00:02, 56.15it/s]Upper bound on the fitting time:  60%|██████    | 242/400 [00:04<00:02, 58.27it/s]Upper bound on the fitting time:  62%|██████▏   | 249/400 [00:04<00:02, 59.89it/s]Upper bound on the fitting time:  64%|██████▍   | 256/400 [00:04<00:02, 61.12it/s]Upper bound on the fitting time:  66%|██████▌   | 263/400 [00:04<00:02, 60.51it/s]Upper bound on the fitting time:  68%|██████▊   | 270/400 [00:04<00:02, 59.08it/s]Upper bound on the fitting time:  69%|██████▉   | 276/400 [00:04<00:02, 58.60it/s]Upper bound on the fitting time:  71%|███████   | 283/400 [00:04<00:01, 59.95it/s]Upper bound on the fitting time:  72%|███████▎  | 290/400 [00:04<00:01, 60.93it/s]Upper bound on the fitting time:  74%|███████▍  | 297/400 [00:04<00:01, 61.83it/s]Upper bound on the fitting time:  76%|███████▌  | 304/400 [00:05<00:01, 62.46it/s]Upper bound on the fitting time:  78%|███████▊  | 311/400 [00:05<00:01, 62.98it/s]Upper bound on the fitting time:  80%|███████▉  | 318/400 [00:05<00:01, 63.38it/s]Upper bound on the fitting time:  81%|████████▏ | 325/400 [00:05<00:01, 63.50it/s]Upper bound on the fitting time:  83%|████████▎ | 332/400 [00:05<00:01, 63.74it/s]Upper bound on the fitting time:  85%|████████▍ | 339/400 [00:05<00:00, 63.96it/s]Upper bound on the fitting time:  86%|████████▋ | 346/400 [00:05<00:00, 64.17it/s]Upper bound on the fitting time:  88%|████████▊ | 353/400 [00:05<00:00, 64.25it/s]Upper bound on the fitting time:  90%|█████████ | 360/400 [00:05<00:00, 64.02it/s]Upper bound on the fitting time:  92%|█████████▏| 367/400 [00:06<00:00, 62.90it/s]Upper bound on the fitting time:  94%|█████████▎| 374/400 [00:06<00:00, 60.23it/s]Upper bound on the fitting time:  95%|█████████▌| 381/400 [00:06<00:00, 61.15it/s]Upper bound on the fitting time:  97%|█████████▋| 388/400 [00:06<00:00, 61.84it/s]Upper bound on the fitting time:  99%|█████████▉| 395/400 [00:06<00:00, 62.99it/s]Upper bound on the fitting time: 100%|██████████| 400/400 [00:06<00:00, 60.45it/s]
Upper bound on the fitting time:   0%|          | 0/150 [00:00<?, ?it/s]Upper bound on the fitting time:  11%|█▏        | 17/150 [00:00<00:00, 162.80it/s]Upper bound on the fitting time:  23%|██▎       | 34/150 [00:00<00:00, 154.76it/s]Upper bound on the fitting time:  33%|███▎      | 50/150 [00:00<00:00, 152.54it/s]Upper bound on the fitting time:  44%|████▍     | 66/150 [00:00<00:00, 151.98it/s]Upper bound on the fitting time:  55%|█████▍    | 82/150 [00:00<00:00, 149.94it/s]Upper bound on the fitting time:  65%|██████▌   | 98/150 [00:00<00:00, 153.13it/s]Upper bound on the fitting time:  76%|███████▌  | 114/150 [00:00<00:00, 149.91it/s]Upper bound on the fitting time:  87%|████████▋ | 130/150 [00:00<00:00, 150.39it/s]Upper bound on the fitting time:  98%|█████████▊| 147/150 [00:00<00:00, 155.02it/s]Upper bound on the fitting time: 100%|██████████| 150/150 [00:00<00:00, 152.85it/s]
Upper bound on the fitting time:   0%|          | 0/400 [00:00<?, ?it/s]Upper bound on the fitting time:   2%|▏         | 7/400 [00:00<00:06, 61.26it/s]Upper bound on the fitting time:   4%|▎         | 14/400 [00:00<00:06, 59.19it/s]Upper bound on the fitting time:   5%|▌         | 20/400 [00:00<00:06, 59.11it/s]Upper bound on the fitting time:   6%|▋         | 26/400 [00:00<00:06, 58.70it/s]Upper bound on the fitting time:   8%|▊         | 33/400 [00:00<00:06, 59.98it/s]Upper bound on the fitting time:  10%|▉         | 39/400 [00:00<00:06, 59.23it/s]Upper bound on the fitting time:  11%|█▏        | 45/400 [00:00<00:05, 59.23it/s]Upper bound on the fitting time:  13%|█▎        | 51/400 [00:00<00:05, 58.50it/s]Upper bound on the fitting time:  14%|█▍        | 57/400 [00:00<00:05, 57.89it/s]Upper bound on the fitting time:  16%|█▌        | 63/400 [00:01<00:05, 58.10it/s]Upper bound on the fitting time:  18%|█▊        | 70/400 [00:01<00:05, 58.98it/s]Upper bound on the fitting time:  19%|█▉        | 76/400 [00:01<00:05, 58.62it/s]Upper bound on the fitting time:  21%|██        | 83/400 [00:01<00:05, 59.90it/s]Upper bound on the fitting time:  22%|██▏       | 89/400 [00:01<00:05, 59.65it/s]Upper bound on the fitting time:  24%|██▍       | 96/400 [00:01<00:05, 60.28it/s]Upper bound on the fitting time:  26%|██▌       | 103/400 [00:01<00:04, 60.07it/s]Upper bound on the fitting time:  28%|██▊       | 110/400 [00:01<00:04, 60.24it/s]Upper bound on the fitting time:  29%|██▉       | 117/400 [00:01<00:04, 59.62it/s]Upper bound on the fitting time:  31%|███       | 124/400 [00:02<00:04, 59.93it/s]Upper bound on the fitting time:  33%|███▎      | 131/400 [00:02<00:04, 61.23it/s]Upper bound on the fitting time:  34%|███▍      | 138/400 [00:02<00:04, 60.54it/s]Upper bound on the fitting time:  36%|███▋      | 145/400 [00:02<00:04, 59.76it/s]Upper bound on the fitting time:  38%|███▊      | 151/400 [00:02<00:04, 58.84it/s]Upper bound on the fitting time:  39%|███▉      | 157/400 [00:02<00:04, 56.56it/s]Upper bound on the fitting time:  41%|████      | 163/400 [00:02<00:04, 56.71it/s]Upper bound on the fitting time:  42%|████▏     | 169/400 [00:02<00:04, 57.57it/s]Upper bound on the fitting time:  44%|████▍     | 176/400 [00:02<00:03, 58.43it/s]Upper bound on the fitting time:  46%|████▌     | 183/400 [00:03<00:03, 59.76it/s]Upper bound on the fitting time:  47%|████▋     | 189/400 [00:03<00:03, 59.80it/s]Upper bound on the fitting time:  49%|████▉     | 196/400 [00:03<00:03, 60.88it/s]Upper bound on the fitting time:  51%|█████     | 203/400 [00:03<00:03, 60.28it/s]Upper bound on the fitting time:  52%|█████▎    | 210/400 [00:03<00:03, 61.29it/s]Upper bound on the fitting time:  54%|█████▍    | 217/400 [00:03<00:02, 61.07it/s]Upper bound on the fitting time:  56%|█████▌    | 224/400 [00:03<00:02, 61.16it/s]Upper bound on the fitting time:  58%|█████▊    | 231/400 [00:03<00:02, 60.51it/s]Upper bound on the fitting time:  60%|█████▉    | 238/400 [00:03<00:02, 60.21it/s]Upper bound on the fitting time:  61%|██████▏   | 245/400 [00:04<00:02, 60.19it/s]Upper bound on the fitting time:  63%|██████▎   | 252/400 [00:04<00:02, 59.99it/s]Upper bound on the fitting time:  65%|██████▍   | 259/400 [00:04<00:02, 59.79it/s]Upper bound on the fitting time:  66%|██████▋   | 265/400 [00:04<00:02, 59.63it/s]Upper bound on the fitting time:  68%|██████▊   | 271/400 [00:04<00:02, 59.28it/s]Upper bound on the fitting time:  69%|██████▉   | 277/400 [00:04<00:02, 59.35it/s]Upper bound on the fitting time:  71%|███████   | 283/400 [00:04<00:01, 59.47it/s]Upper bound on the fitting time:  72%|███████▎  | 290/400 [00:04<00:01, 59.67it/s]Upper bound on the fitting time:  74%|███████▍  | 296/400 [00:04<00:01, 58.86it/s]Upper bound on the fitting time:  76%|███████▌  | 303/400 [00:05<00:01, 60.09it/s]Upper bound on the fitting time:  78%|███████▊  | 310/400 [00:05<00:01, 59.45it/s]Upper bound on the fitting time:  79%|███████▉  | 317/400 [00:05<00:01, 59.90it/s]Upper bound on the fitting time:  81%|████████  | 324/400 [00:05<00:01, 60.78it/s]Upper bound on the fitting time:  83%|████████▎ | 331/400 [00:05<00:01, 59.82it/s]Upper bound on the fitting time:  84%|████████▍ | 338/400 [00:05<00:01, 60.60it/s]Upper bound on the fitting time:  86%|████████▋ | 345/400 [00:05<00:00, 59.51it/s]Upper bound on the fitting time:  88%|████████▊ | 351/400 [00:05<00:00, 59.34it/s]Upper bound on the fitting time:  89%|████████▉ | 357/400 [00:05<00:00, 59.48it/s]Upper bound on the fitting time:  91%|█████████ | 363/400 [00:06<00:00, 59.02it/s]Upper bound on the fitting time:  92%|█████████▎| 370/400 [00:06<00:00, 59.94it/s]Upper bound on the fitting time:  94%|█████████▍| 377/400 [00:06<00:00, 60.62it/s]Upper bound on the fitting time:  96%|█████████▌| 384/400 [00:06<00:00, 60.29it/s]Upper bound on the fitting time:  98%|█████████▊| 391/400 [00:06<00:00, 60.61it/s]Upper bound on the fitting time: 100%|█████████▉| 398/400 [00:06<00:00, 61.11it/s]Upper bound on the fitting time: 100%|██████████| 400/400 [00:06<00:00, 59.66it/s]
Upper bound on the fitting time:   0%|          | 0/150 [00:00<?, ?it/s]Upper bound on the fitting time:  11%|█▏        | 17/150 [00:00<00:00, 159.94it/s]Upper bound on the fitting time:  22%|██▏       | 33/150 [00:00<00:00, 158.07it/s]Upper bound on the fitting time:  33%|███▎      | 49/150 [00:00<00:00, 156.28it/s]Upper bound on the fitting time:  43%|████▎     | 65/150 [00:00<00:00, 146.11it/s]Upper bound on the fitting time:  53%|█████▎    | 80/150 [00:00<00:00, 140.75it/s]Upper bound on the fitting time:  63%|██████▎   | 95/150 [00:00<00:00, 138.72it/s]Upper bound on the fitting time:  73%|███████▎  | 109/150 [00:00<00:00, 138.28it/s]Upper bound on the fitting time:  83%|████████▎ | 124/150 [00:00<00:00, 139.94it/s]Upper bound on the fitting time:  93%|█████████▎| 139/150 [00:00<00:00, 142.93it/s]Upper bound on the fitting time: 100%|██████████| 150/150 [00:01<00:00, 144.24it/s]
Upper bound on the fitting time:   0%|          | 0/400 [00:00<?, ?it/s]Upper bound on the fitting time:   2%|▏         | 6/400 [00:00<00:06, 56.64it/s]Upper bound on the fitting time:   3%|▎         | 12/400 [00:00<00:07, 54.66it/s]Upper bound on the fitting time:   4%|▍         | 18/400 [00:00<00:07, 50.76it/s]Upper bound on the fitting time:   6%|▌         | 24/400 [00:00<00:07, 49.41it/s]Upper bound on the fitting time:   7%|▋         | 29/400 [00:00<00:07, 48.79it/s]Upper bound on the fitting time:   8%|▊         | 34/400 [00:00<00:07, 48.47it/s]Upper bound on the fitting time:  10%|▉         | 39/400 [00:00<00:07, 47.81it/s]Upper bound on the fitting time:  11%|█         | 44/400 [00:00<00:07, 47.11it/s]Upper bound on the fitting time:  12%|█▏        | 49/400 [00:01<00:07, 46.42it/s]Upper bound on the fitting time:  14%|█▎        | 54/400 [00:01<00:07, 45.99it/s]Upper bound on the fitting time:  15%|█▍        | 59/400 [00:01<00:07, 45.73it/s]Upper bound on the fitting time:  16%|█▌        | 64/400 [00:01<00:07, 45.43it/s]Upper bound on the fitting time:  17%|█▋        | 69/400 [00:01<00:07, 45.60it/s]Upper bound on the fitting time:  18%|█▊        | 74/400 [00:01<00:07, 45.51it/s]Upper bound on the fitting time:  20%|█▉        | 79/400 [00:01<00:07, 45.56it/s]Upper bound on the fitting time:  21%|██        | 84/400 [00:01<00:06, 45.77it/s]Upper bound on the fitting time:  22%|██▏       | 89/400 [00:01<00:06, 45.90it/s]Upper bound on the fitting time:  24%|██▎       | 94/400 [00:02<00:06, 45.74it/s]Upper bound on the fitting time:  25%|██▍       | 99/400 [00:02<00:06, 45.44it/s]Upper bound on the fitting time:  26%|██▋       | 105/400 [00:02<00:06, 47.78it/s]Upper bound on the fitting time:  28%|██▊       | 111/400 [00:02<00:05, 50.77it/s]Upper bound on the fitting time:  29%|██▉       | 117/400 [00:02<00:05, 52.24it/s]Upper bound on the fitting time:  31%|███       | 123/400 [00:02<00:05, 53.38it/s]Upper bound on the fitting time:  32%|███▏      | 129/400 [00:02<00:04, 54.33it/s]Upper bound on the fitting time:  34%|███▍      | 135/400 [00:02<00:04, 54.99it/s]Upper bound on the fitting time:  35%|███▌      | 141/400 [00:02<00:04, 55.70it/s]Upper bound on the fitting time:  37%|███▋      | 147/400 [00:02<00:04, 56.18it/s]Upper bound on the fitting time:  38%|███▊      | 153/400 [00:03<00:04, 55.50it/s]Upper bound on the fitting time:  40%|███▉      | 159/400 [00:03<00:04, 55.76it/s]Upper bound on the fitting time:  41%|████▏     | 165/400 [00:03<00:04, 55.56it/s]Upper bound on the fitting time:  43%|████▎     | 171/400 [00:03<00:04, 55.33it/s]Upper bound on the fitting time:  44%|████▍     | 177/400 [00:03<00:04, 54.90it/s]Upper bound on the fitting time:  46%|████▌     | 183/400 [00:03<00:03, 54.81it/s]Upper bound on the fitting time:  47%|████▋     | 189/400 [00:03<00:03, 55.42it/s]Upper bound on the fitting time:  49%|████▉     | 195/400 [00:03<00:03, 56.19it/s]Upper bound on the fitting time:  50%|█████     | 201/400 [00:03<00:03, 55.61it/s]Upper bound on the fitting time:  52%|█████▏    | 207/400 [00:04<00:03, 56.28it/s]Upper bound on the fitting time:  53%|█████▎    | 213/400 [00:04<00:03, 56.27it/s]Upper bound on the fitting time:  55%|█████▍    | 219/400 [00:04<00:03, 56.04it/s]Upper bound on the fitting time:  56%|█████▋    | 225/400 [00:04<00:03, 55.63it/s]Upper bound on the fitting time:  58%|█████▊    | 231/400 [00:04<00:03, 55.75it/s]Upper bound on the fitting time:  59%|█████▉    | 237/400 [00:04<00:02, 56.48it/s]Upper bound on the fitting time:  61%|██████    | 243/400 [00:04<00:02, 56.20it/s]Upper bound on the fitting time:  62%|██████▏   | 249/400 [00:04<00:02, 56.34it/s]Upper bound on the fitting time:  64%|██████▍   | 255/400 [00:04<00:02, 56.89it/s]Upper bound on the fitting time:  65%|██████▌   | 261/400 [00:05<00:02, 56.44it/s]Upper bound on the fitting time:  67%|██████▋   | 267/400 [00:05<00:02, 55.23it/s]Upper bound on the fitting time:  68%|██████▊   | 273/400 [00:05<00:02, 55.42it/s]Upper bound on the fitting time:  70%|██████▉   | 279/400 [00:05<00:02, 55.59it/s]Upper bound on the fitting time:  71%|███████▏  | 285/400 [00:05<00:02, 55.36it/s]Upper bound on the fitting time:  73%|███████▎  | 291/400 [00:05<00:01, 56.08it/s]Upper bound on the fitting time:  74%|███████▍  | 297/400 [00:05<00:01, 55.45it/s]Upper bound on the fitting time:  76%|███████▌  | 303/400 [00:05<00:01, 54.83it/s]Upper bound on the fitting time:  77%|███████▋  | 309/400 [00:05<00:01, 54.65it/s]Upper bound on the fitting time:  79%|███████▉  | 315/400 [00:05<00:01, 55.10it/s]Upper bound on the fitting time:  80%|████████  | 321/400 [00:06<00:01, 55.65it/s]Upper bound on the fitting time:  82%|████████▏ | 327/400 [00:06<00:01, 55.80it/s]Upper bound on the fitting time:  83%|████████▎ | 333/400 [00:06<00:01, 55.41it/s]Upper bound on the fitting time:  85%|████████▍ | 339/400 [00:06<00:01, 56.09it/s]Upper bound on the fitting time:  86%|████████▋ | 345/400 [00:06<00:00, 55.76it/s]Upper bound on the fitting time:  88%|████████▊ | 351/400 [00:06<00:00, 55.84it/s]Upper bound on the fitting time:  89%|████████▉ | 357/400 [00:06<00:00, 56.05it/s]Upper bound on the fitting time:  91%|█████████ | 363/400 [00:06<00:00, 55.77it/s]Upper bound on the fitting time:  92%|█████████▏| 369/400 [00:06<00:00, 56.74it/s]Upper bound on the fitting time:  94%|█████████▍| 375/400 [00:07<00:00, 55.98it/s]Upper bound on the fitting time:  95%|█████████▌| 381/400 [00:07<00:00, 56.39it/s]Upper bound on the fitting time:  97%|█████████▋| 387/400 [00:07<00:00, 56.83it/s]Upper bound on the fitting time:  98%|█████████▊| 393/400 [00:07<00:00, 56.73it/s]Upper bound on the fitting time: 100%|█████████▉| 399/400 [00:07<00:00, 55.87it/s]Upper bound on the fitting time: 100%|██████████| 400/400 [00:07<00:00, 53.31it/s]

4.5.1 Evaluate model quality

collection.show(figsize=(8, 8))

This displays BIC, AIC, log-likelihood, and clustering metric (WCSS, silhouette) for each model.

Use the silhouette score (higher is better) or WCSS (lower is better) to determine the optimal number of clusters. In this example, 2 clusters may be appropriate.

⚠️ WCSS always decreases with the number of clusters, so that an ELBOW method must be used. Based on the graph and the WCSS metric, I would suggest 4 clusters.

The silhouette score is not sensitive to the number of clusters.

4.5.2 Select the best model

One can directly access the best model using the best_model method, with the metric of choice:

best_mixture = collection.best_model("silhouette") # Could be also BIC, AIC, or WCSS.
print(best_mixture)
A multivariate PlnMixture with diagonal covariances and 2 clusters.
======================================================================
     Loglike   Dimension    Nb param         BIC         AIC         ICL  Silhouette
   -25178.46          20          80  25418.1208  25258.4622    12105.51   0.5514621

======================================================================
* Useful attributes
    .latent_variables .latent_positions .coef .covariance .precision .model_parameters .latent_parameters .optim_details
* Useful methods
    .transform() .show() .predict() .sigma() .projected_latent_variables() .plot_correlation_circle() .biplot() .viz() .pca_pairplot() .plot_expected_vs_true()
* Additional attributes for PlnMixture are:
    .covariances .cluster_bias .latent_prob .n_cluster .weights
* Additional methods for PlnMixture are:
    .predict_clusters()

You can access specific models within the collection by using the cluster number as a key:

print(collection[3])
A multivariate PlnMixture with diagonal covariances and 3 clusters.
======================================================================
     Loglike   Dimension    Nb param         BIC         AIC         ICL  Silhouette
   -24320.75          20         120  24680.2424  24440.7545    11700.29  0.42461434

======================================================================
* Useful attributes
    .latent_variables .latent_positions .coef .covariance .precision .model_parameters .latent_parameters .optim_details
* Useful methods
    .transform() .show() .predict() .sigma() .projected_latent_variables() .plot_correlation_circle() .biplot() .viz() .pca_pairplot() .plot_expected_vs_true()
* Additional attributes for PlnMixture are:
    .covariances .cluster_bias .latent_prob .n_cluster .weights
* Additional methods for PlnMixture are:
    .predict_clusters()

and loop through the collection:

for mixture in collection.values():
    print(mixture)

References

Batardière, Bastien, Joon Kwon, and Julien Chiquet. 2024. “pyPLNmodels: A Python Package to Analyze Multivariate High-Dimensional Count Data.” Journal of Open Source Software.