Full PyCVI pipeline

Here is an example using exclusively PyCVI for the entire clustering pipeline. The preprocessing steps and the clustering steps can be integrated into the PyCVI pipeline by providing sklearn-like classes of clustering models (e.g. KMeans) and data preprocessor (e.g. StandardScaler).

In this example, we use time-series data and non-time-series data. In addition we use classes from scikit-learn, scikit-learn extra and aeon in order to illustrate the compatibility of PyCVI with sklearn-like libraries.

If you wish to run the example scripts on your own computer, please first follow the instructions detailed in Running example scripts on your computer.

import numpy as np
import time
from sklearn.cluster import AgglomerativeClustering, KMeans
from sklearn.preprocessing import StandardScaler
from sklearn_extra.cluster import KMedoids
from aeon.clustering import TimeSeriesKMeans

from pycvi.cluster import generate_all_clusterings, get_clustering
from pycvi.cvi import CVIs
from pycvi.compute_scores import compute_all_scores
from pycvi.vi import variation_information
from pycvi.datasets.benchmark import load_data
from pycvi.exceptions import SelectionError

from pycvi_examples_utils import plot_true_best, plot_selected_clusters

def pipeline(
    X: np.ndarray,
    y: np.ndarray,
    model_class,
    model_kw: dict,
    k_max: int = 25,
    scaler = StandardScaler(),
    DTW:bool = False,
    fig_title: str = "",
    fig_name: str = "",
) -> None:
    """
    This function gives an example of using most of PyCVI's features.

    In this full example, we assume that we have access to the real
    labels of the datapoints. In this function we:

    - Standardize the data
    - Generate all clusterings for a given range of number of clusters.
    - Compute the Variation of Information (VI) between the generated
      clusterings and the true clustering
    - For each CVI available in PyCVI, compute their values for all
      generated clusterings
    - For each CVI, select the best clustering according to its CVI
      values
    - Create a summary plot containing the true clustering, the
      clustering assuming the correct number of clusters and the
      selected clusterings of each CVI.
    """
    print(f'\n ***** {fig_title} ***** \n')
    k_range = range(k_max)

    # ------------------------------------------------------------------
    # ------------------ Define true clustering  -----------------------
    # ------------------------------------------------------------------
    # From the label for each datapoint to a list of
    # datapoints for each cluster.
    # true clusters: List[List[int]]
    true_clusters = get_clustering(y)
    k_true = len(true_clusters)

    # ------------------------------------------------------------------
    # ------------------ Generate clusterings  -------------------------
    # ------------------------------------------------------------------

    t_start = time.time()

    clusterings = generate_all_clusterings(
            X,
            model_class,
            model_kw=model_kw,
            n_clusters_range = k_range,
            DTW = DTW,
            scaler=scaler,
        )

    t_end = time.time()
    dt = t_end - t_start

    print(f"Clusterings generated in: {dt:.2f}s")

    # ------------------------------------------------------------------
    # ------  Variation of information with the true clustering --------
    # ------------------------------------------------------------------

    best_clusters = clusterings[k_true]
    VI_best = variation_information(true_clusters, best_clusters)

    # -- Plot true clusters & clusters when assuming k_true clusters ---
    fig = plot_true_best(X, y, best_clusters, VI_best)

    print(" ================ VI ================ ")
    # Compute VI between the true clustering and each clustering
    # obtained with the different clustering methods
    VIs = {}
    for k, clustering in clusterings.items():
        VIs[k] = variation_information(true_clusters, clustering)
        print(k, VIs[k])

    # ------------------------------------------------------------------
    # ------------ Compute CVI values and select k ---------------------
    # ------------------------------------------------------------------
    ax_titles = []
    clusterings_selected = []

    for cvi_class in CVIs:

        # Instantiate a CVI model
        cvi = cvi_class()
        t_start = time.time()
        print(f" ====== {cvi} ====== ")

        # Compute CVI values for all clusterings
        scores = compute_all_scores(
            cvi,
            X,
            clusterings,
            DTW=DTW,
            scaler=StandardScaler(),
        )

        t_end = time.time()
        dt = t_end - t_start

        # Print CVI values and selected k
        for k in clusterings:
            print(k, scores[k])
        print('Code executed in %.2f s' %(dt))

        # Select k
        try:
            k_selected = cvi.select(scores)
        except SelectionError as e:
            k_selected = None
            clusterings_selected.append(None)
            ax_titles.append(
                f"{cvi}, No clustering could be selected."
            )
        else:
            clusterings_selected.append(clusterings[k_selected])
            ax_titles.append(
                f"{cvi}, k={k_selected}, VI={VIs[k_selected]:.2f}"
            )
        finally:
            print(f"Selected k: {k_selected} | True k: {k_true}")
    # ------------------------------------------------------------------
    # ----------------------- Summary plot -----------------------------
    # ------------------------------------------------------------------

    fig = plot_selected_clusters(X, clusterings_selected, fig, ax_titles)
    fig.suptitle(fig_title)
    fig.savefig(fig_name + ".png")

