我正在寻找一种方法,根据其值按比例分配正数到数字列表(更高得到更多)。可以把它想象成根据每个人的表现分配固定的奖金。
如果数字都是正数,这很简单。[1,2,3]的比例权重为[1/6,2/6,3/6]。但是我不确定如何处理代码中像[- 1,2,3]这样的情况?
在没有附加信息的情况下:如果[1,2,3]的权重为[1/6,2/6,3/6],则[-1,2,3]的权重为[-1/4,2/4,3/4]。
的例子:
def get_weights(p, nums):
total = sum(nums)
return [p * num / total for num in nums]
print(get_weights(1, [1, 2, 3]))
print(get_weights(1, [-1, 2, 3]))
输出:
[0.16666666666666666, 0.3333333333333333, 0.5]
[-0.25, 0.5, 0.75]
更新:
根据OP更新的问题和评论,一个"奖金";可以采用的策略是:
- 分配"基本奖金";每个人都能获得相同基础奖金的池
- 另外,分配"排名奖金"。池,每个人都可以根据他们的表现排名获得额外的奖金
- 对于奖金池的平衡,每个表现良好的人都会根据他们的表现获得额外的奖金。
例子:
performance = [-1,2,3,-1]
bonus_pool = 1
base_bonus = 0.1
rank_bonus = 0.1
# rank items in the list `performance` and allocate the rank_bonus pro rata to rank
from collections import Counter
c = Counter(performance)
rank = {x[1][0][0]:(x[0] + 1, x[1][0][1]) for x in enumerate(zip(sorted(c.items())))}
total_rank = sum(v[0]*v[1] for v in rank.values())
pro_rata_bonus = 1 - base_bonus - rank_bonus
total_pro_rata = sum(x for x in performance if x > 0)
n = len(performance)
bonus_base = [bonus_pool * base_bonus / n for k in performance]
bonus_rank = [bonus_pool * rank_bonus * rank[k][0] / total_rank for k in performance]
bonus_pro_rata = [bonus_pool * pro_rata_bonus * max(k, 0) / total_pro_rata for k in performance]
bonus = [bonus_pool * (base_bonus / n + rank_bonus * rank[k][0] / total_rank +
pro_rata_bonus * max(k, 0) / total_pro_rata) for k in performance]
print(f'performance :', end=''); [print(f' {x:5}',end='') for x in performance]; print(f' TOTAL: {sum(performance):5}')
print(f'bonus_base :', end=''); [print(f' {x:0.3f}',end='') for x in bonus_base]; print(f' TOTAL: {sum(bonus_base):0.3f}')
print(f'bonus_rank :', end=''); [print(f' {x:0.3f}',end='') for x in bonus_rank]; print(f' TOTAL: {sum(bonus_rank):0.3f}')
print(f'bonus_pro_rata:', end=''); [print(f' {x:0.3f}',end='') for x in bonus_pro_rata]; print(f' TOTAL: {sum(bonus_pro_rata):0.3f}')
print(f'---------------', end=''); [print(f'------',end='') for x in bonus]; print()
print(f'bonus :', end=''); [print(f' {x:0.3f}',end='') for x in bonus]; print(f' TOTAL: {sum(bonus):0.3f}')
输出:
performance : -1 2 3 -1 TOTAL: 3
bonus_base : 0.025 0.025 0.025 0.025 TOTAL: 0.100
bonus_rank : 0.014 0.029 0.043 0.014 TOTAL: 0.100
bonus_pro_rata: 0.000 0.320 0.480 0.000 TOTAL: 0.800
---------------------------------------
bonus : 0.039 0.374 0.548 0.039 TOTAL: 1.000
你需要定义负数的权重,对我来说最直观的方法是用它们的绝对值除以腹肌的总和,就像:
total_sum = sum([abs(x) for x in my_list])
weights = [abs(x)/total_sum for x in my_list]
但这只是一种方法,如果没有更多关于你想要达到的目标的信息,很难做到更精确。
如果您可以将值解释为在对数尺度上测量,那么合理的方法是使用softmax函数。SciPy在scipy.special.softmax
中有实现。
例如,
In [39]: softmax([-1, 2, 3])
Out[39]: array([0.01321289, 0.26538793, 0.72139918])
In [40]: softmax([-3, 2, 3])
Out[40]: array([0.00180884, 0.26845495, 0.72973621])
因为这些值是在对数刻度上,当所有值都是正的时候,你不会得到你在问题中提到的比例结果:
In [43]: softmax([1, 2, 3])
Out[43]: array([0.09003057, 0.24472847, 0.66524096])
In [44]: softmax([2, 2, 3])
Out[44]: array([0.21194156, 0.21194156, 0.57611688])
In [45]: softmax([2, 2.1, 3])
Out[45]: array([0.20732037, 0.22912444, 0.56355519])