出于一些奇怪的原因,让我们说我想使用List Comprehensions - 而仅使用List Comprehensions - 来生成10个大于0.5的随机数.对于问题的"10个随机数"部分,我们将使用:
samples = [ random.random() for x in range(10) ]
Run Code Online (Sandbox Code Playgroud)
现在,对于"大于0.5",如何使用LC实现?
samples = [ random.random() for x in range(10) if ??? ]
Run Code Online (Sandbox Code Playgroud)
你在描述什么称为拒绝抽样,这是一个坏主意.例如,如果您只想要数字>0.999,则生成它们需要花费1000倍的时间.
最好的办法
正确的方法是使用另一种采样技术,例如使用CDF的反转(累积密度函数),然后执行[inverseCDF(random()) for _ in range(10)].在你的情况下,就像GaretJax建议的那样,[0.5+random()/2 for _ in range(10)]
意图
我认为你的意图是能够根据列表理解的整个表达式进一步过滤.在这种情况下,你会把你的可迭代(在这里用括号而不是[...]用于懒惰,虽然没关系)在另一个理解中:
[r for r in (random.random() for x in range(10)) if r>0.5]
Run Code Online (Sandbox Code Playgroud)
有关可以处理拒绝的这些行的更好解决方案,请参阅"仅限列表推导的解决方案"部分或eryksun的答案.
发电机解决方案
(请参阅下面的列表理解解决方案)
您可以对任何线性范围执行此操作.但是,如果拒绝功能是任意复杂的,那么进行拒绝采样的一般方法如下.(同样,一个非常糟糕的想法,除非你知道你在做什么,效率无关紧要.)
from random import random
from itertools import *
def randoms():
while True:
yield random()
def rejectionSample(pred, n):
return islice(filter(pred, randoms()), n)
Run Code Online (Sandbox Code Playgroud)
例:
>>> print( list(rejectionSample(lambda x:x>0.5)) )
[0.6656564857979361, 0.9850389778418555, 0.9607471536139308, 0.9191328900300356, 0.810783093197139]
Run Code Online (Sandbox Code Playgroud)
你也可以这样做:
def rejectionSample(pred, n):
count = 0
while count<n:
r = random()
if pred(r):
yield r
count += 1
Run Code Online (Sandbox Code Playgroud)
仅限列表推导的解决方案
然而,由于要使用列表理解只,这意味着你的理解的表达部分不能失败,所以你必须以某种方式嵌入在修真while循环.单独使用单个lambda函数是不可能的,但只要我们有一些递归/循环原语,我们就可以将它拉下来,例如......
[next(filter(pred,randoms())) for _ in range(10)]
Run Code Online (Sandbox Code Playgroud)
(如果你真的想要一个单行列表理解,randoms()可以重写为(random() for _ in count()).)同样,如果你很容易找到你的特定发行版的分析逆累积分布函数,这是不必要的.
编辑:我把它拿回来......它可能 ......只有lambdas ......
亲爱的上帝,我在世界NOOOOOO上发生了什么样的恐惧?
[
(lambda f:f(f,random()))(lambda self,r:r if r>0.5 else self(self,random()))
for _ in range(10)
]
Run Code Online (Sandbox Code Playgroud)