Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a matrix of arbitrary size where rows sum to 1?

My task is to create a program that simulates a discrete time Markov Chain, for an arbitrary number of events. However, right now the part I'm struggling with is creating the right stochastic matrix that will represent the probabilities. A right stochastic matrix is a matrix that has row entries that sum to 1. And for a given size, I kind of know how to write the matrix that does that, however, the problem is that I don't know how to do that for an arbitrary size.

Any help is appreciated.

(Note that this isn't a homework problem, it's only for extra credit in my Math class and the professor doesn't mind the use of outside sources.)

like image 659
Raleigh L. Avatar asked Jul 12 '15 05:07

Raleigh L.


3 Answers

Using @MBo's idea:

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]:
like image 168
Sait Avatar answered Oct 25 '22 01:10

Sait


Generate NxN matrix with random values.
For every row:
Find sum of row S

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

Then subtract (S-1)/N from every value in this row

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

If you need only non-negative values, generate non-negative randoms, and divide every value in row by sum of this row

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

like image 40
MBo Avatar answered Oct 25 '22 01:10

MBo


Here is some code:

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

I assumed the random numbers have to be positive, the sum of numbers on a raw has to be 1. I used a precision give in variable 'precision', if this is 1000 it means that the random numbers will have 3 digits after the comma. In y example 6 digits are used, you may use more.

Output:

[[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]]
like image 22
Mihai Hangiu Avatar answered Oct 25 '22 01:10

Mihai Hangiu