Создание матрицы произвольного размера, где строки суммируют с 1?

Моя задача - создать программу, которая имитирует цепь Маркова с дискретным временем, для произвольного числа событий. Однако сейчас часть, с которой я борюсь, - это создание правильной стохастической матрицы, которая будет представлять вероятности. Правильная стохастическая матрица - это матрица, в которой есть записи строк, сумма которых равна 1. И для данного размера я вроде знаю, как написать матрицу, которая делает это, однако проблема в том, что я не знаю, как это сделать. для произвольного размера.

Например: вот мой код для матрицы 3х3, а также пример вывода, который я получил.

http://pastebin.com/4GXpAYTM

Однако мой код не работает каждый раз - бывают случаи, когда третья запись в строке является отрицательной, потому что первые две слишком велики. И я не знаю, как обойти это, насколько я знаю, в Python нет функции, которая бы позволяла генерировать случайные числа, которые суммируют что-то конкретное.

Любая помощь приветствуется.

(Обратите внимание, что это не домашнее задание, это только для дополнительной оценки в моем классе математики, и профессор не против использования внешних источников.)

4 ответа

Используя идею @MBo:

In [16]: matrix = np.random.rand(3,3)

In [17]: matrix/matrix.sum(axis=1)[:,None]
Out[17]:
array([[ 0.25429337,  0.22502947,  0.52067716],
       [ 0.17744651,  0.42358254,  0.39897096],
       [ 0.36179247,  0.28707039,  0.35113714]])

In [18]:

Вот некоторый код:

import random

precision = 1000000

def f(n) :
    matrix = []
    for l in range(n) :
        lineLst = []
        sum = 0
        crtPrec = precision
        for i in range(n-1) :
            val = random.randrange(crtPrec)
            sum += val
            lineLst.append(float(val)/precision)
            crtPrec -= val
        lineLst.append(float(precision - sum)/precision)
        matrix.append(lineLst)
    return matrix


matrix = f(5)
print matrix

Я предположил, что случайные числа должны быть положительными, сумма чисел в необработанном виде должна быть равна 1. Я использовал прецизионное задание в переменной "точность", если это 1000, это означает, что случайные числа будут иметь 3 цифры после запятой, В вашем примере используется 6 цифр, вы можете использовать больше.

Выход:

[[0.086015, 0.596464, 0.161664, 0.03386, 0.121997], 
[0.540478, 0.040961, 0.374275, 0.003793, 0.040493], 
[0.046263, 0.249761, 0.460089, 0.006739, 0.237148], 
[0.594743, 0.125554, 0.142809, 0.056124, 0.08077], 
[0.746161, 0.151382, 0.068062, 0.005772, 0.028623]]

Генерация матрицы NxN со случайными значениями.
Для каждого ряда:
Найти сумму строки S

S[j] = Sum(0..N-1){A[j, i]}

Затем вычтите (S-1)/N из каждого значения в этой строке

A[j, i] = A[j, i] - (S[j] - 1) / N

Если вам нужны только неотрицательные значения, генерируйте неотрицательные случайные числа и делите каждое значение в строке на сумму этой строки

A[j, i] = A[j, i] / S[j]

Правая стохастическая матрица - это вещественная квадратная матрица, каждая строка суммируется с 1.

Вот пример, из которого вы можете создать функцию, я оставляю ее вам в качестве домашней работы.

In [26]: import numpy as np

In [27]: N, M = 5, 5

In [28]: matrix = np.random.rand(N, M)

In [29]: matrix
Out[29]:
array([[ 0.27926909,  0.37026136,  0.35978443,  0.75216853,  0.53517512],
       [ 0.93285517,  0.54825643,  0.43948394,  0.15134782,  0.31310007],
       [ 0.91934362,  0.51707873,  0.3604323 ,  0.78487053,  0.85757986],
       [ 0.53595238,  0.80467646,  0.88001499,  0.4668259 ,  0.63567632],
       [ 0.83359167,  0.41603073,  0.21192656,  0.22650423,  0.95721952]])

In [30]: matrix = np.apply_along_axis(lambda x: x - (np.sum(x) - 1)/len(x), 1, matrix)

In [31]: matrix
Out[31]:
array([[ 0.01993739,  0.11092965,  0.10045272,  0.49283682,  0.27584341],
       [ 0.65584649,  0.27124774,  0.16247526, -0.12566087,  0.03609139],
       [ 0.43148261,  0.02921772, -0.12742871,  0.29700952,  0.36971886],
       [ 0.07132317,  0.34004725,  0.41538578,  0.00219669,  0.17104711],
       [ 0.50453713,  0.08697618, -0.11712798, -0.10255031,  0.62816498]])

объяснение

Мы создаем матрицу N x M

Затем мы рассчитываем (sum - 1) / N вычитать из каждого элемента по строкам

Затем мы применяем его к каждой строке матрицы, используя np.apply_along_axis() с axis=1 наноситься на каждый ряд

Проверьте результат

Каждая строка должна суммировать до 1

In [37]: matrix.sum(axis=1)
Out[37]: array([ 1.,  1.,  1.,  1.,  1.])

но как вычесть это значение из каждой записи в строке?

В моем примере я использовал lambda что эквивалентно этой функции

def subtract_value(x):
    return x - (np.sum(x) - 1)/len(x)

Вы можете передать функцию apply_along_axis() вызываться для каждого элемента на оси, в нашем случае это строки

Есть и другие способы, такие как numpy.vectorize() и numpy.frompyfunc

Создание функции и ее применение, как и любого метода, описанного выше, лучше, чем циклический просмотр каждого элемента в каждой строке, ускорение и уменьшение количества кода, упрощение чтения / понимания цели.

Одна маленькая точка была упущена. Стохастическая матрица - это матрица M x N неотрицательных элементов, сумма строк которой равна 1,0. MBo комментарий выше заявляет, что:

Если вам нужны только неотрицательные значения, сгенерируйте неотрицательные случайные числа и разделите каждое значение в строке на сумму этой строки

A[j, i] = A[j, i] / S[j]

Это верно только в том случае, если сохраненная матрица целиком состоит из целых чисел (не обязательно целых). В противном случае полученная матрица может содержать отрицательные числа: чем больше матрица, тем больше отрицательных элементов.

Это может быть достигнуто с помощью:

 X[i, j] = Math.Abs(random.Next(100, 900));
Другие вопросы по тегам