在Python中,我如何检查列表中的2个数字是否彼此相差一定百分比?

4

我有一个数值较大的列表,我想查看它们是否大致相等。如果两个数字“大致相等”(根据我的目的),它们之间的差距不超过10%(请参见以下2个示例)。然后我想将它们分类为大约相等的数字。

示例#1 比较5.0和5.5: 5.5 +/- 10% = 4.95到6.05(5.0在此范围内) 5.0 +/- 10% = 4.50到5.50(5.5在此范围内) 因此,5.0和5.5大致相等。

示例#2 比较5.0和5.6: 5.6 +/- 10% = 5.04到6.16(5.0在此范围内) 5.0 +/- 10% = 4.50到5.50(5.6不在此范围内) 因此,5.0和5.6不大致相等。

需要完成的工作: 输入={4.0, 4.1, 4.2, 4.0, 9.0, 9.4, 8.9, 4.3} 期望输出={4.0, 4.1, 4.2, 4.0, 4.3}和{9.0, 9.4, 8.9}


你使用的是哪种编程语言? - user229564
您可能想要研究一下k-means聚类算法。请注意,收敛对于您的问题将是一个问题。 - dan
1
如果所有数字都在另一个数字的10%范围内,例如[1.0、1.1、1.2、1.3、1.4、1.5、1.6、... 99.9],如何决定哪些数字归入哪个组? - dansalmo
4.0在4.3和4.2的范围内,偏差不超过0.4(10%)。 - dansalmo
但是4.3不在4.0的10%之内... - user229564
显示剩余8条评论
3个回答

3
input_list = [4.0, 4.1, 4.2, 4.0, 9.0, 9.4, 8.9, 4.3]

results = {input_list[0]: [input_list[0]]}    # Start with first value
for value in input_list[1:]:         # loop through our entire list after first value
    hi = value * 1.1
    low = value * 0.9
    print("Value: {0}\tHi: {1}\tLow:{2}".format(value, hi, low))
    for existing in results:     # search through our result set
        found_similar = False
        if low < existing < hi:  # if we find a match
            results[existing].append(value)    # we add our value to the list for that set
            found_similar = True
            break
    if not found_similar:        # if we looped through our entire results without a match
        results[value] = [value] # Create a new entry in our results dictionary

for entry in results:
    print(results[entry])

Will give:

results = { 9.0: [9.0, 9.4, 8.9],
            4.0: [4.0, 4.1, 4.2, 4.0, 4.3] }

这段代码以列表中的第一个值为起点,寻找所有与该值相似的后续数值,相似的定义是两者差值在10%以内。在您的例子中,它从4开始,找到所有类似的数值。任何不符合条件的值都被添加到一个新的“集合”中。
一旦程序执行到9.0,它发现这个数不匹配,于是将一个新的结果集添加到字典results中,用key值9.0表示。接着,当程序考虑到9.4时,它没有在4.0列表中找到匹配项,但在9.0列表中找到了一项匹配。因此,它将这个值添加到第二个结果集中。

我认为这会起作用。谢谢! 我还没有测试过,但逻辑对我来说看起来不错。 - leon
我不认为它解决了你后来提到的关于成对出现在多个集合中的问题...但我认为这个问题需要进一步定义,所以我坚持采用非常简单直接的解决方案。希望这是一个很好的起点。 - supermitch

0

这里是一个生成器/基于集合的方法。

def set_gen(nums):
    for seed in sorted(nums):
        yield tuple([n for n in nums if seed <= n and n/seed <= 1.1])

def remove_subsets(sets):
    for s in sets.copy():
        [sets.remove(s2) for s2 in sets.difference([s]) if set(s2).issubset(s)]

>>> nums = [4.0, 4.1, 4.2, 4.0, 9.0, 9.4, 8.9, 4.3]
>>> x = set(num for num in set_gen(nums))
>>> remove_subsets(x)
>>> list(x)
[(9.0, 9.4, 8.9), (4.0, 4.1, 4.2, 4.0, 4.3)]

>>> nums =  [1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0]
>>> x = set(num for num in set_gen(nums))
>>> remove_subsets(x)
>>> list(x)
[(1.9, 1.8), (1.5, 1.4), (1.4, 1.3), (1.2, 1.1), (1.7, 1.6), (1.5, 1.6), (1.3, 1.2), (1.9, 2.0), (1.0, 1.1), (1.8, 1.7)]

你在第二个例子的结果中有多个双精度浮点数,例如(1.2,1.1)(1.3,1.2)(1.0,1.1)。我认为这是不正确的。 - dawg
这是解决方案正确所必需的。请参见莱昂在他原始问题下我的评论中的澄清。他说:可以分为多个组的数字将出现在它可以出现的所有组中。因此,如果输入是{1.0,1.1,1.2},则输出将是2个列表:{1.0,1.1}和{1.1,1.2}。 - dansalmo

-1
你可以这样做:
Input = {4.0, 4.1, 4.2, 4.0, 9.0, 9.4, 8.9, 4.3} 

wl=sorted(Input,reverse=True)
apr=.1
out={}
while wl:
    wn=wl.pop()
    out[wn]=[wn]
    while wl and wl[-1]<=wn*(1+apr):
        out[wn].append(wl.pop())

print [(k,out[k]) for k in sorted(out.keys())]

输出:

[(4.0, [4.0, 4.1, 4.2, 4.3]), (8.9, [8.9, 9.0, 9.4])]

尝试评论中的示例:

>>> Input = {1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0}

输出:

[(1.0, [1.0, 1.1]), (1.2, [1.2, 1.3]), (1.4, [1.4, 1.5]), (1.6, [1.6, 1.7]), (1.8, [1.8, 1.9]), (2.0, [2.0])]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接