# ======================================================================
# PyCVI on non time-series data
# ======================================================================

# ------------- KMeans ------------------------
X, y = load_data("zelnik1", "barton")
DTW = False
k_max = 10

model_class = KMeans
model_kw = {}
scaler = StandardScaler()

fig_title = "Non time-series data with KMeans"
fig_name = "Barton_data_KMeans"
pipeline(X, y, model_class, model_kw, k_max, scaler, DTW, fig_title, fig_name)

# --------- AgglomerativeClustering ----------
X, y = load_data("zelnik1", "barton")
DTW = False
k_max = 10

model_class = AgglomerativeClustering
# sklearn kwargs for AgglomerativeClustering
model_kw = {"linkage" : "single"}
scaler = StandardScaler()

fig_title = "Non time-series data with AgglomerativeClustering-Single"
fig_name = "Barton_data_AgglomerativeClustering_Single"

pipeline(X, y, model_class, model_kw, k_max, scaler, DTW, fig_title, fig_name)

# ======================================================================
# PyCVI on time series data
# ======================================================================

X, y = load_data("Trace", "UCR")

# ==========================
# PyCVI using DTW
# ==========================

DTW = True

model_class = TimeSeriesKMeans
# aeon kwargs for TimeSeriesKMeans
model_kw = {
    "distance" : "dtw",
    "distance_params" : {"window": 0.2},
}
scaler = StandardScaler()
fig_title = "Time-series data using DTW with TimeSeriesKMeans"
fig_name = "UCR_data_DTW_TimeSeriesKMeans"

pipeline(X, y, model_class, model_kw, k_max, scaler, DTW, fig_title, fig_name)

# ==========================
# PyCVI not using DTW
# ==========================

DTW = False

model_class = KMedoids
model_kw = {}
scaler = StandardScaler()
fig_title = "Time-series data without DTW with KMedoids"
fig_name = "UCR_data_no_DTW_KMedoids"

pipeline(X, y, model_class, model_kw, k_max, scaler, DTW, fig_title, fig_name)

../_images/Barton_data_KMeans.png ../_images/Barton_data_AgglomerativeClustering_Single.png ../_images/UCR_data_no_DTW_KMedoids.png ../_images/UCR_data_DTW_TimeSeriesKMeans.png
 ***** Non time-series data with KMeans ***** 

Clusterings generated in: 11.01s
 ================ VI ================ 
0 1.5095732725667173
1 1.5095732725667173
2 2.1467706655447474
3 2.515266501864858
4 2.431269031458642
5 2.182742718815624
6 2.5315911393573645
7 2.1941272212544254
8 1.8754266323464934
9 1.9576850488697186
 ====== Hartigan_monotonous ====== 
0 232.0654934825328
1 119.56923880154238
2 117.42068546623949
3 76.40446648796775
4 91.3780159415236
5 57.09486007192689
6 55.83515279586739
7 58.81596944462576
8 50.25603112718371
9 None
Code executed in 0.01 s
Selected k: 1 | True k: 3
 ====== CalinskiHarabasz_original ====== 
