Python 如何强制以特定模式对数据进行聚类?
我有一大套“车速与发动机转速”的车辆值。我试图预测车辆在每个档位上花费的时间 我在数据集上运行了K-Means聚类,得到了以下结果: 显然,我的算法未能捕捉到明显的模式。我想强制K-Means(或任何其他聚类算法)沿着六条倾斜线对数据进行聚类。相关代码片段:Python 如何强制以特定模式对数据进行聚类?,python,scikit-learn,data-science,Python,Scikit Learn,Data Science,我有一大套“车速与发动机转速”的车辆值。我试图预测车辆在每个档位上花费的时间 我在数据集上运行了K-Means聚类,得到了以下结果: 显然,我的算法未能捕捉到明显的模式。我想强制K-Means(或任何其他聚类算法)沿着六条倾斜线对数据进行聚类。相关代码片段: import numpy as np import pandas as pd from matplotlib import pyplot as plt from sklearn.cluster import KMeans plt.rcP
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运行相同的点集。在对eps
和min\u样本
值进行了一段时间的反复试验后,得到以下结果:
尽管仍然不够完美,而且异常值太多,但该算法开始捕捉线性趋势
代码:
您可以将y值乘以10或更多的因子,使它们沿着该轴展开。确保跟踪您使用的是实际值还是乘以的值。High Level 这里有两个主要选项:
选择2 Python很好地描述了几种集群算法。从链接中,可以看到一个(粗略裁剪的)有用的图形: 这一行看起来与您的数据集相似;你试过高斯混合模型吗?A有一些众所周知的理论性质,但它的工作原理是根据数据计算的后验概率分配点属于每个簇中心的概率。您通常可以使用kmeans对其进行初始化,Sklearn会为您这样做 类似地,基于细节的聚类算法(例如)似乎是一种合乎逻辑的选择。您的数据有一个很好的密集簇分割,这似乎是一个很好的拓扑属性进行过滤。在链接的wikipedia页面上的图像中: 它们提供了标题: DBSCAN可以找到非线性可分簇。此数据集无法访问 用k-均值充分聚类 这似乎说明了你的麻烦
更多关于你的烦恼 Kmeans是一种非常通用的算法,但它不是全局最优的,并且存在许多弱点 除了像质心这样的问题之外,kmeans经常试图最小化到质心的简单欧几里德距离。虽然这对很多问题都很有意义,但在你的问题上却没有意义,因为集群的倾斜意味着这不是正确的度量。请注意,上面所示的其他算法,如凝聚/分层聚类,使用类似的度量,具有类似的特征 我没有介绍如何转换数据或调整kmeans,因为后者实际上需要侵入(或编写自己的)聚类算法(鉴于sklearn和类似软件包的覆盖范围,我不建议使用简单的探索性问题),因为前者似乎是对您的确切数据敏感的局部解决方案。这可能是一个不错的开始,但这项任务有很多选项k-means(以及@en knight答案中引用的其他聚类算法)适用于多维数据,这些数据往往具有彼此“接近”但在空间上分离的数据点组 在您的例子中,如果在未处理的输入空间(rpm vs velocity)中考虑数据,则形成的“簇”非常长,并且在(0,0)附近的区域中大部分重叠,因此大多数基于欧几里德距离的方法(如果不是所有的话)注定会失败 您的数据实际上不是6组空间上分离的二维点。相反,它实际上是6种可能的线性趋势的组合 因此,分组应基于x/y(传动比)。它是一维的:每个(rpm,velocity)对对应一个(rpm/velocity)值,您需要对它们进行分组 我不知道k-means(或其他算法)是否可以获取一维数据集,但如果不能,您可以使用[0,rpm/vel]这样的对创建一个新数组,并在其中运行 您可能需要寻找一种比多维通用算法更有效的一维算法
这将使图形标记更加复杂,因为分组是在派生数据集上计算的,该派生数据集的形状(1 x样本)与原始数据(2 x样本)不同,但映射它们并不困难。至少要缩放数据,使拉伸的水滴看起来更像圆。如果使用正确的种子,KMeans或其他聚类算法(如混合高斯算法)的性能会更好。另一种方法是使用RANSAC或其他稳健回归算法将一个斑点与一条直线拟合,然后删除这条直线周围的数据并进行迭代。你是如何得到明显由6个线性趋势混合而成的结果的,虽然被检查的车辆可能有5速变速器,但根据您的代码示例判断(它设置了
k=5
)?@LeoK k=5意味着聚类算法将生成5个中心,这似乎来自他的图像(EXE和颜色)。您提到的“6个线性趋势”来自基础数据。对我来说,这似乎没有什么不一致之处。我想问的是,数据是否来自6速汽车——似乎是这样(当你试图将其分为5组时,即使没有其他问题,也无法给出正确的分组)k-means和我熟悉的任何其他聚类算法都可以在一维中工作。欧几里德距离是沿着一条数线完美定义的(其他一些细节:)并非所有的算法我都是按欧几里德距离“引用”分组的。谱聚类
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()