如何强制以特定的明显模式进行数据聚类?

时间:2018-09-04 19:56:50

标签: python scikit-learn data-science

我有大量的“车辆速度与发动机RPM”值。我试图预测车辆在每个档位上花费的时间。

我对数据集进行了K-Means聚类,得到以下结果: Vehicle Speed vs Engine RPM (~86000 points)

很显然,我的算法未能捕获明显的模式。我想强迫K-Means(或其他任何聚类算法)沿着六条倾斜线对数据进行聚类。相关代码段:

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from sklearn.cluster import KMeans

plt.rcParams['figure.figsize'] = (16, 9)
plt.style.use('ggplot')

# Importing the dataset
data = pd.read_csv('speedRpm.csv')
print(data.shape)
data.head()

# Getting the data points
f1 = data['rpm'].values
f2 = data['speed'].values
X = np.array(list(zip(f1, f2)))

# Number of clusters
k = 5

kmeans = KMeans(n_clusters=k)
# Fitting the input data
kmeans = kmeans.fit(X)
# Getting the cluster labels
labels = kmeans.predict(X)
# Centroid values
centroids = kmeans.cluster_centers_

labeled_array = {i: X[np.where(kmeans.labels_ == i)] for i in range(kmeans.n_clusters)}

colors = ['r', 'g', 'b', 'y', 'c']
fig, ax = plt.subplots()
for i in range(k):
        points = np.array([X[j] for j in range(len(X)) if kmeans.labels_[j] == i])
        ax.scatter(points[:, 0], points[:, 1], s=7, c=colors[i])
ax.scatter(centroids[:, 0], centroids[:, 1], marker='*', s=200, c='#050505')

plt.show()

即使它可能不是最有效的,我如何确保聚类算法捕获正确的模式?

谢谢!

编辑

这次使用DBSCAN运行相同的点集。在使用epsmin_samples值一段时间后,得到以下结果:

enter image description here

尽管仍然不够完美,并且离群值太多,但是该算法开始捕获线性趋势。

代码:

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from sklearn.cluster import KMeans
from sklearn.cluster import DBSCAN

plt.rcParams['figure.figsize'] = (16, 9)
plt.style.use('ggplot')

# Importing the dataset
data = pd.read_csv('speedRpm.csv')
print(data.shape)
data.head()

# Getting the values and plotting it
f1 = data['rpm'].values
f2 = data['speed'].values
X = np.array(list(zip(f1, f2)))

# DBSCAN

# Compute DBSCAN
db = DBSCAN(eps=1.1, min_samples=3).fit(X)
core_samples_mask = np.zeros_like(db.labels_, dtype=bool)
core_samples_mask[db.core_sample_indices_] = True
labels = db.labels_

# Number of clusters in labels, ignoring noise if present.
n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0)
print "Estimated Number of Clusters", n_clusters_

# Black removed and is used for noise instead.
unique_labels = set(labels)
colors = [plt.cm.Spectral(each)
          for each in np.linspace(0, 1, len(unique_labels))]
for k, col in zip(unique_labels, colors):
    if k == -1:
        # Black used for noise.
        col = [0, 0, 0, 1]

    class_member_mask = (labels == k)

    xy = X[class_member_mask & core_samples_mask]
    plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=tuple(col),
             markeredgecolor='k', markersize=14)

    xy = X[class_member_mask & ~core_samples_mask]
    plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=tuple(col),
             markeredgecolor='k', markersize=6)

plt.title('Estimated number of clusters: %d' % n_clusters_)
plt.show()

3 个答案:

答案 0 :(得分:2)

高级别

这里有两个主要选项:

  1. 转换数据,以使k-means样式的聚类算法成功
  2. 选择其他算法

次要选项:

  1. 通过强制初始化更加智能来调整kmeans

选项2

Python很好地描述了几种聚类算法here。在链接中,有一个(粗略裁剪的)有用的图形:

enter image description here

此行看起来与您的数据集相似;您是否尝试过高斯混合模型? GMM几乎没有众所周知的理论属性,但是它是根据根据数据计算出的后验来分配属于每个聚类中心的点的概率而起作用的。您通常可以使用kmeans对其进行初始化,Sklearn会为您进行初始化。

类似地,基于Desity的聚类算法(例如DBSCAN)似乎是一种逻辑选择。您的数据对密集群集进行了很好的分割,这似乎是要过滤的良好拓扑属性。在链接的维基百科页面上的图像中:

enter image description here

他们提供了标题:

  

DBSCAN可以找到非线性可分离的簇。该数据集不能   与k均值充分聚类

这似乎说明您遇到了麻烦。


有关麻烦的更多信息

Kmeans是一种用途非常广泛的算法,但是它并不是全局最优的,并且存在很多弱点。 Here is dense reading

除了mickey mouse problem之类的问题外,kmeans经常尝试最小化到质心的简单欧几里得距离。尽管这对于许多问题来说很有意义,但在您的问题中却没有意义,因为集群的偏斜意味着这不是正确的措施。请注意,上面显示的诸如聚集/层次聚类之类的其他算法使用相似的度量,也具有相似的陷阱。

我没有介绍如何转换数据或调整kmeans,因为后者实际上需要侵入(或编写自己的)集群算法(鉴于sklearn和类似软件包的覆盖范围,我不建议针对一个简单的探索性问题),前者似乎是对您的确切数据敏感的本地解决方案。 ICA可能是一个不错的开始,但是该任务有很多选择

答案 1 :(得分:2)

k均值(以及@ en-knight答案中引用的其他聚类算法)旨在用于多维数据,这些数据倾向于具有彼此“接近”(根据欧几里得距离)的数据点组。 ,但在空间上分开。

在您的情况下,如果在未处理的输入空间(rpm与速度)中考虑数据,则形成的“簇”会非常伸长,并且在(0,0)附近的区域会大量重叠,因此如果没有,所有基于欧氏距离的方法注定会失败。

您的数据实际上并不是6个在空间上分开的2维点组。相反,它实际上是6种可能的线性趋势的组合。

因此,分组应基于x / y(齿轮比)。它是一维的:每对(rpm,速度)对应一个单一的(rpm /速度)值,并且您希望将它们分组。

我不知道k均值(或其他算法)是否可以获取一维数据集,但是如果不能,则可以创建一个具有[0,rpm / vel]对的新数组并运行通过它。

您可能想寻找一种比多维通用算法更有效的一维算法。

这将使图形标记更加复杂,因为分组是基于与原始数据(2个样本)形状不同(1个样本)而形状不同(1个样本)的派生数据集计算的,但映射它们是很难。

答案 2 :(得分:0)

您可以将y值乘以10或更大的倍数,以便它们沿该轴分布。确保跟踪使用的是实数值还是乘数值。