Reinforcement Learning para dummies: El problema del k-armed bandit en R
- fjroar
- 11 abr
- 6 Min. de lectura
Tras haber leído bastante sobre Reinforcement Learning y tras buscar librerías fáciles de entender y de usar tanto en R como en Python, no he conseguido encontrar nada sencillo, que se acerque ni tan siquiera al caso más básico de agentes como es el problema del k-armed bandit y de funciones que de algún modo me permita generar un agente aplicado a algún caso o a un modelo de datos. Tal vez sea, y lo digo humildemente, porque algo se me escapa y no he visto lo suficiente, pero, aunque hay algunas cosas, resultan complejas darle una aplicación fuera del “ejemplo preparado” que se presenta como puede ser el caso de la librería contextual. Además, me temo que tal vez no sea el único que ha observado esta situación tal y como he podido hablar con más gente.
Por tanto, voy a intentar en las siguientes líneas crear un ejemplo sencillo y espero que claro sobre RL que por supuesto podría mejorarse pero que podría ser implementado bajo un sistema que se “alimente correctamente” bajo la aplicación que describo a continuación.

El caso que traigo a colación puede imaginarse como que tengo unas 2500 máquinas tragaperras cuyo coste de uso es de 10€ y podemos ganar 1000€ si acertamos y 0€ si erramos. Para exponer este caso en mi github:
Puede descargarse el código que consiste en 3 programas (conviene guardar todo en una carpeta donde existan 2 sub-carpetas code y data si se quiere que todo funcione), ya que este ejemplo viene con demo para que se pueda adaptar a algún caso real:
Un primer programa en la subcarpeta data crea un dataset denominado bandits este dataset consta de un ID por máquina y la probabilidad de éxito asignada a cada una. Por supuesto, en un caso real, sólo tendremos la columna ID (que es la que se usa en el código), la otra no se tiene, porque será desconocida, salvo a lo sumo para el dueño de las tragaperras. En este caso se generan máquinas 2500 con números aleatorios uniformes entre 0 y 0.02 (en el programa 3, se pueden modificar estos parámetros para otros ejemplos). Además, ejecutando este programa vía el citado programa 3, se genera un histórico que en este caso tendría unas n_historico = 20 observaciones (tipo 0 – 1) por cada una de las 2500 máquinas (siendo esta la muestra base inicial y el punto de partida, conocido del problema)
Un segundo programa contiene las funciones específicas que van a utilizarse en las iteraciones del agente de modo que, si se lee con detenimiento el código, lo que permiten estas funcione es dar los siguientes pasos:
La creación de un número aleatorio entre 0 – 1 que permita aplicar por iteración y muestra de máquinas a utilizar en cada una (que en el caso del ejemplo básico que dejo es n_inversion = 100) el dilema exploración – explotación
Bajo el dilema del paso anterior el resto de las funciones permiten montar la siguiente lógica por iteración:
Se eligen el (1 – dilema)% de las máquinas con mayor tasa de éxito del paso anterior
Se elige aleatoriamente dilema% del resto de las máquinas que no están entre las anteriores
Se generan las observaciones de los anteriores pasos y se dejan a missing las no conocidas asociándose cada dato a cada máquina
Se integra la fila al fichero histórico
El tercer programa básicamente permite activarlo todo y realiza las siguientes acciones:
Va a ordenar al agente que actúe n_iter = 100 veces sobre un número de máquinas igual n_inversion = 100 y con una estrategia exploración – explotación de dilema = 0.1 (todo esto se puede modificar por el usuario pero por favor, meter cosas lógicas y no “romper” el programa, no he puesto nada de tratamiento de errores ya que no es una aplicación sino una idea lo que estoy tratando de explicar!!!!)
Por otro lado, va a calcular el beneficio (o coste) inicial de haber hecho el estudio (con el programa 1) por haber generado 20 observaciones por cada una de las 2500 máquinas donde se fue a modo fuerza bruta (en este caso se tiene un coste que sería coste_uso = 10 que multiplicado por cada una de las 2500 máquinas y las 20 observaciones sería igual a 500.000€ pero como algunas dan premio igual a ganancia_acierto = 1000, gran parte de ese número se reduce como se observa tras la ejecución), saliendo el coste inicial por -3000€ en el caso de la poc que está preparada
La inicialización (re-generación de la información) se hace con la función genera_entorno() que además de producir la información en data necesaria, genera la matriz_historico que es la que tiene la información que vendría de la observación de las máquinas (este riesgo, que en muchas ocasiones como es este caso sería un coste, debe ser asumido si se quiere tener una aproximación a la realidad)
Tras esto con la función genera_dinamica_prob_futuras() se generan las probabilidades anteriormente comentadas para aplicar el dilema exploración – explotación
Finalmente se aplica el agente que en la primera iteración hace uso exclusivamente de la matriz_historico y en el resto de las iteraciones incorpora la información que obtiene tras revisar las n_inversion = 100 máquinas. Esto genera un dataset que se denomina dinamico.csv que si se observa tendrá un número de observaciones igual n_historico + n_iter = 20 + 100 = 120. Sin missing en los primero 20 registros y con missing a partir de la fila 21 hasta la 120
Así pues, tras ejecutar el agente sobre el entorno creado y ver su actuación bajo un trade-off exploración – explotación de un 10% se obtendría el siguiente resultado:

