Разделение k-средних значений пополам - это гибридный подход между разделенной иерархической кластеризацией (кластеризация сверху вниз) и кластеризацией K-средних. Вместо разделения набора данных на K кластеров на каждой итерации, алгоритм деления пополам k-средних разбивает один кластер на два подкластера на каждом шаге деления пополам (с использованием k-средних) до тех пор, пока не будут получены k кластеров.
Разделительная иерархическая кластеризация
Разделительная кластеризация начинается на верхнем уровне с одного кластера и делит его на нижний уровень. Чтобы решить, какие кластеры следует разделить, необходима мера несходства между наборами наблюдений. Это достигается за счет использования меры расстояния между парами наблюдений.
Как работают биссектрисы К-средних
- Установите K, чтобы определить количество кластеров.
- Установить все данные как единый кластер
3. Используйте K-means с K = 2, чтобы разбить кластер.
4. Измерьте расстояние для каждого внутреннего кластера.
- Сумма квадратов расстояния
5. Выберите кластер с наибольшим расстоянием и разделите его на 2 кластера с помощью K-средних.
6. Повторяйте шаги 3–5, пока количество кластеров листьев не будет равно K.
Последний кластер - это кластер [C, D, E, F]
Выполнение
Определить функцию
"""Implementation of k-means clustering algorithm. These functions are designed to work with cartesian data points """ import pandas as pd import numpy as np from matplotlib import pyplot as plt def convert_to_2d_array(points): """ Converts `points` to a 2-D numpy array. """ points = np.array(points) if len(points.shape) == 1: points = np.expand_dims(points, -1) return points def visualize_clusters(clusters): """ Visualizes the first 2 dimensions of the data as a 2-D scatter plot. """ plt.figure() for cluster in clusters: points = convert_to_2d_array(cluster) if points.shape[1] < 2: points = np.hstack([points, np.zeros_like(points)]) plt.plot(points[:,0], points[:,1], 'o') plt.show() def SSE(points): """ Calculates the sum of squared errors for the given list of data points. """ points = convert_to_2d_array(points) centroid = np.mean(points, 0) errors = np.linalg.norm(points-centroid, ord=2, axis=1) return np.sum(errors) def kmeans(points, k=2, epochs=10, max_iter=100, verbose=False): """ Clusters the list of points into `k` clusters using k-means clustering algorithm. """ points = convert_to_2d_array(points) assert len(points) >= k, "Number of data points can't be less than k" best_sse = np.inf for ep in range(epochs): # Randomly initialize k centroids np.random.shuffle(points) centroids = points[0:k, :] last_sse = np.inf for it in range(max_iter): # Cluster assignment clusters = [None] * k for p in points: index = np.argmin(np.linalg.norm(centroids-p, 2, 1)) if clusters[index] is None: clusters[index] = np.expand_dims(p, 0) else: clusters[index] = np.vstack((clusters[index], p)) # Centroid update centroids = [np.mean(c, 0) for c in clusters] # SSE calculation sse = np.sum([SSE(c) for c in clusters]) gain = last_sse - sse if verbose: print((f'Epoch: {ep:3d}, Iter: {it:4d}, ' f'SSE: {sse:12.4f}, Gain: {gain:12.4f}')) # Check for improvement if sse < best_sse: best_clusters, best_sse = clusters, sse # Epoch termination condition if np.isclose(gain, 0, atol=0.00001): break last_sse = sse return best_clusters def bisecting_kmeans(points, k=2, epochs=10, max_iter=100, verbose=False): """ Clusters the list of points into `k` clusters using bisecting k-means clustering algorithm. Internally, it uses the standard k-means with k=2 in each iteration. """ points = convert_to_2d_array(points) clusters = [points] while len(clusters) < k: max_sse_i = np.argmax([SSE(c) for c in clusters]) cluster = clusters.pop(max_sse_i) two_clusters = kmeans( cluster, k=2, epochs=epochs, max_iter=max_iter, verbose=verbose) clusters.extend(two_clusters) return clusters
Основной код
# Import the data df = pd.read_csv('Mall_Customers.csv') df = df[['Annual Income (k$)','Spending Score (1-100)']] points = np.array(df.values.tolist()) # algorithm = kmeans algorithm = bisecting_kmeans k = 5 verbose = False max_iter = 1000 epochs = 10 clusters = algorithm( points=points, k=k, verbose=verbose, max_iter=max_iter, epochs=epochs) visualize_clusters(clusters)
Преимущество использования B-Kmeans перед Kmeans
- Деление k-средних пополам более эффективно, когда K велико.
Для алгоритма kmeans вычисление включает каждую точку данных набора данных и k центроидов. С другой стороны, на каждом шаге деления пополам к-средних пополам в вычислении участвуют только точки данных одного кластера и двух центроидов. Таким образом сокращается время вычислений. - Деление k-средних пополам дает кластеры одинакового размера, в то время как k-среднее, как известно, дает кластеры самых разных размеров.