0 None
1 0.0
2 119.56923880154244
3 141.9298657398708
4 144.191997982083
5 164.12016355397242
6 167.76625281550028
7 175.2757114218074
8 188.38538187109924
9 199.0203357228885
Code executed in 0.00 s
Selected k: 9 | True k: 3
 ====== GapStatistic_original ====== 
0 None
1 -0.004049261254301939
2 -0.16192237942780618
3 -0.27244279695838625
4 -0.4920812182219976
5 -0.4256169770342595
6 -0.43858275225194276
7 -0.3904993095017155
8 -0.411570354038723
9 -0.356396250294015
Code executed in 4.31 s
Selected k: 1 | True k: 3
 ====== Silhouette ====== 
0 None
1 None
2 0.2933768469613197
3 0.31259123245038284
4 0.3413392739191957
5 0.37039924016733944
6 0.37094479495684984
7 0.4103379087638091
8 0.4267966614343076
9 0.44664602143258175
Code executed in 0.26 s
Selected k: 9 | True k: 3
 ====== ScoreFunction ====== 
0 None
1 0.2674380756639073
2 0.1541968037562551
3 0.08425097006376447
4 0.04451072472017037
5 0.025935922707537307
6 0.020008430379183317
7 0.014868903544519974
8 0.01065525111768495
9 0.010142318743235013
Code executed in 0.00 s
Selected k: 1 | True k: 3
 ====== MaulikBandyopadhyay_absolute ====== 
0 None
1 0.0
2 0.9188567336356419
3 1.0147704154274744
4 1.8063317682795923
5 1.5744441716522772
6 1.3663661141095103
7 1.7926005567580077
8 1.5857603654451993
9 1.6153559519442864
Code executed in 0.01 s
Selected k: 4 | True k: 3
 ====== SD ====== 
0 None
1 None
2 441728.4898442268
3 310275.2846361639
4 272386.7989562048
5 245987.46320760727
6 169327.7515705076
7 160079.58432485093
8 157886.32118620203
9 121936.9065598348
Code executed in 0.04 s
Selected k: 9 | True k: 3
 ====== SDbw ====== 
0 None
1 None
2 1.82006477611026
3 1.8280466583013388
4 1.1142881325194292
5 0.9169185191600353
6 0.7119653884664494
7 0.4572866615763178
8 0.4238378943556881
9 0.36873664289345237
Code executed in 0.01 s
Selected k: 9 | True k: 3
 ====== Dunn ====== 
0 None
1 None
2 0.017042923961732886
3 0.015506094539212548
4 0.016483327637834295
5 0.02230805219889633
6 0.013671611560250492
7 0.03813269509486268
8 0.019671003843756696
9 0.009020621976657353
Code executed in 0.01 s
Selected k: 7 | True k: 3
 ====== XB ====== 
0 None
1 None
2 0.5659598687639614
3 0.3695518574219425
4 0.3539850573619467
5 0.27747225133109554
6 0.27133129210124823
7 0.330795539278967
8 0.4091579352328854
9 0.3443653098477721
Code executed in 0.00 s
Selected k: 6 | True k: 3
 ====== XB_star ====== 
0 None
1 None
2 0.6189447883700204
3 0.4175182071057973
4 0.46217485095276317
5 0.4233736268817278
6 0.4052968621701478
7 0.47523707449636077
8 0.7654105312870668
9 0.6239183292628411
Code executed in 0.00 s
Selected k: 6 | True k: 3
 ====== DB ====== 
0 None
1 None
2 1.519725983475532
3 1.205964355571457
4 1.1984831154588216
5 0.9854186988692494
6 1.0483543825083532
7 1.0357678706324993
8 1.0522205276125398
9 1.0463260728661898
Code executed in 0.01 s
Selected k: 5 | True k: 3
 ====== Inertia_sum ====== 
