【问题标题】:how to random generate a sequence of list that are unobserved before in python 3如何在python 3中随机生成之前未观察到的列表序列
【发布时间】:2019-01-11 18:53:53
【问题描述】:

假设我有 Python 3 中的代码

X, Y, Z = 10, 20, 30
data = [[1,3,6],[8,15,29],[8,9,19]] # observe data

那我如何随机生成不在data 中的n(不是很大)数据元素。

条件:元素[a,b,c]必须不在data0<a<X0<b<Y0<c<Z

[1,3,5] 很好,因为它不在data 中,并且它的元素满足条件

[11,3,6] 不好,因为它不满足条件 11>10

例如n=4时,我想要一个不重复的元素列表

newdata = [[1,6,6],[8,17,25],[2,6,11], [4,6,12]] 

【问题讨论】:

  • 听起来是个有趣的问题,您能否在开始时也包括一个合理的编码尝试?
  • @davedwards,我还在想。我的方法是使用蛮力技术。例如生成所有可能的元素,然后随机选择不在data 中的n 元素。但效率不高。
  • 这可能行得通,但暴力并不总是有效的。也许像生成random.randint(0, X) 并检查结果是否不在data 列表中,如果不是,则添加到newdata 列表中?

标签: arrays python-3.x list random


【解决方案1】:

应该这样做:

from random import randint

X, Y, Z = 10, 20, 30
data = [[1,3,6],[8,15,29],[8,9,19]]
n = 4

newdata = set()

for i in range(n):
    while True:
    l = [randint(1, X), randint(1, Y), randint(1, Z)]
    if l not in data:
        newdata.add(tuple(l))
        break

print(newdata)

示例结果:

newdata = [(9, 9, 11), (10, 10, 4), (7, 6, 23), (2, 10, 4)]

【讨论】:

  • 如果l in data 会生成太少的样本,因为它仍然会中断循环。 break 应该放在 if 块内。
  • 此外,它不处理生成样本的唯一性,即这种方法允许重复。这需要再次检查l not in newdata,所以我强烈建议使用datanewdata 的集合来加快成员资格测试。
  • @a_guest,这是一个很好的观点。似乎这种方法允许重复。
  • @davedwards 你还需要检查l not in newdata(或者用while len(newdata) < n 代替for 循环)。目前不允许重复,但如果生成重复,它将生成太少的样本。我还建议在运行算法之前将data 转换为set 以改进成员资格测试。您可以从一开始就将l 创建为tuple,这样可以节省额外的转化次数。
【解决方案2】:

花了一点力气,但这似乎奏效了:

from random import *
from pprint import pprint

X, Y, Z = 10, 20, 30
data = [[1,3,6],[8,15,29],[8,9,19]]

while 1:
    newData = []
    try: n = int(input("How many lists do you want: "))
    except:
        print("Please enter an integer.\n")
        continue
    for i in range(n):
        newList = [randrange(1, X), randrange(1, Y), randrange(1, Z)]
        while (newList in data) or (newList in newData):
            newList = [randrange(1, X), randrange(1, Y), randrange(1, Z)]
        newData.append(newList)
    pprint(newData)

这是通过创建一个空列表,获取 n 的值,然后进入恰好 n 次迭代的循环来实现的。然后它会创建一个满足要求的新列表。如果新列表在观察到的数据列表中,它会一遍又一遍地执行,直到它不在数据中。然后它将这些数据添加到输出列表并重复该过程,直到 for 循环中断(在 n 次迭代之后)。

可能有更好的方法,但这可以解决问题。

【讨论】:

    【解决方案3】:

    如果X, Y, Z 不是太大,您可以创建所有可能的组合,然后从该池中采样:

    import itertools as it
    import random
    
    x, y, z = 10, 20, 30
    pool = it.product(range(x), range(y), range(z))
    data = [(1, 3, 6), (8, 15, 29), (8, 9, 19)]
    pool = set(pool) - set(data)
    n = 4
    newdata = random.sample(pool, n)
    

    【讨论】:

      【解决方案4】:

      为了获得更高的性能,您可以使用 Numpy,并且可以通过简单地枚举元组来将它们转换为整数并返回(z, y, x 被枚举):

      import numpy as np
      
      x, y, z = 100, 200, 300
      n = 1000
      
      data = [[1,3,6],[8,15,29],[8,9,19]]
      forbidden = [i[0]*y*z + i[1]*z + i[2] for i in data]
      pool = np.arange(x*y*z)
      mask = np.ones(pool.size, dtype=bool)
      mask[forbidden] = False
      pool = pool[mask]
      newdata = np.random.choice(pool, n, replace=False)
      newdata = [(i // (y*z), i // z, i % z) for i in newdata]
      

      【讨论】:

        猜你喜欢
        • 2019-07-17
        • 2017-12-31
        • 2013-08-13
        • 1970-01-01
        • 1970-01-01
        • 2016-04-20
        • 1970-01-01
        • 1970-01-01
        • 2023-01-09
        相关资源
        最近更新 更多