通过仅知道级别数来识别1D数据的级别

时间:2018-03-20 15:13:41

标签: c++ cluster-analysis k-means unsupervised-learning statistical-sampling

你好,伙计们, 我有一个传感器,输出数据由一个属性(单值)组成。有序数据打孔的一个例子如下:

样品: 199 200 205 209 217 224 239 498 573 583 583 590 591 594 703 710 711 717 719 721 836 840 845 849 855 855 856 857 858 858 928 935 936 936 942 943 964 977

您可以看到第一张图片输入中的数据。 input 数据分为几个级别。我给出了级别数(本例中为5级)。但是,每个级别的样本数量是未知的,并且级别之间的距离也是未知的。 我需要排除异常值并定义每个级别的中心(查看第二个图像输出output 红色样本代表异常值,黄色代表级别中心)。有没有算法,数学公式,c ++代码可以帮我实现这个要求? 我尝试了KMeans(在这个例子中K = 5)并且因为随机的初始K质心而得到了不好的结果。大多数时候,一些内部质心共享相同的水平,使该水平成为两个群集,而其他两个水平属于一个群集。如果我通过从每个级别选择一个质心手动设置初始质心,我会得到非常好的结果。 任何帮助将不胜感激!

4 个答案:

答案 0 :(得分:4)

如果两个连续数据点之间的差异大于特定值(将其视为Delta)则属于不同的群集。

对于此数据集:199 200 205 209 217 224 239 498 573 583 583 590 591 594 703 710 711 717 719 721 836 840 845 849 855 855 856 857 858 858 928 935 936 936 942 943 964 977

假设delta为15(根据传感器对此进行微调),如果连续数据点差异不大于15,则它们属于同一群集。您可以通过查找群集的中间值找到中心点。 如果点具有差值为delta的附近点,则可以将其视为异常值。另一个选项是我们可以根据数据集的当前值来改变delta。

答案 1 :(得分:3)

这是@KarthikeyanMV答案的延伸。 +1。是的,您需要能够确定Delta的值。这是一个可以做到这一点的过程。我在R中编写代码,但我认为这个过程很清楚。

据推测,群体之间的差距大于任何群体中的差距,所以只需看看连续点之间的差异,并询问差距在哪里。既然你认为应该有5组,那么应该有4个大的差距,所以看看第4大差异。

## Your data
dat = c(199, 200, 205, 209, 217, 224, 239, 498, 573, 583, 
    583, 590, 591, 594, 703, 710, 711, 717, 719, 721, 
    836, 840, 845, 849, 855, 855, 856, 857, 858, 858, 
    928, 935, 936, 936, 942, 943, 964, 977)
(Delta = sort(diff(dat), decreasing=TRUE)[4])
[1] 75

这个看起来像 Delta应该是75,但我们没有考虑异常值。下面下面的下一个点是否有超过Delta的点数?是。

BigGaps = diff(dat) >= Delta
(Outliers = which(c(BigGaps, T) & c(T, BigGaps)))
[1] 8

第8点太远,不属于上面或下面的组。所以,让我们删除它,然后再试一次。

dat = dat[-Outliers]
(Delta = sort(diff(dat), decreasing=TRUE)[4])
[1] 70
BigGaps = diff(dat) >= Delta
(Outliers = which(c(BigGaps, T) & c(T, BigGaps)))
integer(0)

在我们删除第8点之后,新的Delta为70.我们使用新的Delta(70)检查异常值并找不到。所以让我们使用Delta = 70进行聚类。

Cluster = cumsum(c(1, diff(dat)>=Delta))
plot(dat, pch=20, col=Cluster+1)

Clustered data

这主要发现了你希望除了之外的集群,它包含最高集群中的最后两个点,而不是声明它们是异常值。我不明白为什么他们应该是异常值而不是这个群体的一部分。也许你可以详细说明为什么你认为不应该包括它们。

我希望这会有所帮助。

答案 2 :(得分:1)

我建议使用DBSCAN代替K-Means。

这是一种基于密度的聚类算法,可以将彼此相同的数据点分组,而无需定义初始k或像K-Means这样的质心。

在DBSCAN中,距离和k邻居是用户定义的。 如果您知道Index具有一致的间隔,则DBSCAN可能适合解决您的问题。

答案 3 :(得分:1)

我注意到这些级别看起来有点像线条。你可以这样做:

1. sort the points
2. take the first two unprocessed points into an ordered set called the current line
3. lay a line between the first and last point of the set
4. test whether the line formed by the first point and the next unprocessed point
    form a line that has an angle lower than some threshold to the other line
5. If yes, add the point and go to 3
6. If no, store the current line somewhere and start again at 2

您还可以从检查此类线的前两个点是否与x轴的角度高于另一个阈值开始,如果是,则将第一个点存储为单数。异常值。

另一个版本只能通过两个点与x轴连接的角度来进行。在水平变化时,角度(倾斜,斜率)将大于水平上两点之间的角度。