0 524.0762519879294
1 349.0214135130419
2 305.51326679993497
3 268.3822961903845
4 238.49202838076548
5 210.50047698366603
6 194.35777004023112
7 174.22676417974458
8 158.32130059577074
9 147.64209076150334
Code executed in 0.00 s
Selected k: 1 | True k: 3
 ====== Diameter_max ====== 
0 6.225889127666499
1 4.737154354950527
2 4.665215171139693
3 3.858736585127345
4 3.527715680838392
5 3.0945238538036546
6 2.7824886852430075
7 2.5235271795281573
8 2.54835120455792
9 2.332601216405105
Code executed in 0.00 s
Selected k: 1 | True k: 3

 ***** Non time-series data with AgglomerativeClustering-Single ***** 

Clusterings generated in: 0.03s
 ================ VI ================ 
0 1.5095732725667173
1 1.5095732725667173
2 0.5935232483446198
3 0.0
4 0.17642364963340507
5 0.3160403254013091
6 0.35617410466552313
7 0.5092833003363406
8 0.6811955126547553
9 0.7159856910848794
 ====== Hartigan_monotonous ====== 
0 243.17059353383993
1 0.017211966847463733
2 0.011381644034122118
3 34.58290182504769
4 35.42587757523952
5 1.2950951116888347
6 60.33785949064848
7 114.59147910894787
8 1.8539186101937388
9 None
Code executed in 0.01 s
Selected k: 1 | True k: 3
 ====== CalinskiHarabasz_original ====== 
0 None
1 0.0
2 0.01721196684745756
3 0.0142681588644381
4 11.538225250696614
5 18.52000323839848
6 15.089892803326242
7 25.17787001256915
8 46.34652110326673
9 40.903946263374344
Code executed in 0.00 s
Selected k: 8 | True k: 3
 ====== GapStatistic_original ====== 
0 None
1 -0.006801696816472358
2 -0.4991860999829134
3 -0.9631340493653182
4 -1.31210809517051
5 -1.350606347491687
6 -1.5241371439455356
7 -1.5325306445865592
8 -1.3725116785839475
9 -1.47693214703785
Code executed in 5.06 s
Selected k: 1 | True k: 3
 ====== Silhouette ====== 
0 None
1 None
2 0.19510829001256025
3 0.12276877018507622
4 0.2666718402395447
5 0.31348555456323224
6 0.36558953430010227
7 0.3731558417803549
8 0.4027680246588693
9 0.4166374121873863
Code executed in 0.26 s
Selected k: 9 | True k: 3
 ====== ScoreFunction ====== 
0 None
1 0.2674380756639073
2 0.05526989678867322
3 0.03930535158636095
4 0.02794482468974735
5 0.022399044305932536
6 0.02434609671721777
7 0.01898781804203109
8 0.015903727593373773
9 0.016224624922212327
Code executed in 0.00 s
Selected k: 1 | True k: 3
 ====== MaulikBandyopadhyay_absolute ====== 
0 None
1 0.0
2 0.0001624885689488273
3 0.00011507955476191883
4 0.5826084938588393
5 0.5140899521509295
6 0.37313655054752143
7 0.43569610764369654
8 0.6956504829553489
9 0.5612754701918737
Code executed in 0.01 s
Selected k: 8 | True k: 3
 ====== SD ====== 
0 None
1 None
2 783980.3997208492
3 549586.6578302318
4 432027.73873390944
5 341231.9036186975
6 275681.20322029595
7 240429.69366993732
8 195142.12738698898
9 169718.94353532573
Code executed in 0.04 s
Selected k: 9 | True k: 3
 ====== SDbw ====== 
0 None
1 None
2 2.350951786083218
3 2.1462945100388757
4 2.7385019142539297
5 inf
6 inf
7 inf
8 inf
9 inf
Code executed in 0.01 s
Selected k: 3 | True k: 3
 ====== Dunn ====== 
0 None
1 None
2 0.22248894960242496
3 0.09930825342423276
4 0.07694370083375403
5 0.06829859591450839
6 0.06533380025087833
7 0.06397229612167823
8 0.060820685569083446
9 0.06081222025210591
Code executed in 0.01 s
Selected k: 2 | True k: 3
 ====== XB ====== 
