Dataproc y Apache Spark proporcionan la infraestructura y la capacidad que se pueden usar para ejecutar simulaciones escritas en Java, Python o Scala.
Los métodos de Monte Carlo pueden ayudar a resolver un amplio rango de cuestiones sobre comercio, ingeniería, ciencia y matemáticas, entre otros campos. A través de muestras aleatorias repetidas que crean una probabilidad de distribución para una variable, una simulación de Monte Carlo puede brindar respuestas a preguntas que, de otro modo, serían imposibles de resolver. Por ejemplo, en finanzas, poner un precio a las opciones sobre acciones implica analizar las miles de formas en las que el precio de las acciones puede cambiar en el futuro. Los métodos de Monte Carlo permiten simular los cambios de precio de las acciones con un amplio rango de resultados posibles sin perder el control del dominio de las posibles causas del problema.
Antes, la ejecución de miles de simulaciones podía tardar mucho tiempo y generar grandes costos. Dataproc permite aprovisionar capacidad a pedido y pagar por minuto. Con Apache Spark, puedes usar clústeres de decenas, cientos o miles de servidores para ejecutar simulaciones de manera intuitiva y escalable con el fin de cumplir con tus necesidades. Esto significa que puedes ejecutar más simulaciones con mayor rapidez, lo que ayuda a que tu negocio innove y administre mejor los riesgos.
La seguridad siempre es importante cuando trabajas con datos financieros. Dataproc se ejecuta en Google Cloud, lo que ayuda a mantener tus datos seguros y privados de varias maneras. Por ejemplo, todos los datos se encriptan durante la transmisión y cuando están en reposo, y Google Cloud cumple con las normas ISO 27001, SOC3 y PCI.
Objetivos
- Crear un clúster de Cloud Dataproc administrado con Apache Spark preinstalado
- Ejecutar una simulación de Monte Carlo con Python que haga un cálculo aproximado del crecimiento de una cartera de valores en el tiempo
- Ejecutar una simulación de Monte Carlo con Scala que simule la forma en que un casino gana dinero
Costos
En este documento, usarás los siguientes componentes facturables de Google Cloud:
Para generar una estimación de costos en función del uso previsto, usa la calculadora de precios.
Cuando finalices las tareas que se describen en este documento, puedes borrar los recursos que creaste para evitar que continúe la facturación. Para obtener más información, consulta Cómo realizar una limpieza.
Antes de comenzar
- Configura un proyecto de Google Cloud
- Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the Dataproc and Compute Engine APIs.
- Install the Google Cloud CLI.
-
To initialize the gcloud CLI, run the following command:
gcloud init
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the Dataproc and Compute Engine APIs.
- Install the Google Cloud CLI.
-
To initialize the gcloud CLI, run the following command:
gcloud init
Cómo crear un clúster de Dataproc
Sigue los pasos para crear un clúster de Dataproc desde la consola de Google Cloud. La configuración del clúster predeterminada, que incluye nodos de dos trabajadores, es suficiente para este instructivo.
Inhabilita el registro de advertencias
De forma predeterminada, Apache Spark muestra el registro detallado en la ventana de la consola. A los fines de este instructivo, cambia el nivel de registro para registrar solo los errores. Sigue estos pasos:
Usa ssh
para conectarte al nodo principal del clúster de Dataproc
El nodo principal del clúster de Dataproc tiene el sufijo -m
en el nombre de la VM.
- In the Google Cloud console, go to the VM instances page.
- In the list of virtual machine instances, click SSH in the row of the instance that you want to connect to.
Se abrirá una ventana SSH conectada al nodo principal.
Connected, host fingerprint: ssh-rsa 2048 ... ... user@clusterName-m:~$
Cambia la configuración de registro
En el directorio principal del nodo principal, edita
/etc/spark/conf/log4j.properties
.sudo nano /etc/spark/conf/log4j.properties
Configura
log4j.rootCategory
comoERROR
.# Set only errors to be logged to the console log4j.rootCategory=ERROR, console log4j.appender.console=org.apache.log4j.ConsoleAppender log4j.appender.console.target=System.err log4j.appender.console.layout=org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{1}: %m%n
Guarda los cambios y cierra el editor. Si deseas volver a habilitar el registro detallado, restablece el valor de
.rootCategory
a su valor original (INFO
) para anular el cambio.
Lenguajes de programación de Spark
Spark admite Python, Scala y Java como lenguajes de programación de aplicaciones independientes y proporciona intérpretes interactivos para Python y Scala. El lenguaje que elijas depende de tu preferencia. En este instructivo, se usan los intérpretes interactivos, ya que puedes experimentar si cambias el código, pruebas diferentes valores de entrada y visualizas los resultados.
Estima el crecimiento de la cartera
En finanzas, los métodos de Monte Carlo a veces se usan para ejecutar simulaciones que intentan predecir el rendimiento de una inversión. Un método de Monte Carlo produce muestras aleatorias de resultados en un rango de condiciones posibles de mercado para resolver preguntas sobre el rendimiento de una cartera en promedio o en los peores casos.
Sigue estos pasos para crear una simulación que use los métodos de Monte Carlo a fin de intentar calcular el crecimiento de una inversión financiera según los factores de mercado comunes.
Inicia el intérprete de Python desde el nodo principal de Dataproc.
pyspark
Espera el mensaje de Spark
>>>
.Ingresa el siguiente código. Asegúrate de mantener la sangría en la definición de la función.
import random import time from operator import add def grow(seed): random.seed(seed) portfolio_value = INVESTMENT_INIT for i in range(TERM): growth = random.normalvariate(MKT_AVG_RETURN, MKT_STD_DEV) portfolio_value += portfolio_value * growth + INVESTMENT_ANN return portfolio_value
Presiona
return
hasta que aparezca el mensaje de Spark.En el código anterior, se define una función que modela lo que puede ocurrir cuando un inversionista tiene una cuenta de retiro existente que se invirtió en el mercado de valores y a la que se le agrega dinero todos los años. La función genera un retorno de la inversión aleatorio, como porcentaje, cada año por un período específico y toma un valor inicial como parámetro. Este valor se usa para reiniciar el generador de números aleatorios a fin de garantizar que la función no obtenga la misma lista de números cada vez que se ejecuta. La función
random.normalvariate
garantiza que se produzcan valores aleatorios en una distribución normal para la media y la desviación estándar especificadas. La función aumenta el valor de la cartera según el nivel de crecimiento que puede ser positivo o negativo y agrega una suma anual que representa las inversiones adicionales.Definirás las constantes requeridas en otro paso.
Crea muchos valores iniciales para la función. En el indicador de Spark, ingresa este código que genera 10,000 valores iniciales:
seeds = sc.parallelize([time.time() + i for i in range(10000)])
El resultado de la operación
parallelize
es un conjunto de datos resilientes y distribuidos (RDD), que es una colección de elementos optimizados para el procesamiento paralelo. En este caso, el RDD contiene valores iniciales que se basan en la hora actual del sistema.Cuando Spark crea el RDD, divide los datos según el número de trabajadores y núcleos disponibles. En este caso, Spark usa ocho divisiones, una por cada núcleo. Es lo adecuado para esta simulación que tiene datos de 10,000 elementos. Sin embargo, en simulaciones de mayor tamaño, cada división puede superar el límite predeterminado. En ese caso, especificar un segundo parámetro en
parallelize
puede aumentar la cantidad de fragmentos, lo que puede ayudar a mantener el tamaño de cada fragmento administrable, mientras Spark aún aprovecha los ocho núcleos.Provee valores al RDD que contiene los valores iniciales de la función de crecimiento.
results = seeds.map(grow)
El método
map
pasa cada valor inicial en el RDD a la funcióngrow
y agrega cada resultado a un nuevo RDD, que se almacena enresults
. Ten en cuenta que esta operación, que realiza una transformación, no produce los resultados de inmediato. Spark no hará este trabajo hasta que se necesiten los resultados. Esta evaluación diferida es la razón por la que puedes ingresar el código sin definir las constantes.Especifica algunos valores para la función.
INVESTMENT_INIT = 100000 # starting amount INVESTMENT_ANN = 10000 # yearly new investment TERM = 30 # number of years MKT_AVG_RETURN = 0.11 # percentage MKT_STD_DEV = 0.18 # standard deviation
Llama a
reduce
para agregar los valores en el RDD. Ingresa el siguiente código para sumar los resultados en el RDD:sum = results.reduce(add)
Calcula y muestra el retorno promedio:
print (sum / 10000.)
Asegúrate de incluir el carácter del punto (
.
) al final. Significa la aritmética de coma flotante.Ahora modifica la suposición y verás cómo cambian los resultados. Por ejemplo, puedes ingresar un valor nuevo para el resultado promedio del mercado:
MKT_AVG_RETURN = 0.07
Vuelve a ejecutar la simulación.
print (sc.parallelize([time.time() + i for i in range(10000)]) \ .map(grow).reduce(add)/10000.)
Cuando termines de experimentar, presiona
CTRL+D
para salir del intérprete de Python.
Carga una simulación de Monte Carlo en Scala
Montecarlo es un destino de juego famoso. En esta sección, usarás Scala para crear una simulación que modele la ventaja matemática que podría usar un casino en un juego de azar. La “ventaja de la casa” en un casino real varía mucho según el juego; en keno, por ejemplo, puede ser de alrededor del 20%. En este instructivo, se crea un juego sencillo en el que la ventaja de la casa es solo del uno por ciento. Así es cómo funciona el juego:
- El jugador hace una apuesta que consiste de un número de fichas del fondo de dinero.
- Luego, lanza un dado de 100 lados (¿no sería estupendo?).
- Si el resultado es un número del 1 al 49, el jugador gana.
- Si está entre el 50 y el 100, pierde la apuesta.
Como se ve, en este juego se crea una desventaja del uno por ciento para el jugador: en 51 de los 100 posibles resultados pierde.
Sigue estos pasos para crear y ejecutar el juego:
Inicia el intérprete de Scala desde el nodo principal de Dataproc.
spark-shell
Copia y pega este código para crear el juego. Scala no tiene los mismos requisitos que Python en lo que respecta a las sangrías, por lo que puedes solo copiar y pegar el código en el mensaje de
scala>
.val STARTING_FUND = 10 val STAKE = 1 // the amount of the bet val NUMBER_OF_GAMES = 25 def rollDie: Int = { val r = scala.util.Random r.nextInt(99) + 1 } def playGame(stake: Int): (Int) = { val faceValue = rollDie if (faceValue < 50) (2*stake) else (0) } // Function to play the game multiple times // Returns the final fund amount def playSession( startingFund: Int = STARTING_FUND, stake: Int = STAKE, numberOfGames: Int = NUMBER_OF_GAMES): (Int) = { // Initialize values var (currentFund, currentStake, currentGame) = (startingFund, 0, 1) // Keep playing until number of games is reached or funds run out while (currentGame <= numberOfGames && currentFund > 0) { // Set the current bet and deduct it from the fund currentStake = math.min(stake, currentFund) currentFund -= currentStake // Play the game val (winnings) = playGame(currentStake) // Add any winnings currentFund += winnings // Increment the loop counter currentGame += 1 } (currentFund) }
Presiona
return
hasta que aparezca el mensajescala>
.Ingresa el siguiente código para jugar 25 veces al juego, que es el número predeterminado de
NUMBER_OF_GAMES
.playSession()
Tus fondos comienzan con un valor de 10 unidades. ¿Ahora, es mayor o menor?
Simula 10,000 jugadores que apuestan 100 fichas por juego. Juega 10,000 juegos en una sesión. Esta simulación de Monte Carlo calcula la probabilidad de perder todo tu dinero antes de que finalice la sesión. Ingresa el siguiente código:
(sc.parallelize(1 to 10000, 500) .map(i => playSession(100000, 100, 250000)) .map(i => if (i == 0) 1 else 0) .reduce(_+_)/10000.0)
Ten en cuenta que la sintaxis
.reduce(_+_)
en Scala es la abreviación para agregar con una función de suma. Su función equivale a la sintaxis.reduce(add)
que viste en el ejemplo de Python.El código anterior realiza las siguientes acciones:
- Crea un RDD con los resultados de juego de una sesión.
- Reemplaza los resultados de los jugadores en quiebra con el número
1
y los resultados que no son cero con el número0
. - Suma la cantidad de jugadores en quiebra.
- La divide por el número de jugadores.
Un resultado típico puede ser:
0.998
Este representa casi una garantía de que perderás todo tu dinero, incluso si la ventaja del casino solo era del uno por ciento.
Limpia
Borra el proyecto
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.
¿Qué sigue?
- A fin de obtener más información sobre cómo enviar trabajos de Spark a Dataproc sin tener que usar
ssh
para conectarse al clúster, lee Dataproc: envía un trabajo.