我有一个有序的1-D数字数组。数组长度和数组中数字的值都是任意的。我想根据数值将数组划分为k个分区,例如:假设我想要4个分区,分配为30%/ 30%/ 20%/ 20%,即前30%的值,之后的30%等等。我可以选择k和分布的百分比。此外,如果相同的数字在数组中出现多次,则不应包含在两个不同的分区中。这意味着上面的分配百分比并不严格,而是“目标”或“起点”,如果你愿意的话。
例如,假设我的数组为ar = [1, 5, 5, 6, 7, 8, 8, 8, 8, 8]
。
我选择k = 4
,数字应按百分比pA = pB = pC = pD = 25%
分配到分区A,B,C和D中。
鉴于我上面给出的限制,结果分区应为:
A = [1]
B = [5, 5]
C = [6, 7]
D = [8, 8, 8, 8, 8]
得出(达到/更正)百分比pcA = 10%, pcB = 20%, pcC = 20%, pcD = 50%
在我看来,我需要一个改进的k-means算法,因为标准算法不能保证尊重我的百分比和/或要求相同的值不能在多个集群/分区中。
那么,有这种聚类的算法吗?
答案 0 :(得分:1)
聚类算法用于多维数据。对于一维数据,您应该只使用排序算法。
对数据进行排序。然后根据您的示例将数据集从数组底部线性分区到顶部。
答案 1 :(得分:1)
这是一个动态编程解决方案,它找到一个分区,可以最大限度地减少部件大小中错误的平方和。所以在[1,5,5,6,7,8,8,8,8,8]的例子中,你需要大小的部分(2.5,2.5,2.5,2.5),这个代码给出的结果是( 9.0,(1,2,2,5))。这意味着所选分区的大小为1,2,2和5,总误差为9 =(2.5-1)^ 2 +(2.5-2)^ 2 +(2.5-2)^ 2 +(2.5- 5)^ 2。
def partitions(a, i, sizes, cache):
"""Find a least-cost partition of a[i:].
The ideal sizes of the partitions are stored in the tuple 'sizes'
and cache is used to memoize previously calculated results.
"""
key = (i, sizes)
if key in cache: return cache[key]
if len(sizes) == 1:
segment = len(a) - i
result = (segment - sizes[0]) ** 2, (segment,)
cache[key] = result
return result
best_cost, best_partition = None, None
for j in xrange(len(a) - i + 1):
if 0 < j < len(a) - i and a[i + j - 1] == a[i + j]:
# Avoid breaking a run of one number.
continue
bc, bp = partitions(a, i + j, sizes[1:], cache)
c = (j - sizes[0]) ** 2 + bc
if best_cost is None or c < best_cost:
best_cost = c
best_partition = (j,) + bp
cache[key] = (best_cost, best_partition)
return cache[key]
ar = [1, 5, 5, 6, 7, 8, 8, 8, 8, 8]
sizes = (len(ar) * 0.25,) * 4
print partitions(ar, 0, (2.5, 2.5, 2.5, 2.5), {})
答案 2 :(得分:0)
天真的做法会是这样的:
假设p1 ... pk是分区的百分比(p1 + ... + pk = 1)
假设你在数组中有N个元素
初始边界(其中有k + 1个,包括数组结束,因为你有k个分区)是: 0,p1 * N,(p1 + p2)* N,...,N(有一些舍入要做)。
要移动边界,可以查看边界两侧的两个数组元素(对于可以移动的k-1边界)。如果两个元素相等,则需要移动到右边的边界,至少在满足约束之前。一种天真的方法是从左侧开始并进行最小的调整(只需将约束调整到导致移动最少的一侧,并且不再进一步移动边界)。
此算法不会覆盖整个分区空间。它只是给你一个解决方案。要找到最佳解决方案,您需要对整个分区空间进行强力搜索,并进行某种修剪(例如动态编程,您可以记住初始数组的子阵列的最佳分区)。