Search code examples
pythonnumpy

Fill numpy array to the right based on previous column


I have the following states and transition matrix

import numpy as np

n_states = 3
states = np.arange(n_states)

T = np.array([
    [0.5, 0.5, 0],
    [0.5, 0,  0.5],
    [0,  0,  1]
])

I would like to simulate n_sims paths where each path consist of n_steps. Each path starts at 0. Therefore, I write

n_sims = 100
n_steps = 10
paths = np.zeros((n_sims, n_steps),  dtype=int)

With the help of np.random.Generator.choice I would like to "fill to the right" the paths using the transition matrix. My attempt look as follows

rng = np.random.default_rng(seed=123)

for s in range(1, n_steps+1):
    paths[:,s] = rng.choice(
        a=n_states,
        size=n_sim,
        p=T[paths[:,s-1]]
    )

This result in the following error:

ValueError: p must be 1-dimensional

How can I overcome this? If possible, I would like to prevent for-loops and vectorize the code.


Solution

  • IIUC, your process being inherently iterative, you won't benefit much from numpy's vectorization.

    You might want to consider using pure python:

    def simulation(T, n_states=3, n_sims=100, n_steps=10, seed=123):
        rng = np.random.default_rng(seed)
        start = np.zeros(n_steps, dtype=np.int64)
        out = [start]
        for i in range(n_sims-1):
            a = np.array([rng.choice(n_states, p=T[x]) for x in start])
            out.append(a)
            start = a
        return np.array(out)
            
    simulation(T, n_states=3, n_sims=100, n_steps=10)
    

    Example output:

    array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
           [1, 0, 0, 0, 0, 1, 1, 0, 1, 1],
           [2, 0, 1, 0, 1, 2, 2, 0, 2, 2],
           [2, 0, 0, 1, 0, 2, 2, 1, 2, 2],
           [2, 1, 0, 2, 1, 2, 2, 2, 2, 2],
           [2, 2, 0, 2, 0, 2, 2, 2, 2, 2],
           [2, 2, 0, 2, 1, 2, 2, 2, 2, 2],
           [2, 2, 1, 2, 0, 2, 2, 2, 2, 2],
           [2, 2, 0, 2, 0, 2, 2, 2, 2, 2],
           [2, 2, 0, 2, 0, 2, 2, 2, 2, 2],
           [2, 2, 1, 2, 0, 2, 2, 2, 2, 2],
           [2, 2, 2, 2, 0, 2, 2, 2, 2, 2],
           [2, 2, 2, 2, 0, 2, 2, 2, 2, 2],
           [2, 2, 2, 2, 0, 2, 2, 2, 2, 2],
           [2, 2, 2, 2, 1, 2, 2, 2, 2, 2],
           [2, 2, 2, 2, 0, 2, 2, 2, 2, 2],
           [2, 2, 2, 2, 1, 2, 2, 2, 2, 2],
           [2, 2, 2, 2, 0, 2, 2, 2, 2, 2],
           ...
           [2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
           [2, 2, 2, 2, 2, 2, 2, 2, 2, 2]])