如何在Python中对这三个区域的数组进行分组/聚类?

17 投票
5 回答
14467 浏览
提问于 2025-04-17 10:41

你有一个数组

1
2
3
60
70
80
100
220
230
250

为了更好地理解:

为了更好地理解

你想知道如何在Python(2.6版)中把这三个区域分组/聚类,这样你就能得到三个数组,分别包含:

[1 2 3] [60 70 80 100] [220 230 250]

背景:

这里的y轴是频率,x轴是数字。这些数字代表的是十个最高的幅度,按它们的频率来表示。我想从中创建三个独立的数字,以便进行模式识别。可能还有更多的点,但它们都是根据相对较大的频率差异来分组的,就像这个例子中,频率大约在50和0之间,以及大约在100和220之间的差异。需要注意的是,什么是大,什么是小是会变化的,但不同组之间的差异相对于组内元素之间的差异仍然是显著的。

5 个回答

8

我想你想要一个简单但效果不错的算法。

如果你已经知道想要分成N个组,那你可以计算输入列表中相邻两个元素之间的差值(也就是增量)。比如在numpy这个库里可以这样做:

 deltas = diff( sorted(input) )

然后你可以在找到的N-2个最大差值的位置上设置分割点。

如果你不知道N是多少,那事情就复杂一些。你可以在看到某个增量大于特定值的时候设置分割点。这就需要你自己调整这个参数,虽然这样不是特别理想,但可能对你来说已经足够用了。

18

注意,如果x只是表示一个索引,那么你的数据点实际上是一维的。你可以使用Scipy的cluster.vq模块来对这些点进行聚类,这个模块实现了k-均值算法。

>>> import numpy as np
>>> from scipy.cluster.vq import kmeans, vq
>>> y = np.array([1,2,3,60,70,80,100,220,230,250])
>>> codebook, _ = kmeans(y, 3)  # three clusters
>>> cluster_indices, _ = vq(y, codebook)
>>> cluster_indices
array([1, 1, 1, 0, 0, 0, 0, 2, 2, 2])

结果的意思是:前面三个点组成了聚类1(这是一个随意的标签),接下来的四个点组成了聚类0,最后三个点组成了聚类2。根据索引对原始点进行分组的部分留给读者自己去做。

如果你想了解更多Python中的聚类算法,可以查看scikit-learn

17

这是一个用Python实现的简单算法,它的作用是检查一个数值是否在一个数据集的平均值附近,具体是看它是否超出了标准差的范围

from math import sqrt

def stat(lst):
    """Calculate mean and std deviation from the input list."""
    n = float(len(lst))
    mean = sum(lst) / n
    stdev = sqrt((sum(x*x for x in lst) / n) - (mean * mean)) 
    return mean, stdev

def parse(lst, n):
    cluster = []
    for i in lst:
        if len(cluster) <= 1:    # the first two values are going directly in
            cluster.append(i)
            continue

        mean,stdev = stat(cluster)
        if abs(mean - i) > n * stdev:    # check the "distance"
            yield cluster
            cluster[:] = []    # reset cluster to the empty list

        cluster.append(i)
    yield cluster           # yield the last cluster

在你的例子中,这段代码会返回你预期的结果,条件是 5 < n < 9

>>> array = [1, 2, 3, 60, 70, 80, 100, 220, 230, 250]
>>> for cluster in parse(array, 7):
...     print(cluster)
[1, 2, 3]
[60, 70, 80, 100]
[220, 230, 250]

撰写回答