0 None
1 None
2 3821.6310955892613
3 5646.566350558779
4 3300.5590447734985
5 2945.622749207921
6 2932.6600403937264
7 2430.4419997127675
8 1743.770908279943
9 1732.6941019304875
Code executed in 0.00 s
Selected k: 9 | True k: 3
 ====== XB_star ====== 
0 None
1 None
2 9446.229005417188
3 13957.603039842357
4 8989.974686370095
5 8641.081615403018
6 8641.081615403018
7 7751.014168430341
8 5854.809633100446
9 5854.809633100446
Code executed in 0.00 s
Selected k: 8 | True k: 3
 ====== DB ====== 
0 None
1 None
2 129.40126293281918
3 125.11207732852509
4 43.39706303619012
5 43.39706303619012
6 43.39706303619011
7 43.39706303619011
8 43.39706303619012
9 43.39706303619011
Code executed in 0.01 s
Selected k: 6 | True k: 3
 ====== Inertia_sum ====== 
0 534.4874209327967
1 349.0214135130419
2 349.0095479285938
3 349.0536409924574
4 325.43055668310694
5 303.72575042981157
6 300.60978707111775
7 272.065674157918
8 233.85530390170882
9 231.56485922473567
Code executed in 0.00 s
Selected k: 1 | True k: 3
 ====== Diameter_max ====== 
0 6.141355878094843
1 4.737154354950527
2 4.737154354950527
3 4.737154354950527
4 4.737154354950527
5 4.737154354950527
6 4.737154354950527
7 4.737154354950527
8 4.665215171139693
9 4.665215171139693
Code executed in 0.00 s
Selected k: 1 | True k: 3

 ***** Time-series data using DTW with TimeSeriesKMeans ***** 

Clusterings generated in: 36942.70s
 ================ VI ================ 
0 1.9826631670014707
1 1.9826631670014707
2 0.9862725476337011
3 0.7243010484525989
4 1.237330929069146
5 1.3997619812533943
6 1.3570255831441447
7 1.3389294718795774
8 1.7223207370640683
9 1.4718332088792603
 ====== Hartigan_monotonous ====== 
0 -56.90067754163524
1 1754.8645616800438
2 76.24579045110623
3 60.777332178599764
4 70.55253905713582
5 59.44243009173897
6 17.24531359302453
7 30.490214473246457
8 13.139952901050911
9 None
Code executed in 87.18 s
Selected k: 2 | True k: 4
 ====== CalinskiHarabasz_original ====== 
0 None
1 0.0
2 909.4945115463156
3 526.7065848162988
4 395.5252420096832
5 2887.299014971559
6 3617.452980893101
7 3479.8924124486934
8 2705.518016754376
9 3023.2852038029937
Code executed in 232.12 s
Selected k: 6 | True k: 4
 ====== GapStatistic_original ====== 
0 None
1 -0.8812998026013208
2 2.0550251089708524
3 2.6308015827781315
4 3.116701450445352
5 3.664744893974242
6 4.149193523955921
7 4.305856718860764
8 4.584264467799349
9 4.710996818049173
Code executed in 194.96 s
Selected k: None | True k: 4
 ====== Silhouette ====== 
0 None
1 None
2 0.970434561006521
3 0.8527254054088229
4 0.772910182768726
5 0.632641006687175
6 0.6462631714605184
7 0.6012197258605453
8 0.6675381038136428
9 0.6846916250623943
Code executed in 56.71 s
Selected k: 2 | True k: 4
 ====== ScoreFunction ====== 
0 None
1 0.0
2 1.0
3 0.9861827986301104
4 0.07229708923169409
5 1.0
6 1.0
7 1.0
8 1.0
9 1.0
Code executed in 279.27 s
Selected k: 2 | True k: 4
 ====== MaulikBandyopadhyay_absolute ====== 
