生成条件随机矩阵

时间:2018-12-02 08:24:49

标签: python

我们如何生成具有总和为1的行和列的矩阵。

import numpy as np
import random
class city:

    def  __init__(self):
        self.distance()

    def  distance(self):
        self.A = np.array([[ 0,  10,    20,  30],[10,   0,    25,  20],[20,  25,      0,  15],[30,  20,    15,   0]])
        self.B =(np.random.randint(0, self.A.shape[0], size=self.A.shape[0]) == np.arange(self.A.shape[0]).reshape(-1, 1)).astype(int)
        return self.B

2 个答案:

答案 0 :(得分:2)

据我所知,您需要一个生成随机doubly stochastic matrices(DSM)的生成器。

如果不需要任何其他属性来分布生成的矩阵,则选择的算法似乎仍然是Sinkhorn-Knopp。在这里,我们交替调整行和列的大小,以使这些值符合求和标准:

def gen_doubly_stochastic(size, max_error=None):
    if max_error is None:
        max_error = 1024 * np.finfo(float).eps

    m = np.matrix(np.random.random((size, size)))
    error = float('Inf')
    while error > max_error:
        m = np.divide(m, m.sum(axis=0), order='C')
        m = np.divide(m, m.sum(axis=1), order='K')

        error = max(
            np.max(np.abs(1 - m.sum(axis=0))),
            np.max(np.abs(1 - m.sum(axis=1)))
        )
    return m

在原始论文之后,迭代很快收敛到一个近似解。

或者,可以利用以下属性:任何n x n DSM可以表示为n随机置换矩阵(例如,Is there a better way to randomly generate a Doubly Stochastic Matrix)的线性组合,且总和为线性系数总和为1:

def gen_doubly_stochastic_permute(size):
    m = np.zeros((size, size))
    I = np.identity(size)

    # n random coefficients
    coeffs = np.random.random(size)
    # enforce coefficient sum == 1
    coeffs /= np.sum(coeffs)

    # index array for identity permutation
    values = np.array(range(0, size))
    for c in coeffs:
        # generate new random permutation in place
        np.random.shuffle(values)
        # add scaled permutation matrix
        m += c * I[values, :]
    return m

答案 1 :(得分:0)

欢迎来到stackoverflow亲爱的达沃德。
这是我解决此问题的算法:
假设我们希望矩阵的尺寸为4 * 4(就像图片中看到的一样,请务必注意)

  1. 首先,我们创建四个总和等于1的随机数,将其放入最上面未填充的行。
  2. 第二,我们尝试填充最后一个填充行下方的最左列,以使该列的总和等于1。

到目前为止,我们已经填充了黄色部分(图片) 在下一次迭代中,将填充橙色部分。等等。 这是代码(已经过测试)

picture of algorithm

# RMG.py

import numpy as np
from random import random

class RMG:

    def __init__(self, dimension, sum_=1):
        self.dimension = dimension
        self.sum = sum_


    def generate_matrix(self):
        # create a matrix filled with zero s
        row_num = self.dimension
        col_num = self.dimension
        matrix = np.zeros((row_num, col_num))
        for i in range(self.dimension):

            matrix[i, i:self.dimension] = \
                self.create_numbers(1-sum(matrix[i, 0:i])
                , self.dimension-i)

            if i == self.dimension -1:
                break

            matrix[i+1:self.dimension, i] = \
                self.create_numbers(1-sum(matrix[0:i+1, i]), self.dimension - i - 1)
        return matrix

    @classmethod
    def create_numbers(cls, wanted_sum, count):

        result = [random() for i in range(count)]
        diff = wanted_sum - sum(result)
        to_be_added = diff/count
        result = \
            list(
                map(
                    lambda x: x + to_be_added,
                    result
                    )
                )
        # to fix the approximations of float type:
        result[-1] += wanted_sum - sum(result)
        return result

这是RMGInteger.py中的派生类:

from RMG import RMG
from random import randint


class RMGInteger(RMG):

    def __init__(self, dimension, sum_=1):
        super(RMGInteger, self).__init__(dimension, sum)

    @classmethod
    def create_numbers(cls, wanted_sum, count):
        index = randint(0, count-1)
        result = [0 if i!= index else wanted_sum for i in range(count)]
        return result

这是要执行的文件:

# main.py

from RMG_Integer import RMGInteger

def main():

    handler = RMGInteger(4, 1)
    matrix = handler.generate_matrix()
    print(matrix)


if __name__ == '__main__':
    main()

# outputs something like this:
# [[1. 0. 0. 0.]
#  [0. 1. 0. 0.]
#  [0. 0. 0. 1.]
#  [0. 0. 1. 0.]]

更新:

根据评论中@Davood提到的内容,对代码进行了修改。
我写了一个派生类,它执行相同的工作,但生成的矩阵只有零个或一个值。