更新:
我设法解决了整个索引,包括上面的原始问题。
事实证明,我不需要找到分母本身,而是只需要计算从点到每个聚类的距离矩阵。
那么,最小的距离与分子有关,次小与分母有关。
之后,WG 指数的计算就很简单了。
支持代码:
def wemmert_gancarski_index(X, labels, n_clusters=None, min_nc=None):
"""
The Wemmert-Gancarski Index, a measure of compactness.
The W-G index is built using the quotients of distances between the points and the barycenters
of all of the clusters.
If the mean of the quotient is greater than :math:`1`, it is ignored, thus it is a weighted mean.
**Maximum value** indicates the optimal number of clusters.
Parameters
----------
X : array-like or dataframe, with **shape:** *(n_samples, n_features)*
An array / dataframe of observations used to compute the W-G index.
labels : array-like, with **shape:** *(n_samples,)*
An array / list of labels represented by integers.
n_clusters : int, optional
The number of clusters to compute the index for.
Returns
-------
The Wemmert-Gancarski Index.
$
"""
# Checking for valid inputs:
def check(labels, n_clusters=None, min_nc=None):
if n_clusters is None and (
isinstance(labels, np.ndarray) or isinstance(labels, pd.DataFrame)) and min_nc is None:
use_labels = labels
return use_labels
elif isinstance(labels, list) and n_clusters is not None and min_nc is not None:
use_labels = self.get_labels(labels, n_clusters=n_clusters, min_nc=min_nc, need="Single")
use_labels = np.asarray(use_labels)
return use_labels
else:
raise ValueError(f"Please provide either an array of labels (without the other arguments) "
f"or (a list of labels, K, min_nc)")
use_labels = check(labels, n_clusters=n_clusters, min_nc=min_nc)
# Calculate the distance between each point and a cluster's centroid, given a dataframe and labels:
def dist_from_centroid(X, labels):
centroids = centers2(X, labels)
# Get the distance from each point to each centroid:
distances = cdist(X, centroids, metric='euclidean')
return distances
dists = dist_from_centroid(X, use_labels)
dists
intra, inter = [], []
for row in dists:
inter.append(sorted(row)[1]) # Get the second smallest distance
intra.append(np.min(row)) # Get the smallest distance
# Compute the quotient of distances between each point and a cluster's centroid:
RM = np.divide(intra, inter)
# Given a vector of shape (n_samples, 1) and the size of each cluster, nk, return a new array of shape (n_samples / nk, nk):
def chunk(vec, chunk_size):
return np.array([vec[i:i + chunk_size] for i in range(0, len(vec), chunk_size)])
nk = len(np.unique(use_labels))
RMi = chunk(RM, nk)
# Compute 1 - the mean of the quotient of distances between each point and a cluster's centroid:
meanDiff = 1 - np.mean(RMi.transpose(), axis=1)
# Only select the values greater than 0:
Jk = meanDiff[meanDiff > 0]
WG = np.sum([i * j for i, j in zip(np.bincount(use_labels), Jk)]) / len(use_labels)
return WG
事实证明,答案只需要从不同的角度看商,其他一切都到位了。