Donde beneficio0 es el coste que se ha tenido que pagar para generar el histórico mientras que en beneficio_final se observa el acumulado del beneficio tras las 100 iteraciones. Además, el agente genera, no solo las nuevas observaciones incorporadas en el dataset dinamico.csv que pueden ser estudiadas, sino que además genera el vector beneficiosIter con los beneficios (o pérdidas) que se han ido generando en cada iteración por las máquinas elegidas.
La pregunta a realizar es ¿Qué pasaría si no se hace ninguna exploración? Es decir, si sólo se consideran los resultados obtenidos en las 20 iteraciones iniciales, el resultado entonces sería el siguiente (dilema = 0):

Es decir, el dato inicial es útil, pero se habría obtenido un mejor resultado con un poco más de exploración, ya que claramente en la muestra inicial no tienen por qué estar las máquinas óptimas.
Por otro lado, también cabe preguntar ¿Qué ocurre si nos lanzamos a una “locura exploratoria” con un nivel de exploración del 50% o con dilema = 0.5? En este caso el resultado, empieza a ser decaer, aunque al menos se cubre la inversión:

Finalmente, y para no extenderme demasiado os dejo varias indicaciones para usar estos programas y algunos comentarios sobre los resultados que se pueden obtener:
El programa puede preparar diversos entornos con una gran versatilidad de situaciones para analizar donde es factible, cambiar el número de máquinas, alterar la distribuciones de las probabilidades de éxito, aumentar o disminuir el número de máquinas a las que se apuesta por iteración, etc
Los resultados obtenidos están en consonancia con el dilema exploración – explotación, pero se debe tener en cuenta que si se altera por ejemplo el valor máximo de probabilidad de éxito de las distribuciones, los resultados pueden cambiar radicalmente y debe pensarse en éstos ya que la teoría funciona cuando el nivel de aleatoriedad de éxito es relativamente bajo y por tanto resulta difícil encontrar “buenas máquinas” que den premios, cuando la tasa de éxito es elevada, en general el efecto del dilema exploración – explotación estará más diluido
También conviene tener en cuenta que en este caso de RL se tiene que el agente se comporta de forma totalmente reactiva al entorno y realmente trata de “perseguir aciertos” cuando “toca una palanca”, dejándose llevar por esas pruebas que va haciendo, sin embargo, su actuación no altera el modo en el que cada máquina genera el dato, sino que el agente aprende en base a los resultados que su elección va generando, no teniendo en consecuencia información en las máquinas que no haya usado durante una determinada iteración
Aplicaciones de este ejemplo pueden tener sentido en sistemas de promoción de anuncios on-line, compra – venta de palabras, movimientos bursátiles y otros; pero debe tenerse en cuenta que debe prepararse la información de modo que se tenga una estructura similar (y en todo caso más completa) que los datasets aquí denominados basehist.csv pero sobre todo dinamico.csv teniendo en cuenta que el valor p de bandits sólo es conocido en esta PoC e incluso si “el fabricante o responsable de las máquinas” ve que ganamos demasiado dinero bajo nuestras elecciones, lo normal es que trate de alterar y cambiar algunas p ya que se está en todo caso ante un juego de suma 0, si unos ganan otros pierden
Comments