BI - Beale Index
The Beale Index (BI) is an internal clustering evaluation metric based on the statistical F-test [43]. It compares the sum of squared errors of a partition with \(K\) clusters against a partition with \(K-1\) clusters (or the overall center) to determine if splitting the data into more clusters significantly reduces the unexplained variance.
Intuitively, BI answers the question: “Does splitting the data into K clusters provide a statistically significant reduction in variance compared to treating the dataset as a single group?” A smaller BI score indicates a better clustering partition.
Where:
\(N\) is the total number of data points (samples).
\(K\) is the total number of clusters.
\(\text{WGSS}\) is the pooled Within-Group Sum of Squares (unexplained variance), identical to \(\text{Tr}(WG)\).
\(\text{BGSS}\) is the Between-Group Sum of Squares (explained variance), identical to \(\text{Tr}(BG)\).
The numerator represents the Mean Square Within (\(MS_W\)).
The denominator represents the Mean Square Between (\(MS_B\)).
Handling Edge Cases (Finite Values)
The calculation of the Beale Index requires at least two clusters (\(K \ge 2\)) to evaluate the between-group degrees of freedom (\(K - 1\)). When evaluated on a single cluster (\(K = 1\)), the denominator evaluates to zero, making the ratio mathematically undefined.
force_finite (bool): If
True, the function catches the undefined division operation when \(K = 1\) and returns a safe fallback value. Default isTrue.finite_value (float): The specific fallback value returned when
force_finite=True. Since a smaller score is better for BI, the default fallback is a large penalty value (1e10).
Properties
Best possible score:
0.0(Smaller value is better, indicating optimal cluster compactness relative to separation).Worst possible score:
+inf(or the defined penaltyfinite_value).Range:
[0.0, +inf)
Example Usage
from permetrics.clustering import ClusteringMetric
import numpy as np
# ==============================================================================
# SCENARIO 1: Basic Evaluation
# ==============================================================================
print("--- 1. BASIC BEALE INDEX EXAMPLE ---")
X_data = np.array([[1, 2], [1, 4], [1, 0], [10, 2], [10, 4], [10, 0]])
y_pred_labels = np.array([0, 0, 0, 1, 1, 1])
cm = ClusteringMetric(X=X_data, y_pred=y_pred_labels)
bi_score = cm.BI()
print(f"Beale Index: {bi_score}")
# ==============================================================================
# SCENARIO 2: Edge Case with 1 Cluster
# ==============================================================================
print("\n--- 2. EDGE CASE (1 CLUSTER) EXAMPLE ---")
y_pred_single = np.array([0, 0, 0, 0, 0, 0])
cm_single = ClusteringMetric(X=X_data, y_pred=y_pred_single)
# Returns the penalty finite_value (1e10) instead of crashing
bi_safe = cm_single.BI(force_finite=True, finite_value=1e10)
print(f"BI with 1 cluster (Safe Mode): {bi_safe}")