从列表中随机移除X个元素

7
我想随机从一个列表中删除一部分元素,而不改变列表的顺序。
比方说,如果我有一些数据,我想删除其中四分之一:
data = [1,2,3,4,5,6,7,8,9,10]
n    = len(data) / 4

我认为我需要一个循环来遍历数据并删除随机元素'n'次?所以大概是这样的:
for i in xrange(n):
    random = np.randint(1,len(data))
    del data[random]

我的问题是,这是最“Pythonic”的做法吗?我的列表将有大约5000个元素,并且我想多次使用不同的“n”值进行此操作。
谢谢!
5个回答

12

顺序删除是一个不好的想法,因为在列表中进行删除的时间复杂度是O(n)。相反,可以像这样做:

def delete_rand_items(items,n):
    to_delete = set(random.sample(range(len(items)),n))
    return [x for i,x in enumerate(items) if not i in to_delete]

5
您可以像这样使用 random.sample

import random

a = [1,2,3,4,5,6,7,8,9,10]

no_elements_to_delete = len(a) // 4
no_elements_to_keep = len(a) - no_elements_to_delete
b = set(random.sample(a, no_elements_to_keep))  # the `if i in b` on the next line would benefit from b being a set for large lists
b = [i for i in a if i in b]  # you need this to restore the order
print(len(a))  # 10
print(b)       # [1, 2, 3, 4, 5, 8, 9, 10]
print(len(b))  # 8

以上有两点需要注意。

  1. 您没有直接修改原始列表,但可以这样做。
  2. 您实际上没有删除元素,而是保留了元素,但它们是相同的(您只需调整比例)
  3. 缺点是列表理解恢复元素顺序所需的时间较长

如@koalo在评论中所说,如果原始列表中的元素不唯一,则以上方法将无法正常工作。我可以轻松解决这个问题,但那样我的答案将与@JohnColeman发布的答案完全相同。所以如果可能会发生这种情况,请使用他的答案。


谢谢!实际上我想保留在'a'中剩下的内容,而不是被删除的内容。 - rh1990
如果一个元素在数组中出现了多次,那么这种方法就不起作用了! - koalo
这太棒了!谢谢 :) - rh1990

1

这个顺序是否有意义? 如果没有,你可以做类似于:

shuffle(data)
data=data[:len(data)-n]

0

我建议使用NumPy索引,如下所示

import numpy as np
data = np.array([1,2,3,4,5,6,7,8,9,10])
n = len(data)/4
indices = sorted(np.random.choice(len(data),len(data)-n,replace=False))
result = data[indices]

0

我认为这样会更方便:

import random
n = round(len(data) *0.3)
for i in range(n):
    data.pop(random.randrange(len(data)))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接