3

回答一个问题,我最终遇到了一个问题,我认为这是一种迂回的解决方法,可以以更好的方式完成,但我一无所知

有两个列表

percent = [0.23, 0.27, 0.4, 0.1]
optimal_partition = [3, 2, 2, 1]

最佳分区,是数字 8 分成 4 部分的整数分区之一

我想以一种optimal_partition将百分比分布匹配到尽可能接近的方式进行排序,这意味着单个分区应尽可能匹配百分比幅度

所以和和3 -> 0.4_2 -> 0.270.231 -> 0.1

所以最终的结果应该是

[2, 2, 3, 1]

我最终解决这个问题的方法是

>>> percent = [0.23, 0.27, 0.4, 0.1]
>>> optimal_partition = [3, 2, 2, 1]
>>> optimal_partition_percent = zip(sorted(optimal_partition),
                    sorted(enumerate(percent),
                       key = itemgetter(1)))
>>> optimal_partition = [e for e, _ in sorted(optimal_partition_percent,
                          key = lambda e: e[1][0])]
>>> optimal_partition
[2, 2, 3, 1]

你能建议一个更简单的方法来解决这个问题吗?

更简单的意思是,无需实现多重排序,以及基于索引的存储和稍后重新排列。

还有几个例子:

percent = [0.25, 0.25, 0.4, 0.1]
optimal_partition = [3, 2, 2, 1]
result = [2, 2, 3, 1]

percent = [0.2, 0.2, 0.4, 0.2]
optimal_partition = [3, 2, 2, 1]
result = [1, 2, 3, 2]
4

2 回答 2

3
from numpy import take,argsort

take(opt,argsort(argsort(perc)[::-1]))

或没有进口:

zip(*sorted(zip(sorted(range(len(perc)), key=perc.__getitem__)[::-1],opt)))[1]

#Test

l=[([0.23, 0.27, 0.4, 0.1],[3, 2, 2, 1]),
   ([0.25, 0.25, 0.4, 0.1],[3, 2, 2, 1]),
   ([0.2,  0.2,  0.4, 0.2],[3, 2, 2, 1])]

def f1(perc,opt):
    return take(opt,argsort(argsort(perc)[::-1]))

def f2(perc,opt):
    return zip(*sorted(zip(sorted(range(len(perc)),
             key=perc.__getitem__)[::-1],opt)))[1]       

for i in l:
    perc, opt = i
    print f1(perc,opt), f2(perc,opt)

# output:
# [2 2 3 1] (2, 2, 3, 1)
# [2 2 3 1] (2, 2, 3, 1)
# [1 2 3 2] (1, 2, 3, 2)
于 2013-01-11T19:59:47.860 回答
0

使用百分比总和为 1 的事实:

percent = [0.23, 0.27, 0.4, 0.1]
optimal_partition = [3, 2, 2, 1]
total = sum(optimal_partition)
output = [total*i for i in percent]

现在你需要想办法以某种方式重新分配小数部分。把想法大声说出来:

from operator import itemgetter
intermediate = [(i[0], int(i[1]), i[1] - int(i[1])) for i in enumerate(output)]
# Sort the list by the fractional component
s = sorted(intermediate, key=itemgetter(2))
# Now, distribute the first item's fractional component to the rest, starting at the top:
for i, tup in enumerate(s):
    fraction = tup[2]
    # Go through the remaining items in reverse order
    for index in range(len(s)-1, i, -1):
        this_fraction = s[index][2]
        if fraction + this_fraction >= 1:
            # increment this item by 1, clear the fraction, carry the remainder
            new_fraction = fraction + this_fraction -1
            s[index][1] = s[index][1] + 1
            s[index][2] = 0
            fraction = new_fraction
        else:
            #just add the fraction to this element, clear the original element
            s[index][2] = s[index][2] + fraction

现在,我不确定我会说这“更容易”。我还没有测试过,我确定我在最后一节中的逻辑是错误的。事实上,我正在尝试分配给元组,所以我知道至少有一个错误。但这是一种不同的方法。

于 2013-01-11T19:54:42.000 回答