在列表中查找几乎相等值的列表

Find lists of almost equal values in list

提问人:Frank Tap 提问时间:11/10/2023 最后编辑:Frank Tap 更新时间:11/10/2023 访问量:82

问:

我有一个一维 numpy 数组,我想找到包含几乎相等值的子列表/子数组。这意味着它们之间的差异不超过容忍度。我的意思是,解决方案中有一个中心点,所有其他点的区别不仅限于公差。例如,如果我有和容忍度,期望的结果是 .我认为以下函数可以完成这项工作:[1.0, 2.2, 1.4, 1.8, 1.5, 2.1]0.2[[1.4, 1.5], [2.1, 2.2]]

import numpy as np


def find_almost_equal(input, tol):
    sorted = np.sort(input)
    result = []
    for i, v1 in enumerate(sorted):
        result.append([])
        for j, v2 in enumerate(sorted):
            if v2 - tol < v1 < v2 + tol:
                result[i].append(v2)

    result = [r for r in result if len(r) > 1]

    for i, r1 in enumerate(result):
        for j, r2 in enumerate(result):
            if set(r2).issubset(set(r1)):
                del result[j]

    return result


test = np.array([2.6, 1.2, 1.5, 1.8, 2.0, 2.2, 2.5, 1.1, 1.4])
tolerance = 0.15

almost_equal = find_almost_equal(test, tolerance)
print(almost_equal)

结果是 .结果是.[[1.1, 1.2], [1.4, 1.5], [2.5, 2.6]]tolerance = 0.25[[1.1, 1.2, 1.4], [1.4, 1.5], [1.8, 2.0, 2.2], [2.5, 2.6]]

当一个点属于多个子列表时,我的算法并不总是给出正确的结果。例如,输入和输出是 ,而预期结果是 。[1.0, 1.1, 1.2, 1.3, 1.4]tolerance = 0.2[[1.0, 1.1, 1.2], [1.2, 1.3, 1.4]][[1.0, 1.1, 1.2], [1.1, 1.2, 1.3], [1.2, 1.3, 1.4]]

问题:有没有更简单的方法可以做到这一点(最好是在numpy中)?我怎样才能正确地做到这一点?

python 数组 列表 numpy 聚类分析

评论

0赞 Tanishq Chaudhary 11/10/2023
对于 ,如何才是有效的解决方案?不是?tolerance = 0.25[1.1, 1.2, 1.4]1.4 - 1.1 > 0.25
0赞 derpirscher 11/10/2023
您正在搜索的术语是“聚类”。但如果您想要可靠且可重复的结果,这并不是一件容易的事。特别是,你没有提供足够的信息,你想要什么。你如何解释你的宽容?在整个簇上(即对于每个簇),或者如果簇中有一个元素在当前元素的容差范围内,则添加到簇中?此外,对集群的大小/数量有什么限制吗?因为根据您遍历元素的顺序,您可能会收到也可能不会收到不同的集群......max - min <= tolerancexcc
0赞 Frank Tap 11/10/2023
@Tanishq 乔杜里 也许解释不清楚。我的意思是,解决方案中有一个中心点,所有其他点的差异不超过容差,在本例中,该点为 1.2。我将把这个添加到问题中。
0赞 Tanishq Chaudhary 11/10/2023
如果数组是:with ?1.1, 1.2, 1.3, 1.4, 1.5tolerance = 0.15
0赞 Julien 11/10/2023
如果存在多种解决方案怎么办?哪个是“THE”解决方案?例如,与和你会期待什么?, , , ... ?tol = 10test = [1,5,6,7,8,12][1,5,6,7,8][5,6,7,8,12]([1,5,6], [7,8,12])

答:

1赞 Matt Pitkin 11/10/2023 #1

一种更简洁的方法,使用更多的 NumPy 功能,是进行一系列差异(如本答案所示),例如:

def find_almost_equal(inp, tol):
    # create array of differences
    inpa = np.sort(inp)
    diff = np.abs(np.subtract.outer(inpa, inpa))
    
    # get precision of float type
    prec = np.finfo(inpa.dtype).eps * 10
    
    # loop over rows in diff array (except first and last)
    l = []
    for row in diff[1:-1]:
         # get values within tolerance (accounting for floating point precision)
         r = inpa[row + prec  < tol].tolist()
         if len(r) > 1:
             for i, prev in enumerate(l):
                 # make sure list isn't subset of previous lists
                 if set(r).issubset(prev):
                     break
                 elif set(prev).issubset(r):
                     # add in longer lists
                     del l[i]
                     l.append(r)
                     break
             else:
                 l.append(r)
    return l

这给出了:

find_almost_equal([2.6, 1.2, 1.5, 1.8, 2.0, 2.2, 2.5, 1.1, 1.4], 0.15)
[[1.1, 1.2], [1.4, 1.5], [2.5, 2.6]]
find_almost_equal([2.6, 1.2, 1.5, 1.8, 2.0, 2.2, 2.5, 1.1, 1.4], 0.25)
[[1.1, 1.2, 1.4], [1.2, 1.4, 1.5], [1.8, 2.0, 2.2], [2.5, 2.6]]
find_almost_equal([1.0, 1.1, 1.2, 1.3, 1.4], 0.2)
[[1.0, 1.1, 1.2], [1.1, 1.2, 1.3], [1.2, 1.3, 1.4]]