我有一份清单如下:
i = [
{'id': '1', 'P': 0.5},
{'id': '2', 'P': 0.4},
{'id': '3', 'P': 0.8},
...
{'id': 'x', 'P': P(x)}
]
当我执行以下操作时:
i.sort(key=lambda x: x['P'], reverse=True)
列表基于P排序,其中具有最大P的元素在前面。但是如果我想让它看起来是随机的,那么即使一个P值很小的元素(概率非常小)也可以作为列表中的第一个项目?
是否可以使用sort()函数实现它,或者我必须自己编写?
答案 0 :(得分:3)
根据我的理解,您希望对列表进行排序,但仍需要一些随机性。列表不能同时排序和随机排序。最近的可以通过像
这样的东西来实现i.sort(key=lambda x: x['P']*random.triangular(0.6, 1.4), reverse=True)
这同时确保订单不是完全随机的,也不是以类似的方式排序。
值0.6
和1.4
可以根据您想要的偏差进行更改。
答案 1 :(得分:3)
正如我在评论中提到的那样,您可以通过从标准正态分布中采样偏差因子来对随机偏差进行排序。然后,您可以将此偏差(在零的任一侧对称)添加到P值。
import numpy as np
#Give some control over the level of rearrangement - larger equals more rearrangement
bias_factor = 0.5
i.sort(key=lambda x: x['P'] + np.random.randn()*bias_factor, reverse=True)
或者,如果您只想使用标准库:
from random import gauss
#Give some control over the level of rearrangement - larger equals more rearrangement
sigma = 0.5
i.sort(key=lambda x: x['P'] + gauss(0, sigma), reverse=True)
答案 2 :(得分:2)
以下是我的看法:假设第1项具有相似性得分 $loginUrl = $helper->getLoginUrl(array('email'));
,而第2项具有相似性得分0.3
。然后,在这两个项目之间进行选择时,项目1应该在项目2之前,概率为0.4
,这似乎是合理的。这样得分较高的项目通常是 之前得分较低的项目。以下函数实现了merge-sort的变体,它包含了这个想法:
0.3 / (0.3 + 0.4)
进行测试:
import random
def pick(a,b,key = None):
ka = key(a) if key else a
kb = key(b) if key else b
if ka+kb == 0:
return random.int(0,1)
else:
p = ka/(ka+kb)
return 0 if random.random() <= p else 1
def randMerge(xs,ys,key = None):
merged = []
i = j = 0
while i < len(xs) and j < len(ys):
k = pick(xs[i],ys[j],key)
if k == 0:
merged.append(xs[i])
i += 1
else:
merged.append(ys[j])
j += 1
if i == len(xs):
merged.extend(ys[j:])
else:
merged.extend(xs[i:])
return merged
def randSort(items,key = None):
if len(items) < 2:
return items
else:
n = len(items)//2
xs = items[:n]
ys = items[n:]
return randMerge(randSort(xs,key),randSort(ys,key),key)
例如:
i = [
{'id': '1', 'P': 0.5},
{'id': '2', 'P': 0.4},
{'id': '3', 'P': 0.8},
{'id': '4', 'P': 0.9}
]