第十六天 Kmean聚类

2018-12-22  本文已影响23人  未不明不知不觉

我们前面说过, 聚类(clustering)是将数据集划分成组的任务,这些组叫作簇(cluster)。.其目标是划分数据,使得一个簇内的数据点非常相似且不同簇内的数据点非常不同。与分类算法类似,聚类算法为每个数据点分配(或预测)一个数字,表示这个点属于哪个簇

k均值聚类

k 均值聚类是最简单也最常用的聚类算法之一。它试图找到代表数据特定区域的簇中心(cluster center)。算法交替执行以下两个步骤:将每个数据点分配给最近的簇中心,然后将每个簇中心设置为所分配的所有数据点的平均值。如果簇的分配不再发生变化,那么算法结束。

km.png

簇中心用三角形表示,而数据点用圆形表示。颜色表示簇成员。我们指定要寻找三个簇,所以通过声明三个随机数据点为簇中心来将算法初始化(见图中“Initialization” /“初始化”)。然后开始迭代算法。首先,每个数据点被分配给距离最近的簇中心(见图中“Assign Points (1)” /“分配数据点(1)”)。接下来,将簇中心修改为所分配点的平均值(见图中“Recompute Centers (1)” /“重新计算中心(1)”)。然后将这一过程再重复两次。在第三次迭代之后,为簇中心分配的数据点保持不变,因此算法结束。

使用sklearn进行k均值算法

用 scikit-learn 应用 k 均值相当简单。下面我们将其应用于上图中的模拟数据。我们将KMeans 类实例化,并设置我们要寻找的簇个数 3。然后对数据调用 fit 方法 :

from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans

X,y = make_blobs(random_state=1)

首先我们来查看生成的数据的可视化图形

import matplotlib.pyplot as plt
plt.scatter(x=X[:,0],y=X[:,1],c=y)

得到下面的可视化图形

我们可以看出来生成的数据为三个簇,那么们使用sklearn自带的kmean算法来对数据进行聚类

X,y = make_blobs(random_state=1)
kmeans = KMeans(n_clusters=3)
kmeans.fit(X)
labels = kmeans.labels_

我们使用kmean算法得到的label来查看我们得到的聚类效果

可以看出我们正确的分出了三个类,聚类效果很好。可以看到,聚类算法与分类算法有些相似,每个元素都有一个标签。但并不存在真实的标签,因此标签本身并没有先验意义

我们可以尝试画出聚类后的数据的簇心

mglearn.discrete_scatter(X[:, 0], X[:, 1], kmeans.labels_, markers='o')
mglearn.discrete_scatter(
kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], [0, 1, 2],
markers='^', markeredgewidth=2)

我们得到下面的图片

当然我们生成的数据是三个簇,kmeans算法也选的三个簇心,看起来有点碰巧了,我们可以选择不同的簇心数量来对数据进行聚类,例如选择2个簇心和5个簇心

fig, axes = plt.subplots(1, 2, figsize=(10, 5))
# 使用2个簇中心:
kmeans = KMeans(n_clusters=2)
kmeans.fit(X)
assignments = kmeans.labels_
mglearn.discrete_scatter(X[:, 0], X[:, 1], assignments, ax=axes[0])
# 使用5个簇中心:
kmeans = KMeans(n_clusters=5)
kmeans.fit(X)
assignments = kmeans.labels_
mglearn.discrete_scatter(X[:, 0], X[:, 1], assignments, ax=axes[1])

那么我们会得出下面的结果

k均值的局限

即使你知道给定数据集中簇的“正确”个数, k 均值可能也不是总能找到它们。每个簇仅由其中心定义,这意味着每个簇都是凸形(convex)。因此, k 均值只能找到相对简单的形状。 k 均值还假设所有簇在某种程度上具有相同的“直径”,它总是将簇之间的边界刚好画在簇中心的中间位置。有时这会导致令人惊讶的结果

X_varied, y_varied = make_blobs(n_samples=200,
cluster_std=[1.0, 2.5, 0.5],
random_state=170)
y_pred = KMeans(n_clusters=3, random_state=0).fit_predict(X_varied)
mglearn.discrete_scatter(X_varied[:, 0], X_varied[:, 1], y_pred)
plt.legend(["cluster 0", "cluster 1", "cluster 2"], loc='best')
plt.xlabel("Feature 0")
plt.ylabel("Feature 1")

我们得到下面的聚类结果

我们发现类0和类1都有一些远离簇的偏离点,k 均值还假设所有方向对每个簇都同等重要。图 3-28 显示了一个二维数据集,数据中包含明确分开的三部分。但是这三部分被沿着对角线方向拉长。由于 k 均值仅考虑到最近簇中心的距离,所以它无法处理这种类型的数据

其他的例子

bar状不规则形状

X, y = make_blobs(random_state=170, n_samples=600)
rng = np.random.RandomState(74)
# 变换数据使其拉长
transformation = rng.normal(size=(2, 2))
X = np.dot(X, transformation)
# 将数据聚类成3个簇
kmeans = KMeans(n_clusters=3)
kmeans.fit(X)
y_pred = kmeans.predict(X)
# 画出簇分配和簇中心
plt.scatter(X[:, 0], X[:, 1], c=y_pred, cmap=mglearn.cm3)
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1],
marker='^', c=[0, 1, 2], s=100, linewidth=2, cmap=mglearn.cm3)
plt.xlabel("Feature 0")
plt.ylabel("Feature 1")

得到下面的聚类结果

半月形数据

# 生成模拟的two_moons数据(这次的噪声较小)
from sklearn.datasets import make_moons
X, y = make_moons(n_samples=200, noise=0.05, random_state=0)
# 将数据聚类成2个簇
kmeans = KMeans(n_clusters=2)
kmeans.fit(X)
y_pred = kmeans.predict(X)
# 画出簇分配和簇中心
plt.scatter(X[:, 0], X[:, 1], c=y_pred, cmap=mglearn.cm2, s=60)
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1],
marker='^', c=[mglearn.cm2(0), mglearn.cm2(1)], s=100, linewidth=2)
plt.xlabel("Feature 0")
plt.ylabel("Feature 1")

参考

1.k均值聚类失效的例子

上一篇 下一篇

猜你喜欢

热点阅读