生成每个数字0..k的随机矩阵

时间:2014-08-31 16:14:20

标签: python algorithm

给定一个整数k,我正在寻找一种生成nxm矩阵(或嵌套列表)的pythonic方法,该矩阵具有0..k-1的每个整数但不会出现多于一次的整数在每一行。

目前我正在做这样的事情

random.sample(list(combinations(xrange(k), m)), n)

但这并不能保证包含0..k-1中的每个数字,只是每行中不会出现多于一次的整数。这也具有组合复杂性,这显然是不可取的。

感谢。

4 个答案:

答案 0 :(得分:2)

你尝试使用numpy吗?这个使用numpy.random.shuffle的简单代码将为您提供一个包含0到k整数的随机列表:

import numpy as np
import numpy.random as npr

k = 7 # or whatever you like
thisrow = np.arange(k)
npr.shuffle(thisrow)

您可以多次重复此操作,以获得矩阵。

import numpy as np
import numpy.random as npr

k = 7 # row length
m = 23 # number of rows
mymatrix = np.zeros((m, k))

for i in range(m):
    mymatrix[i] = np.arange(k)
    npr.shuffle(mymatrix[i])

我同意上面的CommuSoft,您在问题中未明确指出kmn之间的关系。以随机顺序包含每个整数0..k-1的行只有一个长度k。也许您给出的示例未能给出范围内的每个整数,因为n<k

答案 1 :(得分:1)

您希望使用每个使用的整数生成一个整数n*m的随机1..k矩阵,并且在任何行中都不会使用两次整数。你想有效地做到这一点。

如果您只是想合理快速地生成合理的答案,可以通过随机选择元素并将它们放入随机顺序来生成行。 numpy.random.random_sample和numpy.random.shuffle可以做到这一点。您将避免重复元素问题。如果你没有使用你的所有元素,那么你可以做的就是随机发展&#34;这是一个正确的解决方案,在每一步确定矩阵中重复多次的所有元素,随机选择一个,并将其转换为1..k尚未使用的整数。这不会导致行内的重复,并且最多会在k步骤中为您提供所需表单的矩阵。

很可能这对你想要的东西来说是一个很好的答案,而且你应该做的。但它并不完美 - 这种形式的矩阵并非都以完全相同的概率发生。 (特别是那些只出现一次元素的元素会出现一些比它们应该更多的元素。)如果你需要一个完美均匀的分布,那么你将不得不做更多的工作。

要实现这一目标,你需要一些理论。如果您有这个理论,那么您可以理解答案为:&#34;动态编程解决方案是否可以转发以查找所有可能解决方案的计数,然后向后运行以做出随机决策以识别随机解决方案。&#34;可能的是你没有这个理论。

我不打算详细解释这个理论。我只是概述你的所作所为。

你从琐碎的陈述开始,&#34;有n!/(n-m)!种方法可以使用m整数的k得到满足条件的1行矩阵,没有人使用更多。&#34;

对于来自i的{​​{1}},1..njm的{​​{1}},您可以计算出构建{{1}的方式的数量使用k整数的i行。您还要跟踪前一行中j的先前值的方式中有多少。 (你以后需要它。)这一步可以在双循环中完成。

请注意,您刚为kj生成的表格中的值是满足所有条件的矩阵数。我们将自下而上构建一个随机的。

首先,为矩阵的最后一行生成一个随机行 - 所有这些行都是可能的。

对于每一行,直到您到达顶部,您使用您构建的表随机决定您生成的最后一行中使用的元素的数量将永远不会再次使用。随机决定哪些元素。从您仍在使用的整数生成随机行。

当你到达顶端时,你会选择符合你描述的随机矩阵,而不会产生偏差。

答案 2 :(得分:1)

以下效率取决于k,n和m的相对值,但如果您知道n*m远大于k,则可能与您获得的速度一样快。它还具有简单和缺乏偏见的优点:

from functools import reduce
from itertools import chain
from operator import ior
from random import sample

def gen(k,m,n):
  if m > k or k > m*n:
    raise ValueError("Unsatisfiable constraint")
  while True:
    mat = [sample(range(k), m) for i in range(n)]
    if reduce(ior, (1<<i for i in chain(*mat))) == (1<<k) - 1:
      yield mat

生成器gen重复计算n长度m列表的列表,其中每个成员列表由range(k)的唯一元素组成,直到n*m组合列表的元素包括range(k)的所有元素。一旦满足该约束,就会产生成功的矩阵,并且循环在下一次迭代中继续。

可能需要生成大量候选矩阵以找到满足约束的候选矩阵。通常,km的较大值很差。例如,对于k=10, n=4 and m=6,很少需要生成两个以上的矩阵,并且通常第一个生成矩阵。但是,对于k=100, n=40, m=6,每个成功的矩阵都会丢弃数百个矩阵,对于k=100, n=4, m=60,需要数万次尝试才能找到符合标准的矩阵。

答案 3 :(得分:0)

取每个数字1..k并将其分配给矩阵的某一行。

对于矩阵的每一行,填补空白而不重复。随机播放每一行也是为了保持随机性。

看起来非常简单有效。

编辑:

import random

k = 10
kset = set(range(k))
m = 4
n = 5

matrix = []
for i in range(m):
    matrix.append(set())

for i in range(k):
    matrix[random.randint(0,m-1)].add(i)

for i in range(m):
    presents = matrix[i]
    newelements = random.sample(kset-presents, n-len(presents))
    matrix[i] = random.sample( matrix[i] | set(newelements), n)