【发布时间】:2016-06-10 01:06:14
【问题描述】:
我有一个很长的 python 生成器,我想通过随机选择值的子集来“精简”它。不幸的是,random.sample() 不适用于任意迭代。显然,它需要支持len() 操作的东西(可能是对序列的非顺序访问,但这还不清楚)。而且我不想建立一个庞大的列表,以便我可以精简它。
事实上,在不知道其长度的情况下,可以一次均匀地从序列中采样——Programming perl 中有一个很好的算法可以做到这一点(编辑: “水库采样”,感谢@user2357112!)。但是有人知道提供此功能的标准 python 模块吗?
问题演示(Python 3)
>>> import itertools, random
>>> random.sample(iter("abcd"), 2)
...
TypeError: Population must be a sequence or set. For dicts, use list(d).
在 Python 2 上,错误更加透明:
Traceback (most recent call last):
File "<pyshell#12>", line 1, in <module>
random.sample(iter("abcd"), 2)
File "/usr/local/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/lib/python2.7/random.py", line 321, in sample
n = len(population)
TypeError: object of type 'iterator' has no len()
如果没有random.sample() 的替代品,我会尝试将生成器包装到提供__len__ 方法的对象中(我可以提前找出长度)。所以我会接受一个显示如何干净地做到这一点的答案。
【问题讨论】:
-
您在寻找水库采样吗?这不是 Python 自带的,可能是因为它只对疯狂的大流有意义。此外,
__len__还不够;random.sample需要随机访问。 -
需要明确的是,
random.sample确实 可用于任意序列,但不能用于任意可迭代对象。见docs.python.org/2/glossary.html -
如您所述,您可以将生成器包装在提供 len 方法的对象中。但至于其实现细节,这将有助于了解您的生成器到底在做什么/它是如何实现的。
-
如果你知道
len()先验,那么你可以这样做:indices = random.sample(xrange(len),k),然后运行你的生成器,直到你提取了每个索引数据。跨度>
标签: python python-3.x random