将浮点数组划分为相似的段(聚类)
Posted
技术标签:
【中文标题】将浮点数组划分为相似的段(聚类)【英文标题】:partitioning an float array into similar segments (clustering) 【发布时间】:2013-07-03 00:42:02 【问题描述】:我有一个这样的浮点数组:
[1.91, 2.87, 3.61, 10.91, 11.91, 12.82, 100.73, 100.71, 101.89, 200]
现在,我想像这样对数组进行分区:
[[1.91, 2.87, 3.61] , [10.91, 11.91, 12.82] , [100.73, 100.71, 101.89] , [200]]
// [200] 将被视为异常值,因为集群支持较少
我必须为几个数组找到这种段,我不知道分区大小应该是多少。我尝试使用hierarchical clustering (Agglomerative) 来做到这一点,它给了我令人满意的结果。但是,问题是,有人建议我不要将聚类算法用于一维问题,因为它们没有理论上的理由(因为它们适用于多维数据)。
我花了很多时间寻找解决方案。但是,建议似乎完全不同,例如:this 和 this VS。 this 和 this 和 this。
我发现了另一个建议而不是聚类,即natural breaks optimization。但是,这也需要像 K-means 一样声明分区号(对吗?)。
这很令人困惑(特别是因为我必须在几个数组上执行那种分段,而且不可能知道最佳分区号)。
有什么方法可以找到分区(因此我们可以减少分区内的方差并最大化分区之间的方差)并具有一些理论依据?
任何指向文章/论文(如果有可用的 C/C++/Java 实现)的指针以及一些理论上的理由都将对我非常有帮助。
【问题讨论】:
我很好奇为什么聚类不适合一维数据 - 如果你以某种方式增加维度,例如,添加 sqrt(n) 作为维度,有点像 SVM 中发生的事情? @ZiyaoWei,“为什么聚类不适合一维数据”——我真的不知道。我在课堂上被告知在一维数据中使用聚类是很疯狂的。但是,我没有发现任何文章说明我为什么不能(或可以)。 @ZiyaoWei 无缘无故增加维度似乎不是一个好的解决方案。 不,不是,只是认为一维和多维数据之间没有真正的区别。还是他们? "...减少分区内的方差并最大化分区之间的方差..." 如果您确切地告诉我们您的意思,也许我们可以提供帮助。您的意思是最小化((分区内的平均方差)-(分区之间的平均方差)),还是什么? 【参考方案1】:聚类通常假设多维数据。
如果您有一维数据,请对其进行排序,然后使用核密度估计,或者只扫描最大的间隙。
在一维中,问题变得容易得多,因为可以对数据进行排序。如果您使用聚类算法,很遗憾不会利用这一点,因此请改用一维方法!
考虑在一维数据中找出最大的差距。这很简单:排序(n log n,但实际上尽可能快),然后查看两个相邻值的最大差异。
现在尝试在二维中定义“最大间隙”,并使用一种有效的算法来定位它...
【讨论】:
【参考方案2】:我想我会对数据进行排序(如果还没有的话),然后取相邻的差异。将差异除以较小的数字,得到百分比变化。设置一个阈值,当变化超过该阈值时,启动一个新的“集群”。
编辑:C++ 中的快速演示代码:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <numeric>
#include <functional>
int main()
std::vector<double> data
1.91, 2.87, 3.61, 10.91, 11.91, 12.82, 100.73, 100.71, 101.89, 200
;
// sort the input data
std::sort(data.begin(), data.end());
// find the difference between each number and its predecessor
std::vector<double> diffs;
std::adjacent_difference(data.begin(), data.end(), std::back_inserter(diffs));
// convert differences to percentage changes
std::transform(diffs.begin(), diffs.end(), data.begin(), diffs.begin(),
std::divides<double>());
// print out the results
for (int i = 0; i < data.size(); i++)
// if a difference exceeds 40%, start a new group:
if (diffs[i] > 0.4)
std::cout << "\n";
// print out an item:
std::cout << data[i] << "\t";
return 0;
结果:
1.91 2.87 3.61
10.91 11.91 12.82
100.71 100.73 101.89
200
【讨论】:
您能详细说明一下吗?我无法得到它(如果可能的话,可能是伪代码)? 我尝试了更大的样本。看起来它不起作用 [78, 89, 74, 42, 89, 22, 48, 26, 28, 92, 100, 96, 35, 5, 70, 76, 11, 70, 12, 91, 7, 38, 19, 68, 58, 2, 89, 20, 30, 81, 95, 11, 97, 81, 86, 43, 52, 48, 71, 91, 4, 64, 94, 41, 82, 16, 35、13、57、50] @deep_rugs:我认为你误解了意图。当您的数据被排序时,只有一个中断,因为在您的数据中没有一个数字与下一个数字之间的变化超过 40% 的地方。如果您关心按原始顺序更改数据,请删除std::sort
行并将 if (diffs[i] > 0.4)
更改为 if (std::abs(diff[i]) > 0.4)
。以上是关于将浮点数组划分为相似的段(聚类)的主要内容,如果未能解决你的问题,请参考以下文章