Las simulaciones de Monte Carlo son una forma de resolver problemas que se basan en repetir un experimento muchísimas veces y simplemente ver lo que ocurre. Sirven por ejemplo para cuando te enfrentas a un problema que tiene posibles soluciones o estrategias y no sabes muy bien cuál escoger. Se pueden utilizar en bolsa para evaluar el resultado de diferentes formas de actuar (por ejemplo: si me espero a vender mis acciones hasta que estén como mínimo al 120% del precio al que las compré ganaré o perderé dinero comparado con venderlas cuando lleguen al 100%?)
Otro ejemplo más sencillo de modelar en Python. Supongamos que cada vez que compramos una caja de cereales nos regalan un cromo aleatorio y que en total hay 6 cromos. ¿De media cuántas cajas espero tener que comprar para tener la colección completa?
El código que sigue a continuación simula la compra de cajas de cereales hasta alcanzar los 6 cromos y repite el juego un millón de veces.
import random
num_cards = 6
games_to_play = 100000
class Game(object):
def __init__(self):
self.tosses = 0
self.cards = []
def pickCard(self):
self.tosses += 1
newcard = random.randint(1, num_cards)
if not newcard in self.cards:
self.cards.append(newcard)
def run(self):
while len(self.cards) < num_cards:
self.pickCard()
return self.tosses
if __name__ == '__main__':
tosses = []
for i in range(games_to_play):
g = Game()
tosses.append(g.run())
print 'Cajas necesarias: %.2f' % (float(sum(tosses)) / len(tosses))
Tras ejecutar el script el resultado es 15 (14.70), lo que quiere decir que podemos esperar tener que comprar ese número de cajas de cereales antes de tener los 6 cromos.
Este otro juego simula diferentes estrategias a la hora de jugar a los dados. Si se acierta a la hora de elegir el número se gana 1 punto y si se falla se pierde 1 punto. Al haber solo una posibilidad entre 6 de acertar no esperamos hacernos ricos.
import random
games_to_play = 10000000
class Game(object):
def __init__(self, strategy):
self.money = 0
self.strategy = strategy
def run(self):
if self.strategy.makeGuess() == random.randint(1, 6):
self.money += 1
else:
self.money -= 1
class Always6(object):
def makeGuess(self):
return 6
class Always3(object):
def makeGuess(self):
return 3
class Random(object):
def makeGuess(self):
return random.randint(1, 6)
class Stair(object):
def __init__(self):
self.count = 0
def makeGuess(self):
self.count += 1
return self.count % 5 + 1
if __name__ == '__main__':
tosses = []
for inst in (Always3(), Always6(), Random(), Stair()):
g = Game(inst)
for i in range(games_to_play):
g.run()
print "%s\t %d " % (inst.__class__.__name__, g.money)</pre>
Los resultados tras jugar 10 millones de veces son:
Estrategia |
---|
Always3 |
Always6 |
Random |
Stair |
De las estrategias usadas la ganadora (que aquí significa que es con la que menos dinero perdemos) es elegir siempre 3, así que ya sabéis si alguna vez váis a jugar a los dados siempre al 3.
Para los curiosos, Python usa Mersenne Twister como generador de números pseudoaleatorios.