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"
***** Non time-series data with KMeans *****
Clusterings generated in: 0.23s
================ VI ================
0 1.5095732725667173
1 1.5095732725667173
2 2.1467706655447474
3 2.515266501864858
4 2.4529092914622925
5 2.173861341607296
6 2.228407965298685
7 2.060493187913537
8 1.8688566322241682
9 1.9671048256256727
====== Hartigan_monotonous ======
0 228.7205789923083
1 119.56923880154238
2 117.42068546623949
3 76.80153548101077
4 93.9137889342267
5 52.06040306154568
6 58.425647923022126
7 60.66524064785683
8 57.640839629380906
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.45128212587218
5 165.93940697725336
6 166.21920620513873
7 175.40163822518565
8 189.7310206301877
9 205.53318021541008
Code executed in 0.00 s
Selected k: 9 | True k: 3
====== GapStatistic_original ======
0 None
1 0.006879406324998172
2 -0.1837300820529375
3 -0.299340515577712
4 -0.48593683178013247
5 -0.3997451769541769
6 -0.4478325055623875
7 -0.449369265776979
8 -0.40892256055038123
9 -0.3574284457977064
Code executed in 1.28 s
Selected k: 1 | True k: 3
====== Silhouette ======
0 None
1 None
2 0.2933768469613197
3 0.31259123245038284
4 0.3453434835780881
5 0.3728295849783575
6 0.4036635131177208
7 0.4135421231835523
8 0.4275506064637222
9 0.4572984487131393
Code executed in 0.32 s
Selected k: 9 | True k: 3
====== ScoreFunction ======
0 None
1 0.2674380756639073
2 0.1541968037562551
3 0.08425097006376447
4 0.04509056773085984
5 0.02589777025200779
6 0.019025099894251163
7 0.014521354651049201
8 0.010364737428136706
9 0.010631945855383629
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.814973474216045
5 1.589394825197374
6 1.8036213914541643
7 1.6897656557345335
8 1.597677636090917
9 1.658219974948295
Code executed in 0.01 s
Selected k: 4 | True k: 3
====== SD ======
0 None
1 None
2 441728.4898442268
3 310275.2846361639
4 282227.6163142389
5 251685.6518789486
6 188975.40856384803
7 165599.55355064312
8 159657.1340200874
9 121239.8784273011
Code executed in 0.06 s
Selected k: 9 | True k: 3
====== SDbw ======
0 None
1 None
2 1.82006477611026
3 1.8280466583013388
4 1.0782910518290005
5 0.862340673656129
6 0.6599271157994484
7 0.5137422393966522
8 0.4315409503710267
9 0.3509760746187338
Code executed in 0.02 s
Selected k: 9 | True k: 3
====== Dunn ======
0 None
1 None
2 0.017042923961732886
3 0.015506094539212548
4 0.020380032189610788
5 0.025414698502604253
6 0.04052950663934442
7 0.028717067530636523
8 0.03243000883323076
9 0.0374847548924401
Code executed in 0.01 s
Selected k: 6 | True k: 3
====== XB ======
0 None
1 None
2 0.5659598687639614
3 0.3695518574219425
4 0.35077778031324125
5 0.26228181959635466
6 0.23088220415369637
7 0.4738881988438514
8 0.3991271417966389
9 0.3160187408461631
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.4381233069841455
5 0.4082216548961064
6 0.3223618732103292
7 0.7650010113710408
8 0.7442185787686729
9 0.5460620812605709
Code executed in 0.00 s
Selected k: 6 | True k: 3
====== DB ======
0 None
1 None
2 inf
3 inf
4 inf
5 inf
6 inf
7 inf
8 inf
9 inf
Code executed in 0.00 s
Selected k: None | True k: 3
====== Inertia_sum ======
0 529.5057244941397
1 349.0214135130419
2 305.51326679993497
3 268.3822961903845
4 238.7632099303106
5 209.39029801402705
6 195.81587150191075
7 175.11795942141643
8 157.5902497573469
9 146.08738472788326
Code executed in 0.00 s
Selected k: 1 | True k: 3
====== Diameter_max ======
0 6.142845897345817
1 4.737154354950527
2 4.665215171139693
3 3.858736585127345
4 3.442257484635432
5 3.128461564031899
6 2.5235271795281573
7 2.54835120455792
8 2.595285468655654
9 2.245316286974912
Code executed in 0.00 s
Selected k: 1 | True k: 3
***** Non time-series data with AgglomerativeClustering-Single *****
Clusterings generated in: 0.01s
================ 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 230.80193090705052
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.01 s
Selected k: 8 | True k: 3
====== GapStatistic_original ======
0 None
1 -0.018261377731080053
2 -0.5046252580908837
3 -0.9755468823121172
4 -1.317063091411665
5 -1.3691091292918625
6 -1.5570611975206923
7 -1.5456323276893205
8 -1.3828877686969427
9 -1.5099285813702488
Code executed in 1.64 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.46 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.01 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.09 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.02 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.01 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.01 s
Selected k: 8 | True k: 3
====== DB ======
0 None
1 None
2 inf
3 inf
4 inf
5 inf
6 inf
7 inf
8 inf
9 inf
Code executed in 0.01 s
Selected k: None | True k: 3
====== Inertia_sum ======
0 529.6445704157419
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.2315059886439235
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: 9894.26s
================ VI ================
0 1.9826631670014707
1 1.9826631670014707
2 0.9862725476337011
3 0.7243010484525989
4 0.9059025939933596
5 1.4683583675989356
6 1.3506039172634514
7 1.352202495054755
8 1.5140199794152842
9 1.4950295668904539
====== Hartigan_monotonous ======
0 -56.818194676749684
1 1754.8645616800438
2 76.24579045110623
3 32.73778465388076
4 97.97405429874684
5 61.16940276393863
6 11.232006351909295
7 24.744495242956393
8 28.108321971579567
9 None
Code executed in 28.96 s
Selected k: 2 | True k: 4
====== CalinskiHarabasz_original ======
0 None
1 0.0
2 1754.085447852665
3 1433.539675966072
4 1594.4130233481558
5 1617.6128582464828
6 1561.876806382158
7 2766.2312652110304
8 2317.6577104872495
9 2621.4051464359554
Code executed in 37.36 s
Selected k: 7 | True k: 4
====== GapStatistic_original ======
0 None
1 -0.8815434902967079
2 2.0539656312014776
3 2.6262982870506173
4 2.9142803400516994
5 3.6176716320507127
6 4.113737844217154
7 4.218018562858955
8 4.449122122425781
9 4.70584785019112
Code executed in 158.67 s
Selected k: None | True k: 4
====== Silhouette ======
0 None
1 None
2 0.970434561006521
3 0.8527254054088229
4 0.6342053634716809
5 0.6244998063072048
6 0.6393333360822521
7 0.7468433685214771
8 0.6397466370513066
9 0.6871614438034362
Code executed in 23.01 s
Selected k: 2 | True k: 4
====== ScoreFunction ======
0 None
1 0.0
2 1.0
3 1.0
4 1.0
5 1.0
6 1.0
7 1.0
8 1.0
9 1.0
Code executed in 46.42 s
Selected k: 2 | True k: 4
====== MaulikBandyopadhyay_absolute ======
0 None
1 0.0
2 13570219.549174054
3 17417652.449314255
4 29238758.35758577
5 115793577.75891587
6 248302404.67389372
7 211776063.4936969
8 280990949.9962046
9 447124175.8520936
Code executed in 26.04 s
Selected k: 9 | True k: 4
====== SD ======
0 None
1 None
2 1.2933347837618612
3 0.8723177381652063
4 2.442758532719365
5 1.6331156631390882
6 1.6204115467847622
7 0.7410286454387737
8 2.585299187199769
9 2.9541602694920193
Code executed in 75.32 s
Selected k: 7 | True k: 4
====== SDbw ======
0 None
1 None
2 0.047171971054305324
3 0.028330098513020513
4 0.021431588812631117
5 inf
6 0.051771991788518164
7 inf
8 inf
9 inf
Code executed in 58.33 s
Selected k: 4 | True k: 4
====== Dunn ======
0 None
1 None
2 0.8305380457449938
3 0.004488337269329974
4 0.004537116488733659
5 0.004486536318569252
6 0.009747978220378454
7 0.015622169774173958
8 0.017549819906086672
9 0.03203081948987781
Code executed in 10.29 s
Selected k: 2 | True k: 4
====== XB ======
0 None
1 None
2 0.013293449506085436
3 0.12378343790297791
4 0.894377090972192
5 0.6328022598686993
6 0.49863124018387817
7 0.10374239835875182
8 0.5003405717615647
9 0.48462570048437076
Code executed in 21.82 s
Selected k: 2 | True k: 4
====== XB_star ======
0 None
1 None
2 0.024136782030059964
3 0.319786471287527
4 2.655663919096876
5 2.187569531148944
6 1.6243286027215955
7 0.1796721891431431
8 1.842587363265394
9 1.0530214495612893
Code executed in 23.39 s
Selected k: 2 | True k: 4
====== DB ======
0 None
1 None
2 inf
3 inf
4 inf
5 inf
6 inf
7 inf
8 inf
9 inf
Code executed in 21.31 s
Selected k: None | True k: 4
====== Inertia_sum ======
0 7635.026651691698
1 11346.458540247657
2 507.8773337544358
3 298.28457577945136
4 180.91363688381068
5 142.47725101218637
6 117.24808582866349
7 55.410629776831215
8 56.15831427552126
9 44.165879750081636
Code executed in 27.90 s
Selected k: 2 | True k: 4
====== Diameter_max ======
0 145.60611740648966
1 746.9674811658102
2 272.39277521031187
3 272.39277521031187
4 42.9663835289349
5 38.652638553616875
6 15.357934963087844
7 11.243614881589929
8 8.936599924012118
9 5.290910999624499
Code executed in 16.00 s
Selected k: 4 | 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.11563332706016
7 2.195785533461467
8 2.221363655227255
9 2.261767695631295
====== Hartigan_monotonous ======
0 16.814378195979476
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.03 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.15471659179450015
2 1.1801480262204151
3 1.2881566203008727
4 1.3106012672251133
5 1.309377861730166
6 1.2982462582865022
7 1.2833032755252685
8 1.27191560884566
9 1.2532835609531165
Code executed in 23.11 s
Selected k: 4 | 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.26 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.02 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.02 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.28 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.36 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.02 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 inf
3 inf
4 inf
5 inf
6 inf
7 inf
8 inf
9 inf
Code executed in 0.01 s
Selected k: None | True k: 4
====== Inertia_sum ======
0 1546.9872994810112
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.49002457065253
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.02 s
Selected k: 2 | True k: 4