Im making a simple montecarlo simulator that takes in a 3*4 matrix of probabilities, and the number of iterations you want to simulate for. And the output is a table with all the results.Each row of the table is a list that contains: [iter no, random no, result1, result2]The logic is simple, just generate a random number and compare it with the cumulative probability. So when i try 1000000 iterations it takes 16 seconds or more and im trying to find out if its possible to get a better time.So far I've tried:
- Using memoization which i guess it doesnt make sense since the return data depends on a random number.
- Using numpy arrays and the method cumsum() to get cumulative probabilities.
- The best data structured i could come up with is a list of tuples of the possible outcomes and a 2 dimensional list to store the probabilities.
from random import randomimport numpy as npmatrix = [ [0.2, 0.2, 0.05, 0.1], [0.7, 0.5, 0.6, 0.4], [0.2, 0.25, 0.2, 0.04], ]estados = [ ("buena", "buena"), ("buena", "regular"), ("buena", "critica"), ("buena", "alta"), ("regular", "buena"), ("regular", "regular"), ("regular", "critica"), ("regular", "alta"), ("critica", "buena"), ("critica", "regular"), ("critica", "critica"), ("critica", "alta"),]estado_siguiente = {"buena": 0, "regular": 1, "critica": 2, "alta": 3}def get_result(rnd, probabilities, sig_estado=None): probabilities= ( probabilities[0] if (sig_estado == "" or sig_estado == "alta") else probabilities[estado_siguiente[sig_estado] + 1] ) for i in range(len(probabilities[0])): if rnd < probabilities[0][i]: return probabilities[1][i] return probabilities[1][len(probabilities) - 1]def start_simulation(probabilities, iter): vector_estado = [0, 0, "", "", 0, ""] table_final = list() #Here i have 4 accumulators for the probabilities of the 3 rows plus one for the whole table because a new result1 depends on the previous result2 meaning sometimes i just need the probs of just a row to_np_arr = np.array(probabilities) all_acc = (np.cumsum(to_np_arr), estados[:]) buena_acc = (all_acc[0][0:4], estados[0:4]) regular_acc = (all_acc[0][4:8], estados[4:8]) critico_acc = (all_acc[0][8:], estados[8:]) for _ in range(iter): rnd1 = random() estado1, estado2 = definir_condicion( rnd1, probabilities=[all_acc, buena_acc, regular_acc, critico_acc], sig_estado=vector_estado[3], ) #Add the list to the rest of the rows tabla_final.append(vector_estado) #Here I replace the old list with the new one vector_estado = [ vector_estado[0] + 1,"%.3f" % (rnd1), estado1, estado2,"%.3f" % (rnd2) if rnd2 else "-", condicion_alta, ] return tabla_final