¿Cómo funciona la caminata aleatoria y cómo se implementa su algoritmo?
¡Bienvenidos a un fascinante viaje al mundo de los caminos aleatorios! Este concepto, conocido también como la "caminata del borracho", es un problema sencillo pero intrigante en el cual un objeto puede desplazarse en múltiples direcciones con igual probabilidad. Vamos a repasar cómo nosotros podemos implementar este modelo con clases en Python para simular estos movimientos aleatorios y representar el comportamiento en un plano cartesiano.
¿Qué es un camino aleatorio?
Un camino aleatorio comienza en un punto de origen y puede moverse en varias direcciones: arriba, abajo, izquierda, o derecha, con una probabilidad igual del 25% para cada dirección. Este proceso se repite en cada paso, llevando a infinitas posibilidades de recorrer diferentes trayectorias. Algunos aspectos interesantes de un camino aleatorio incluyen:
Puede ser extendido a múltiples dimensiones, no solo en 2D, sino también en 3D, 5D, etc.
Se pueden asignar probabilidades diferentes para cada movimiento.
La distancia recorrida se calcula fácilmente mediante el teorema de Pitágoras.
¿Cómo podemos representar un borracho?
En el contexto del camino de borrachos, un borracho es una entidad que se mueve al azar en un plano. Implementamos la clase Borracho para abstraer el comportamiento de esta entidad.
classBorracho:def__init__(self, nombre): self.nombre = nombre
De esta manera, al extender Borracho, podemos crear subclases que modelen diferentes tipos de trayectorias y comportamientos. Un ejemplo de subclase es el BorrachoTradicional, quien se mueve aleatoriamente entre cuatro opciones: arriba, abajo, izquierda y derecha.
¿Cómo defino los movimientos del borracho?
Usamos la clase BorrachoTradicional para implementar esta lógica con la ayuda de la librería random de Python.
import random
classBorrachoTradicional(Borracho):def__init__(self, nombre):super().__init__(nombre)defcamina(self):return random.choice([(0,1),(0,-1),(1,0),(-1,0)])
Aquí random.choice se utiliza para seleccionar aleatoriamente una de las direcciones posibles, reflejando nuestro modelo de movimientos equiprobables.
¿Cómo manejamos las coordenadas y calculamos distancias?
Para gestionar la posición en el plano, creamos la clase Coordenada. Esta clase se encarga de las posiciones y desplazamientos del borracho.
Aquí, utilizamos el teorema de Pitágoras para calcular la distancia entre dos puntos.
¿Cómo se representa el campo?
El campo es el espacio que contiene a los borrachos. Implementamos esto a través de la clase Campo, la cual permitirá añadir, mover, y consultar las coordenadas de nuestros "borrachos".
Con esto, ahora tenemos el framework necesario para implementar simulaciones complejas de caminos aleatorios. Estas clases nos ofrecen la flexibilidad para modelar diferentes escenarios de simulación.
¡Construye y observa tu simulación!
Con las bases listas, podemos avanzar hacia integrar todo en un solo programa. Esto te permitirá realizar experimentos con diferentes escenarios y parámetros, y observar cómo varía la distancia al origen a medida que aumenta el número de pasos. Este ejercicio no solo es útil para aprender sobre programación orientada a objetos, sino también sobre probabilidad y estadísticas. ¡Sigue experimentando y expandiendo tus conocimientos!
Me agradan mucho este tipo de algoritmos, solo que cuando el profesor empieza a programar lo hace muy rápido y sin explicar la solución que propone (esto también hizo en el curso de CRUD con python), me parece que la forma de ayudar al estudiante es explicar el problema y diagramar una solución, por ejemplo un diagrama de clases UML, para saber que clases se van a crear y como van a estar relacionadas
Concuerdo contigo, es lo que hace falta en todos los cursos que imparte.
Concuerdo, un diagrama de clases ayudaría mucho en la visualización del proyecto/programa
Hola, vengo del futuro ( dos clases mas adelante) y les vengo a recomendar que vayan comentando su código ( se usa # )
Este modulo integra varias funciones y tener a la vista que hace cada una ayuda bastante al momento de leer.
vuelvo al futuro, adiós
Solo de la clase siguiente jajajaja Pero gracias por el aviso!
Este es un ejercicio donde empezando desde un punto 0 aleatoriamente podemos decidir que dirección tomar, dependiendo de las opciones establecidas.
Para realizar un ejemplo de aleatoriedad vamos a crear un programa que representara el problema del "Camino de Borrachos". Para esto crearemos 3 clases: uno que represente al agente que camina, una que genere una abstracción de las coordenadas y una que represente el plano en el cual nos estamos moviendo, y vamos a graficar la distancia en la que termina nuestro agente a medida que definimos una mayor cantidad de pasos que puede dar.
Primero crearemos un ambiente virtual, para ello vamos a la terminar.
mkdir camino_de_borramos # Creamos una carpeta para nuestro proyecto.cd camino_de_borrachos # Ingresamos a la carpeta.python3 -m venv env# Creamos nuestro ambiente virtual.source env/bin/activate # Activamos nuestro ambiente.pip install bokeh # Instalamos el paquete de bokeh para generar nuestra gráfica.
Luego de haber creado nuestro entorno de trabajo creamos los siguientes archivos en nuestra carpeta.
# Creamos un archivo borracho.pyimport random
# Creamos nuestra Clase borracho.classBorracho:def__init__(self, nombre): self.nombre = nombre
# Creamos la clase BorrachoTradicional que extiende de Borracho.classBorrachoTradicional(Borracho):def__init__(self, nombre):super().__init__(nombre)# Y tendrá un método caminar que devolverá la dirección a la que ira.defcamina(self):# Con random.choice elegimos un elemento aleatoriamente de la lista.return random.choice([(0,1),(0,-1),(1,0),(-1,0)])
# Creamos un archivo coordenada.py# La clase Coordenada guardara las coordenadas de nuestro agenteclassCoordenada:# Definimos unas posiciones iniciales.def__init__(self, x, y): self.x = x
self.y = y
# Y cuando se mueve simplemente a las coordenadas actuales se les# suma las coordenadas X e Y que ingresan como parámetros.defmover(self, delta_x, delta_y):return Coordenada(self.x + delta_x, self.y + delta_y)# Y si queremos saber la distancia del agente con respecto a# unas coordenadas, simplemente lo calculamos con el# teorema de Pitágoras.defdistancia(self, otra_coordenada): delta_x = self.x - otra_coordenada.x
delta_y = self.y - otra_coordenada.y
return(delta_x**2+ delta_y**2)**0.5
# Creamos un archivo campo.pyclassCampo:# Nuestra clase tendrá como atributo un diccionario.def__init__(self): self.coordenadas_de_borrachos ={}# Añadimos un agente a nuestro diccionario, nuestra llave sera# nuestro parámetro "borracho" y tendrá el valor asignado "coordenada"# que es una clase Coordenada creado en coordenada.py.defanadir_borracho(self, borracho, coordenada): self.coordenadas_de_borrachos[borracho]= coordenada
defmover_borracho(self, borracho):# Al mover a nuestro agente ejecutamos el método camina de# nuestra clase BorrachoTradicional creado en el archivo borracho.py,# devolviendo la dirección hacia donde se movió. delta_x, delta_y = borracho.camina()# Obtenemos el objeto de Coordenada. coordenada_actual = self.coordenadas_de_borrachos[borracho]# Del objeto Coordenada ejecutamos el método mover con los parámetros# que el objeto borracho genero. El resultado lo guardamos en# nueva_coordenada. nueva_coordenada = coordenada_actual.mover(delta_x, delta_y)# El objeto guardado en nueva_coordenada ahora estará asociado# a la llave de borracho. self.coordenadas_de_borrachos[borracho]= nueva_coordenada
defobtener_coordenada(self, borracho):return self.coordenadas_de_borrachos[borracho]
# Creamos el archivo camino_aleatorio.py# Importamos las clases que creamos anteriormente.from borracho import BorrachoTradicional
from campo import Campo
from coordenada import Coordenada
# Importamos bokeh para generar un gráfico con nuestros resultados.from bokeh.plotting import figure, show
defcaminata(campo, borracho, pasos):# De la instancia Campo obtenemos las coordenadas actuales de la llave "borracho". inicio = campo.obtener_coordenada(borracho)# Repetiremos la misma cantidad de pasos definidos.for _ inrange(pasos):# De la instancia campo ejecutaremos mover_borracho. campo.mover_borracho(borracho)# Y devolveremos la distancia entre las coordenadas de la instancia# inicio y campo.return inicio.distancia(campo.obtener_coordenada(borracho))defsimular_caminata(pasos, numero_de_intentos, tipo_de_borracho):# Definimos los parámetros para crear una instancia de Campo. borracho = tipo_de_borracho(nombre='Karl') origen = Coordenada(0,0)# Creamos una lista que guardara las distancias en cada simulación. distancias =[]# Por cada numero de intento.for _ inrange(numero_de_intentos):# Creamos una instancia de Campo. campo = Campo()# A nuestra instancia de Campo le damos la llave borracho y sus coordenadas de origen. campo.anadir_borracho(borracho, origen)# Obtenemos la distancia final de la simulación. simulacion_caminata = caminata(campo, borracho, pasos)# El resultado lo guardamos en la lista de distancias. distancias.append(round(simulacion_caminata,1))# Retornamos la lista de distancias.return distancias
defgraficar(x, y):# Creamos una instancia de figure, con su titulo y las etiquetas de los ejes. grafica = figure(title='Camino aleatorio', x_axis_label='pasos', y_axis_label='distancia')# Ingresamos los datos de X e Y. grafica.line(x, y, legend='distancia media')# Generamos una gráfica en HTML. show(grafica)defmain(distancias_de_caminata, numero_de_intentos, tipo_de_borracho):# Creamos una lista que guardara el promedio de cada caminata. distancias_media_por_caminata =[]# Por cada ítem en nuestras series de caminata.for pasos in distancias_de_caminata:# Guardamos las distancias que generan todas las simulaciones definido en numero_de_intentos. distancias = simular_caminata(pasos, numero_de_intentos, tipo_de_borracho)# De la lista de distancias obtenemos la distancia promedio. distancia_media =round(sum(distancias)/len(distancias),4)# De la lista de distancias obtenemos el máximo valor. distancia_maxima =max(distancias)# De la lista de distancias obtenemos el menor valor. distancia_minima =min(distancias)# Guardamos el promedio de la caminata en la lista distancias_media_por_caminata. distancias_media_por_caminata.append(distancia_media)# Imprimimos los datos de la caminata actual.print(f'{tipo_de_borracho.__name__} caminata aleatoria de {pasos} pasos')print(f'Media = {distancia_media}')print(f'Max = {distancia_maxima}')print(f'Min = {distancia_minima}')# Generamos un gráfico con la información de las distancias finales según la cantidad de pasos. graficar(distancias_de_caminata, distancias_media_por_caminata)if __name__ =='__main__':# Definamos cuantos pasos queremos que camine en cada serie. distancias_de_caminata =[10,100,1000,10000]# Determinamos la cantidad de simulaciones que generara en cada serie. numero_de_intentos =100# Ejecutamos el método main con los parámetros definidos anteriormente# y además pasamos la clase BorrachoTradicional main(distancias_de_caminata, numero_de_intentos, BorrachoTradicional)
Dentro el pensamiento estocástico debemos realizar varias simulaciones, por ese motivo en el ejemplo anterior realizamos varios intentos. Lo importante de esta aleatoriedad es que podemos distribuirla a lo largo de varios intentos, con esto podemos obtener certeza de que el comportamiento de nuestro programa se comporte en que esperamos estadísticamente.
Para ejecutar nuestro programa iremos nuevamente a la consola.
python3 camino_aleatorio.py # Ejecutamos nuestro programa# Y veremos nuestros resultados:BorrachoTradicional caminata aleatoria de 10 pasos
Media =2.639Max =6.3Min =0.0BorrachoTradicional caminata aleatoria de 100 pasos
Media =8.914Max =23.5Min =1.4BorrachoTradicional caminata aleatoria de 1000 pasos
Media =28.58Max =73.8Min =2.0BorrachoTradicional caminata aleatoria de 10000 pasos
Media =86.012Max =241.3Min =22.4
Wow quedo muy bien explicado, gracias Karl.
Muchas gracias!!!!
Díganme por favor que no soy el único que de alguna forma mira los continentes en esta imagen del minuto 03:09 jajajaja
es lo que yo pensé cuando vi la imagen por primera vez
también lo vi
Por aca les dejo los archivos con algunos comentarios y un repo de GitHub REPO
borracho.py
"""Modulo borrachos."""import random
classBorracho:"""Clase para los borrachos.""" def __init__(self, nombre):"""Inicializa el borracho.""" self.nombre= nombre
classBorrachoTradicional(Borracho):"""Clase para el borracho tradicional.""" def __init__(self, name):"""Inicializa el borracho tradicional."""super().__init__(name) def camina():"""Retorna una tupla.Calcula el valor aleatorio con la direccion
a donde se mueve el borracho."""return random.choice([(0,1),(0,-1),(1,0),(-1,0)])
coordenada.py
"""Modulo de coordenadas."""classCoordenada:"""Clase para las coordenadas.""" def __init__(self, x, y):"""Inicializa las coordendas.""" self.x= x
self.y= y
def mover(self, delta_x, delta_y):"""Retorna una nueva Coordenada con la nueva posicion."""returnCoordenada(self.x+ delta_x, self.y+ delta_y) def distancia(self, otra_coordenada):"""Calcula la distancia entre las coordenada.""" delta_x = self.x- otra_coordenada.x delta_y = self.y- otra_coordenada.yreturn(delta_x**2+ delta_y**2)**0.5
campo.py
"""Modulo del Campo."""classCampo:"""Clase para el campo donde se mueve le borracho.""" def __init__(self):"""Inicializa el campo.""" self.coordenadas_de_borrachos={} def anadir_borracho(self, borracho, coordenada):"""Agrega un borracho al diccionario.""" self.coordenadas_de_borrachos[borracho]= coordenada
def mover_borracho(self, borracho):"""Mueve al borracho de coordenda.""" delta_x, delta_y = borracho.camina() coordenada_actual = self.coordenadas_de_borrachos[borracho] nueva_coordenada = coordenada_actual.mover(delta_x, delta_y) self.coordenadas_de_borrachos[borracho]= nueva_coordenada
def obtener_coordenada(self, borracho):"""Retorna la coordenda del borracho."""return self.coordenadas_de_borrachos[borracho]
GRACIAS!!
Mira que en la función borracho me aparece error en el método "Camina"
Y me tocó corregirlo así
def camina(self):
Para poder entender mejor la funcionalidad de las clases hice el diagrama UML, tomando como referencia un artículo de un curso de POO.
Así quedo:
Nota: NO soy experta en esto, y realice el diagrama conforme al artículo. Si alguien encuentra algún error o tiene sugerencias de como mejorarlos, bienvenido sea :)
Muy valioso el aporte. Así pienso que se debe pensar siempre la programación orientada a objetos.
Cada vez que escribe estos códigos "largos" me hace dudar de mi inteligencia. ¿Uno debe hacer así en la vida real? o sea, parece que no tuviera la necesidad de pensarlo solo tiene claro que va en cada sitio y ya. Yo en su lugar tendría que pensar detenidamente cada paso (que se yo en un cuaderno) y ahí si podría empezar a escribir las clases y mientras escribo me daría cuenta que me faltó algo por definir.
Esto pasa porque la clase ya está preparada, y si estas aquí es para aprender así que no dudes de tu inteligencia, lo que recomiendo es que practiques
Puedes hacerlo en HackerRank o CodeWars
Yo estoy en mi segundo trabajo como programador y aún tengo el cuaderno al lado, por así decirlo, en problemas que no he memorizado. Supongo que detenerse a pensar en un problema no depende del nivel de este o tu inteligencia, sino de la frecuencia con el que lo resuelvas :") Practiquemos, como dice Royer Guerrero Pinilla.
Estuvo genial la clase. Cuando hago mi código, repito lo más aproximadamente posible las palabras del profesor, así voy interiorizando más ese método para programar.
Siento que, como todo, en la medida en que se practica, luego queda en la memoria, es decir que nuestro cerebro ya no debe crear un valor nuevo, sino que recursivamente va a esas experiencias para que podamos llegar a un nivel cada vez mejor como programadores, solo después de practicar, y practicar y seguir practicando.
se llama seudo codigo -> es la forma profesional de hacer programas
sigue asi compañero vas por buen camino
The winter is coming ¿Una referencia a GOT?
YES.!
si, ajjajajjaa
Quedé borracho de la clase xd
todos al inicio creo que quedamos asi con esta clase, por suerte subieron una nueva
AAAAAAAAAAAAAA TODO ESTO VA MUY RAPIDOOOOOOOOOOOOOOOOOOOOOOO
jajajaja super super real!!! Siento que esto fue tremendo crossover con el curso de POO y algoritmos
Winter is coming! XD ajajajajaj
lo que hago para entender mejor el codigo es poner comentarios explicando que hace cada linea de codigo:
classCampo: def __init__(self): self.coordenadas_de_borrachos={} #creamos un diccionario
def anadir_borracho(self, borracho, coordenada): self.coordenadas_de_borrachos[borracho]= coordenada
#le damos una llave(borracho) y un valor(coordenada) def mover_borracho(self, borracho): coordenada_actual = self.coordenadas_de_borrachos #creamos la varible coordenada_actual y le asignamos las coordenadas del borracho
dif_x, dif_y = borracho.camina() #lo que hacemos es: generar el movimiento aleatorio con "borracho.camina()" #y guardar el movimiento en las variables dif_X , dif_Y
nueva_coordenada = coordenada_actual.mover(dif_x, dif_y) #creamos una nueva_coordenada y le asignamos "coordenada_actual.mover(dif_x, dif_y)" #lo que hace "coordenada_actual.mover(dif_x, dif_y)": # es aplicar el movimiento aleatorio generado anteriormente por "borracho.camina()" self.coordenadas_de_borrachos[borracho]= nueva_coordneenada
#reasignamos las coordenadas_de_borrachos con la nueva_coordenada
def obtener_coordenada(self, borracho):return self.coordenadas_de_borrachos[borracho] #retornamos las coordenadas_de_borrachos```
Tiempo de tomar!! .... para comprender al borracho!
Aquí les dejo un video acerca del teoréma de pitágoras. Saludos.
Camino de Borrachos
Generamos un 'borracho' que elije aleatoriamente entre moverse entre cualquier dirección (aunque puede cambiarse las probabilidades de elección por ejemplo podemos hacer que sea el doble de probable que se mueva hacia el este).
Nuestra hipótesis es que mientras más se mueve el borracho más se aleja del punto de inicio. Para ello usamos el teorema de Pitágoras para calcular la distancia al punto inicial
Nota:
random.choice(<lista>) → elije aleatoriamente entre los valores de la lista
El profesor se explica solo , creo que deberia pausar y explicar y no leer el codigo de la maquina q tiene al frente
En el codigo de borracho. py, por que se crean los objetos borracho y borracho tradicional si pudiese haber bastado con una clase como la que muestro. Que utiidad extra permite esa segunda abstraccion?
classBorracho: def __init__(self, nombre): self.nombre= nombre
def camina(self):return random.choice([(0,1),(0,-1),(1,0),(-1,0)])
Simplemente se quería mostrar cómo crear una clase con herencia, para que en uno de los retos posteriores, cada estudiante cree su "tipo de borracho", heredando de la clase principal Borracho, y así tener varios tipos de Borracho (tradicional, izquierdista, al que le gustan las vueltas en circulos, etc), cambiando las proporciones en el método camina().
¡Saludos!
Lo que queria implementar como dijo el compañero era la herencia y que pudiera personalizarse el borracho usando polimorfismo
pero no se supone que el teorema de pitagoras es solo para triangulos rectangulos? ¿siempre las distancias del borracho seran triangulos rectangulos?
en este caso se supone que ambos salieron caminando en linea recta formando un angulo de 90 grados, a efectos del ejercicio.
no importa a donde vaya siempre será un triangulo rectángulo
A que se refiere en el minuto ** 12:01 ** al decir que la llave sera [borracho] ?
Recuerda que los elementos de un diccionario se definen por llaves y valores de la siguiente forma:
diccionario ={objeto: propiedad}
donde el objeto es la llave, y la propiedad el valor.
En el código de la clase, la llave borracho tendrá asignada la coordenada del borracho, así que es solo una forma de asociar cada borracho con su correspondiente coordenada.