当我们讨论k-means算法时, 我们看到我们必须给出簇数作为输入参数之一. 在现实世界中, 我们不会提供这些信息. 我们绝对可以扫描参数空间, 使用轮廓系数得分找出最佳聚类数, 但这将是一个昂贵的过程! 如果有一种方法可以告诉我们数据中的集群数量, 那不是很好吗? 这就是噪声应用(DBSCAN)的基于密度的空间聚类.

这通过将数据点视为密集群组来实现. 如果一个点属于一个集群, 则应该有很多属于同一个集群的其他点, 我们可以控制的一个参数是这个点与其他点的最大距离 这被称为epsilon. 特定集群中的两点不应超过epsilon. 您可以在http://staffwww.itn.liu.se/~aidvi/courses/06/dm/Seminars2011/DBSCAN(4).pdf上了解更多信息. 这种方法的主要优点之一是它可以处理异常值. 如果在低密度区域中有一些点, DBSCAN将会将这些点作为异常值来检测,而不是将其强制为集群.

怎么做...?

  • 这个食谱的完整代码在estimate_clusters.py文件. 我们来看看它是如何构建的. 创建一个新的Python文件, 并导入必需的包:
from itertools import cycle

import numpy as np
from sklearn.cluster import DBSCAN
from sklearn import metrics
import matplotlib.pyplot as plt

from utilities import load_data
  • 导入数据:
input_file = 'data_perf.txt'
X = load_data(input_file)
  • 我们需要找到最好的参数. 我们来初始化一些变量:
# Find the best epsilon
eps_grid = np.linspace(0.3, 1.2, num=10)
silhouette_scores = []
eps_best = eps_grid[0]
silhouette_score_max = -1
model_best = None
labels_best = None
  • 让我们扫描参数空间
for eps in eps_grid:
    # Train DBSCAN clustering model
    model = DBSCAN(eps=eps, min_samples=5).fit(X)

    # Extract labels
    labels = model.labels_

    # Extract performance metric
    silhouette_score = round(metrics.silhouette_score(X, labels), 4)
    silhouette_scores.append(silhouette_score)

    print ("Epsilon:", eps, " --> silhouette score:", silhouette_score)

    if silhouette_score > silhouette_score_max:
        silhouette_score_max = silhouette_score
        eps_best = eps
        model_best = model
        labels_best = labels
  • 我们来绘制柱状图
# Plot silhouette scores vs epsilon
plt.figure()
plt.bar(eps_grid, silhouette_scores, width=0.05, color='k', align='center')
plt.title('Silhouette score vs epsilon')

# Best params
print ("Best epsilon =", eps_best)
  • 让我们存储最好的模型和标签
# Associated model and labels for best epsilon
model = model_best
labels = labels_best
  • 某些数据点可能仍未分配. 我们需要识别它们, 如下所示:
# Check for unassigned datapoints in the labels
offset = 0
if -1 in labels:
    offset = 1
  • 提取集群的数量
# Number of clusters in the data
num_clusters = len(set(labels)) - offset

print ("Estimated number of clusters =", num_clusters)
  • 我们需要提取所有核心样品:
# Extracts the core samples from the trained model
mask_core = np.zeros(labels.shape, dtype=np.bool)
mask_core[model.core_sample_indices_] = True
  • 我们来看看结果集. 我们将首先提取一组唯一标签并指定不同的标记:
# Plot resultant clusters
plt.figure()
labels_uniq = set(labels)
markers = cycle('vo^s<>')
  • 我们迭代集群, 并使用不同的标记绘制数据点:
for cur_label, marker in zip(labels_uniq, markers):
    # Use black dots for unassigned datapoints
    if cur_label == -1:
        marker = '.'

    # Create mask for the current label
    cur_mask = (labels == cur_label)

    cur_data = X[cur_mask & mask_core]
    plt.scatter(
        cur_data[:, 0],
        cur_data[:, 1],
        marker=marker,
        edgecolors='black',
        s=96,
        facecolors='none'
    )

    cur_data = X[cur_mask & ~mask_core]
    plt.scatter(
        cur_data[:, 0],
        cur_data[:, 1],
        marker=marker,
        edgecolors='black',
        s=32
    )

plt.title('Data separated into clusters')
plt.show()
  • 运行代码会得到如下结果:

  • 柱状图如下:

  • 我们来看看标记的数据点以及未分配的数据点, 如下图所示:

results matching ""

    No results matching ""