所以,假设我有一个这样的数组:
[1,1,2,3,10,11,13,67,71]
有没有一种方便的方法将数组分区为这样的东西?
[[1,1,2,3],[10,11,13],[67,71]]
我查看了类似的问题但是大多数人建议使用k-means来聚集点,例如scipy,这对于像我这样的初学者来说非常混乱。另外我认为k-means更适合两维或更多维聚类吧?有没有办法根据数字将N个数组分组到多个分区/聚类?
有些人还建议使用严格的范围分区,但并不总是将结果呈现为 预期
答案 0 :(得分:91)
不要将多维聚类算法用于一维问题。单个维度很多比您想象的更加特殊,因为您实际上可以排序它,这使事情变得更加容易。
事实上,它通常甚至不称为聚类,但例如分割或自然中断优化。
您可能希望查看Jenks Natural Breaks Optimization和类似的统计方法。 Kernel Density Estimation 也是一个很好的方法,具有强大的统计背景。密度的局部最小值是将数据分成簇的好地方,有统计学的理由这样做。 KDE可能是聚类1维数据的最佳方法。
使用KDE,再次证明一维数据表现得更好。在1D,你有当地的最小值;但在2D中你可能有马鞍点和这样的“可能”分裂点。请参阅此Wikipedia illustration of a saddle point,了解这一点可能适合或不适合拆分群集。
答案 1 :(得分:5)
您可以查找离散算法。 1D离散化问题与您提出的问题非常相似。他们根据频率,分组策略等决定截止点。
weka在其离散化过程中使用以下算法。
weka.filters.supervised.attribute.Discretize
使用Fayyad& Irani的MDL方法或Kononeko的MDL标准
weka.filters.unsupervised.attribute.Discretize
使用简单的分箱
答案 2 :(得分:1)
CKwrap 是一个快速而直接的 k-means 聚类函数,尽管文档上有点少。
pip 安装 ckwrap
import ckwrap
nums= np.array([1,1,2,3,10,11,13,67,71])
km = ckwrap.ckmeans(nums,3)
print(km.labels)
# [0 0 0 0 1 1 1 2 2]
buckets = [[],[],[]]
for i in range(len(nums)):
buckets[km.labels[i]].append(nums[i])
print(buckets)
# [[1, 1, 2, 3], [10, 11, 13], [67, 71]]
exit()
我希望作者希望您使用 nd 数组功能,而不是创建列表列表。
其他措施:
km.centers
km.k
km.sizes
km.totss
km.betweenss
km.withinss
底层算法基于此article。
答案 3 :(得分:0)
这个简单的算法有效:
points = [0.1, 0.31, 0.32, 0.45, 0.35, 0.40, 0.5 ]
clusters = []
eps = 0.2
points_sorted = sorted(points)
curr_point = points_sorted[0]
curr_cluster = [curr_point]
for point in points_sorted[1:]:
if point <= curr_point + eps:
curr_cluster.append(point)
else:
clusters.append(curr_cluster)
curr_cluster = [point]
curr_point = point
clusters.append(curr_cluster)
print(clusters)
上面的例子将点聚集到一个组中,这样一个组中的每个元素至多与组中的另一个元素相距eps
。这就像带有 DBSCAN
的聚类算法 eps=0.2, min_samples=1
。正如其他人指出的那样,一维数据允许您直接解决问题,而不是使用像 DBSCAN
这样的大枪。
对于一些包含 <1000
元素的小型数据集,上述算法的速度提高了 10-100 倍。