Создание матрицы произвольного размера, где строки суммируют с 1?
Моя задача - создать программу, которая имитирует цепь Маркова с дискретным временем, для произвольного числа событий. Однако сейчас часть, с которой я борюсь, - это создание правильной стохастической матрицы, которая будет представлять вероятности. Правильная стохастическая матрица - это матрица, в которой есть записи строк, сумма которых равна 1. И для данного размера я вроде знаю, как написать матрицу, которая делает это, однако проблема в том, что я не знаю, как это сделать. для произвольного размера.
Например: вот мой код для матрицы 3х3, а также пример вывода, который я получил.
Однако мой код не работает каждый раз - бывают случаи, когда третья запись в строке является отрицательной, потому что первые две слишком велики. И я не знаю, как обойти это, насколько я знаю, в 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));