0 None
1 0.0
2 9764539.528487094
3 40628502.56714549
4 84661918.83474743
5 166043374.10421497
6 327795828.35090786
7 333621447.2929916
8 477780406.36508566
9 519646084.2950269
Code executed in 86.60 s
Selected k: 9 | True k: 4
 ====== SD ====== 
0 None
1 None
2 1.040885406580014
3 2.099751582581919
4 1.9169986749689858
5 1.2582188484772292
6 13.059709768462964
7 11.487605447143816
8 10.681018210820302
9 13.636539621565179
Code executed in 367.50 s
Selected k: 2 | True k: 4
 ====== SDbw ====== 
0 None
1 None
2 0.037893359297291124
3 0.07126170982692477
4 0.12876852942434452
5 0.07434583296016221
6 0.20510977325582036
7 0.07577506109677666
8 inf
9 inf
Code executed in 337.02 s
Selected k: 2 | True k: 4
 ====== Dunn ====== 
0 None
1 None
2 0.8305380457449938
3 0.004488337269329974
4 0.0006448396453246943
5 0.004400722638605994
6 0.01343452835459107
7 0.014483103741398617
8 0.029457702501142203
9 0.02928860938221321
Code executed in 27.84 s
Selected k: 2 | True k: 4
 ====== XB ====== 
0 None
1 None
2 0.009145963962476508
3 0.24034419423695977
4 0.7723959360581394
5 0.26835840833683783
6 1.97865858981936
7 1.6957486989451136
8 1.2614862291683262
9 1.8988163403241916
Code executed in 103.46 s
Selected k: 2 | True k: 4
 ====== XB_star ====== 
0 None
1 None
2 0.013948302957666072
3 0.7251912448883574
4 2.6222638778606755
5 1.8423227311714532
6 2.3668587025142993
7 2.3836097954007824
8 2.741071252365762
9 3.9806998902618087
Code executed in 103.15 s
Selected k: 2 | True k: 4
 ====== DB ====== 
0 None
1 None
2 0.023029071315210144
3 2.2826228053514726
4 2.2826228053514726
5 2.4323683776149516
6 6.8076974700562705
7 6.8076974700562705
8 4.392518276020974
9 7.92718392237781
Code executed in 103.76 s
Selected k: 2 | True k: 4
 ====== Inertia_sum ====== 
0 7702.02760727836
1 8093.267386810244
2 296.40332652261225
3 512.4017882745567
4 455.40012014716064
5 84.45996762919928
6 49.81112696675366
7 42.689099666544166
8 35.9817878351014
9 37.480167570895546
Code executed in 227.01 s
Selected k: 2 | True k: 4
 ====== Diameter_max ====== 
0 147.52587026993422
1 746.9674811658102
2 272.39277521031187
3 272.39277521031187
4 272.39277521031187
5 39.913822110649264
6 12.127901842859023
7 12.127901842859023
8 6.617742410930589
9 5.301706358625468
Code executed in 45.23 s
Selected k: 5 | True k: 4

 ***** Time-series data without DTW with KMedoids ***** 

Clusterings generated in: 0.01s
 ================ VI ================ 
0 1.9826631670014707
1 1.9826631670014707
2 0.9862725476337011
3 1.4889724739808208
4 1.8023622751784476
5 2.012593203749084
6 2.1156333270601606
7 2.195785533461467
8 2.221363655227255
9 2.261767695631295
 ====== Hartigan_monotonous ====== 
0 16.44418491910634
1 180.2820962759362
2 13.302686374925614
3 3.4235009878409772
4 1.632966687870133
5 0.35567452883605943
6 0.10576421399323088
7 0.15317151376182636
8 0.014553381734068171
9 None
Code executed in 0.02 s
Selected k: 2 | True k: 4
 ====== CalinskiHarabasz_original ====== 
0 None
1 0.0
2 180.2820962759362
3 108.22514436407516
4 75.11267812946629
5 57.118096240851436
6 45.45239790464092
7 37.530421673348854
8 31.894710499865717
9 27.60747418122749
Code executed in 0.01 s
Selected k: 2 | True k: 4
 ====== GapStatistic_original ====== 
