我预计下面的算法性能会非常慢。 我有一个包含大字符串的非常大的(1.000.000+)列表。
ie:id_list = ['MYSUPERLARGEID:1123:123123', 'MYSUPERLARGEID:1123:134534389', 'MYSUPERLARGEID:1123:12763']...
num_reads
是从此列表中随机选择的最大元素数。
我们的想法是在id_list
中随机选择一个字符串ID,直到达到num_reads
并添加(我说添加,而不是追加,因为我不关心random_id_list
将它们放入random_id_list
,它在开头是空的。
我无法重复相同的ID,所以我在被选中后将其从原始列表中删除。我怀疑这就是让脚本变得非常慢的原因......也许我错了,而且这个循环的另一部分是缓慢行为的原因。
for x in xrange(0, num_reads):
id_index, id_string = random.choice(list(enumerate(id_list)))
random_id_list.append(id_string)
del read_id_list[id_index]
答案 0 :(得分:9)
使用random.sample()
生成N个元素的样本,没有重复:
random_id_list = random.sample(read_id_list, num_reads)
从大型列表中间删除元素确实很慢,因为超出该索引的所有内容都必须向上移动一步。
当然,这不会删除原始列表中的元素,因此重复的 random.sample()
调用仍然可以为您提供之前已选择的元素的样本。如果您需要重复生成样本,直到列表用完为止,那么一次,然后从那里开始挑选元素:
def random_samples(k):
random.shuffle(id_list)
while id_list:
res, id_list = id_list[-k:], id_list[:-k]
yield res
然后用它来制作你的样品;无论是循环还是next()
:
sample_gen = random_samples(num_reads)
random_id_list = next(sample_gen)
# some point later
another_random_id_list = next(sample_gen)
因为列表是完全随机的,所以以这种方式生成的切片也都是有效的随机样本。
答案 1 :(得分:0)
“硬”方式,而不是仅仅改组列表,是按顺序评估列表中的每个元素,并选择具有依赖于您仍需要选择的项目数量和数量的概率的项目的项目可供选择。如果您没有立即向您提供整个列表(这是一种所谓的在线算法),这将非常有用。
假设您需要选择k
个N
个项目。这意味着如果您可以同时考虑所有项目,则每个项目都有k/N
被选中的概率。但是,如果您接受第一项,则只需从k-1
剩余项目中选择N-1
项。如果您拒绝,则仍需要k
个N-1
个项目中的N = len(id_list)
k = 10 # For example
choices = []
for i in id_list:
if random.randint(1,N) <= k:
choices.append(i)
k -= 1
N -= 1
项。所以算法看起来像
k/N
最初,选择的第一个项目的预期概率为N
。当您浏览列表时,k
会逐渐减少,而p = k/N
会在您实际接受项目时减少。请注意,总体而言,每个项目仍有pi
被选中的机会。例如,考虑列表中的第二项。让i
成为您在列表中选择p1
元素的概率。考虑到k/N
和k
的起始值,N
显然是p2
。例如,考虑p2 = p1 * (k-1) / (N-1) + (1-p1) * k / (N-1)
= (p1*k - p1 + k - k*p1) / (N-1)
= (k - p1)/(N-1)
= (k - k/N)/(N-1)
= k/(N-1) - k/(N*(N-1)
= (k*N - k)/(N*(N-1))
= k/N
。
p3
类似(但更长)的分析适用于p4
,{{1}}等