如何找到K-Shape中正在聚类的数据?

时间:2018-08-02 08:09:05

标签: python matplotlib

我写了代码,

import numpy
import matplotlib.pyplot as plt

from tslearn.clustering import KShape
from tslearn.datasets import CachedDatasets
from tslearn.preprocessing import TimeSeriesScalerMeanVariance


ks = KShape(n_clusters=3, n_init=10, verbose=True, random_state=seed)
y_pred = ks.fit_predict(data)

plt.figure(figsize=(16,9))
for yi in range(3):
    plt.subplot(3, 1, 1 + yi)
    for xx in stack_data[y_pred == yi]:
        plt.plot(xx.ravel(), "k-", alpha=.2)
    plt.title("Cluster %d" % (yi + 1))

plt.tight_layout()
plt.show()

我想用usigng KShape的聚类除以data。现在显示了图,但是我找不到每3个聚类中的数据。

数据是A,B,C,D的顺序。因此,我想显示要绘制的标签或聚类的结果。我搜索了KShape的文档(http://tslearn.readthedocs.io/en/latest/auto_examples/plot_kshape.html),但找不到信息来做我理想的事情。我应该怎么做?

1 个答案:

答案 0 :(得分:2)

为什么没有完美的解决方案

K形随机工作,并且没有为每次迭代设置种子,您可能会得到不同的簇和质心。如果给定类完全由给定质心描述,则没有确定性的方式可以知道先验,但是您可以通过模糊方式检查给定类主要归为哪个质心,从而以脱机方式继续进行模糊处理。

例如,任何给定的类A都可以包含属于您正在考虑的特征空间中的两个群集的元素。

假设您有3个类,但最好用4个类来描述您的数据集(例如,按最大平均密度):在第4个类中肯定有至少一个类的某些点。

或者,假设您的类别与正在考虑的距离度量生成的质心不重叠:考虑一个明显的例子:您有3个类别,数字从0到100,从100到1000和从1000到1000。 1100,但是您的数据集包含0到150以及950到1100之间的数字:一种聚类算法会在2个聚类中找到其最佳值,并将A类的点放在两个聚类之一中。

例如,一旦确定类A主要用于群集1,类B专门用于群集2等,则可以继续进行分配该集群到给定的类。

一种可能的模糊方法

我们将通过为包含大多数点的聚类分配最佳拟合类来确定聚类类别:

简单的例子:实际上适合集群的类

在此示例中,我们使用tslearn.datasets中的一个。该代码部分取自this K-Shape example on tslearn

import numpy as np
import matplotlib.pyplot as plt
from tslearn.clustering import KShape
from tslearn.datasets import CachedDatasets
from tslearn.preprocessing import TimeSeriesScalerMeanVariance
from seaborn import heatmap

我们为代码可重复性设置了种子:

seed = 0
np.random.seed(seed)

首先,我们准备数据集,选择第一个classes_number=3类:

classes_number = 3
X_train, y_train, X_test, y_test = CachedDatasets().load_dataset("Trace")
mask = y_train <= classes_number
X_train, y_train = X_train[mask], y_train[mask]  # Keep first 3 classes
X_train = TimeSeriesScalerMeanVariance().fit_transform(X_train)  # Keep only 50 time series
sz = X_train.shape[1]

现在我们找到具有clusters_number=3的簇:

# Euclidean k-means
clusters_number = 3
ks = KShape(n_clusters=clusters_number, verbose=False, random_state=seed)
y_pred = ks.fit_predict(X_train)

我们现在继续计算分配给每个群集的每个类的元素,并为未将给定类的元素分配给给定群集的地方添加0填充(当然会有更多的pythonic的方法,但我还没有找到它):

data = [np.unique(y_pred[y_train==i+1], return_counts=True) for i in range(classes_number)]

>>>[(array([2]), array([26])),
    (array([0]), array([21])),
    (array([1]), array([22]))]

添加填充:

padded_data = np.array([[
    data[j][1][data[j][0] == i][0] if np.any(data[j][0] == i) else 0
    for i in range(clusters_number)
] for j in range(classes_number)])

>>> array([[ 0,  0, 26],
           [21,  0,  0],
           [ 0, 22,  0]])

归一化获得的矩阵:

normalized_data = padded_data / np.sum(padded_data, axis=-1)[:, np.newaxis]

>>> array([[0., 0., 1.],
          [1., 0., 0.],
          [0., 1., 0.]])

我们可以使用seaborn.heatmap可视化获得的矩阵:

xticklabels = ["Cluster n. %s" % (1+i) for i in range(clusters_number)]
yticklabels = ["Class n. %s" % (1+i) for i in range(classes_number)]
heatmap(
    normalized_data,
    cbar=False,
    square=True,
    annot=True,
    cmap="YlGnBu",
    xticklabels=xticklabels,
    yticklabels=yticklabels)
plt.yticks(rotation=0)

获取:

Classes/clusters heatmap

在这种最佳情况下,每个聚类仅包含且仅包含一个类,因此我们可以绝对精确地获得:

classes_clusters = np.argmax(normalized_data, axis=1)

>>> array([2, 0, 1])

第二个例子:不与集群重叠的类

为简单起见,为了模拟不与集群完全重叠的类,我将仅对部分标签进行混洗,但是有大量示例:大多数集群问题最终都归因于不完全相同的类与簇重合。

tmp = y_train[:20]
np.random.shuffle(tmp)
y_train[:20] = tmp

现在,当我们再次执行脚本时,我们得到了完全不同的矩阵:

Classes/clusters heatmap, non overlapping

但是我们仍然能够确定类的簇:

classes_clusters = np.argmax(normalized_data, axis=1)

>>> array([2, 0, 1])

第三个示例:数据集中不存在的类

假设我们被认为是在数据集中存在4个类:在使用不同的k值运行后,我们会发现在当前数据集中,最佳簇数为k=3:我们继续将类分配给集群?哪个班可以丢掉?

我们通过向标签任意分配第四类来模拟这种情况:

y_train[:20] = 4

再次运行我们的脚本,我们将获得:

Classes/clusters heatmap, more classes than clusters

第四节课显然要去了。我们可以对平均方差进行阈值处理:

threshold = np.mean(np.var(normalized_data, axis=1))

result = np.argmax(normalized_data[np.var(normalized_data, axis=1)>threshold], axis=1)

我们又得到了:

array([2, 0, 1])

我希望这种解释消除了您的大部分疑问!