0 None
1 0.14959122676002323
2 1.1827072160132364
3 1.2955873457576423
4 1.3083599903962284
5 1.3167439352309227
6 1.3036349124355766
7 1.2943662813458108
8 1.2737223930004724
9 1.258318540961195
Code executed in 2.06 s
Selected k: 5 | True k: 4
 ====== Silhouette ====== 
0 None
1 None
2 0.5851724720291331
3 0.48653252447581946
4 0.4613796224684171
5 0.4669912349149497
6 0.3993340727577719
7 0.35145877312648655
8 0.31516469574166683
9 0.26480221494611983
Code executed in 0.11 s
Selected k: 2 | True k: 4
 ====== ScoreFunction ====== 
0 None
1 6.445205555927203e-07
2 1.0
3 1.0
4 1.0
5 1.0
6 1.0
7 0.9999640854120324
8 0.3123983899542244
9 0.035128464820290306
Code executed in 0.01 s
Selected k: 2 | True k: 4
 ====== MaulikBandyopadhyay_absolute ====== 
0 None
1 0.0
2 425.1118921667764
3 274.7198897093655
4 176.67909064991406
5 122.68231972661196
6 87.21518235383846
7 64.8064259598351
8 50.2218329579174
9 39.82038224111589
Code executed in 0.01 s
Selected k: 2 | True k: 4
 ====== SD ====== 
0 None
1 None
2 3.0428152641301534
3 2.027986494688144
4 1.5409168125687014
5 1.2942197640038466
6 1.5778535780135994
7 2.2087881792555715
8 2.6995996943695557
9 6.890284714804801
Code executed in 0.16 s
Selected k: 5 | True k: 4
 ====== SDbw ====== 
0 None
1 None
2 inf
3 0.3488568187153079
4 0.25588497890022993
5 0.19710364856552479
6 inf
7 inf
8 inf
9 inf
Code executed in 0.24 s
Selected k: 5 | True k: 4
 ====== Dunn ====== 
0 None
1 None
2 0.6502295327816004
3 0.059180301263260494
4 0.06320420480439193
5 0.03234016272068643
6 0.03234016272068643
7 0.03234016272068643
8 0.02888903375394709
9 0.02888903375394709
Code executed in 0.01 s
Selected k: 2 | True k: 4
 ====== XB ====== 
0 None
1 None
2 0.133838927267939
3 0.9627618141728497
4 1.664126478821868
5 2.9046292708600503
6 9.321747138430855
7 17.572917988163343
8 22.237603408015445
9 62.46595641498748
Code executed in 0.01 s
Selected k: 2 | True k: 4
 ====== XB_star ====== 
0 None
1 None
2 0.23315333559033175
3 1.9095790679355487
4 3.4196394895719058
5 6.072457404788166
6 19.562702855536457
7 36.921080771064474
8 46.800327831385616
9 131.48449117734995
Code executed in 0.01 s
Selected k: 2 | True k: 4
 ====== DB ====== 
0 None
1 None
2 0.7011289065432457
3 0.746218697496609
4 0.7532744692910314
5 0.721566120553927
6 1.1020445512542372
7 1.1223097180987889
8 1.123790821025426
9 1.123790821025426
Code executed in 0.01 s
Selected k: 2 | True k: 4
 ====== Inertia_sum ====== 
0 1550.7100623367241
1 1411.2211210804048
2 766.9830051666322
3 659.5101286861243
4 620.9287741703226
5 596.2228276794025
6 590.5735625679174
7 587.805078050318
8 585.1716946231384
9 584.3859312451355
Code executed in 0.01 s
Selected k: 2 | True k: 4
 ====== Diameter_max ====== 
0 26.52376778327575
1 29.63943217185524
2 26.085661705315456
3 26.085661705315456
4 26.085661705315456
5 26.085661705315456
6 26.085661705315456
7 26.085661705315456
8 26.085661705315456
9 26.085661705315456
Code executed in 0.01 s
Selected k: 2 | True k: 4