ALGORITMOS DE ORDENACIÓN EN PYTHON: ORDENACIÓN POR ARBOL BINARIO DE BUSQUEDA.

Continuamos hoy con nuestra serie de artículos acerca de los principales algoritmos existentes para la ordenación de elementos de una lista y su implementación usando el lenguaje Python. En la presente ocasión hablaremos de la ordenación por ‘Arbol Binario de Busqueda‘ (‘BST‘ por sus siglas en inglés), donde combinaremos la estructura de árbol binario con la propiedad de búsqueda de datos, ofreciendo un enfoque efectivo para organizar y recuperar información. Tras ello, mostraremos un sencillo ejemplo de implementación en Python.

QUE ES UN ARBOL BINARIO DE BUSQUEDA:

Un Árbol Binario de Búsqueda (‘BST‘ en adelante) es una estructura de datos jerárquica en la que cada nodo tiene, a lo sumo, dos nodos secundarios: Un nodo izquierdo, cuyo valor es menor y un nodo derecho, cuyo valor es superior al nodo principal. Siendo este principio de organización el que facilita la búsqueda y ordenación de datos de manera eficiente:

Para ordenar elementos en un árbol binario de búsqueda, se siguen reglas simples. Al insertar un nuevo elemento, se compara con el nodo actual. Si es menor, se inserta a la izquierda; si es mayor, a la derecha. Este proceso se repite recursivamente hasta encontrar un nodo sin hijo en la dirección adecuada, donde se inserta el nuevo elemento.

IMPLEMENTACIÓN EN PYTHON:

A continuación pasaremos a ver un sencillo ejemplo de implementación de este algoritmo, en Python, en la que empezaremos definiendo una clase (a la que llamaremos ‘Nodo‘), la cual, representará un nodo en nuestro ‘BST‘, en donde cada nodo tendrá un valor, así como referencias a sus respectivos nodos secundarios izquierdo (‘self.izquierdo‘) y derecho (‘self.derecho‘), que inicialmente no tendrán ninguno:

A continuación, definiremos la función ‘insertar()‘ que se encargará de insertar un nuevo nodo al árbol. De modo que si la variable ‘raiz‘ es ‘None‘, significará que estamos insertando el primer nodo, creándose un nuevo nodo con el valor proporcionado. Por su parte, si la raíz ya existe, se comparará el valor a insertar con el valor de la raíz. Así, dependiendo de si es menor o mayor, se llamará recursivamente a la función ‘insertar()‘ en el subárbol izquierdo o derecho, devolviéndose finalmente la raíz actualizada del árbol:

Por último, definiremos la función ‘inorden()‘, la cual, realiza un recorrido por los elementos del árbol. Recorriendo primero el subárbol izquierdo, luego la raíz y finalmente el subárbol derecho. En este caso, se utiliza para imprimir los elementos del árbol en orden ascendente:

Una vez definida la clase y sendas funciones, definiremos la lista de elementos a ordenar, la cual iremos recorriendo, utilizando la función ‘insertar()‘ para ir incluyéndolos en el árbol, para, finalmente, proceder a su ordenación mediante el la función ‘inorden()‘:

OUTPUT:

CONCLUSIÓNES:

Las ventajas de utilizar un árbol binario de búsqueda (‘BST‘) radican en su eficiencia y simplicidad conceptual. Permite la rápida búsqueda y ordenación de elementos, con operaciones como inserción y eliminación. Además, la estructura jerárquica facilita la comprensión y manipulación de datos ordenados. Además, se puede adaptar para aplicaciones específicas, como árboles ‘AVL‘ o árboles ‘rojo-negro‘, para mantener un equilibrio y mejorar aún más la eficiencia.

No obstante, existen desventajas importantes. La eficiencia está sujeta a la estructura del árbol, y si este degenera en una lista enlazada, las operaciones pueden volverse lineales, perdiendo la ventaja logarítmica. Además, la complejidad en la gestión de memoria y la necesidad de mantener la propiedad de búsqueda pueden complicar la implementación. Además, en comparación con otras estructuras de datos, como las tablas hash, la búsqueda puede volverse menos eficiente en ciertos casos.

En resumen, aunque los árboles binarios de búsqueda ofrecen una solución eficaz para ciertos escenarios, su rendimiento óptimo depende de la gestión de su estructura y su implementación precisa.

Saludos.

GENERANDO CÓDIGO MORSE EN PYTHON, CON ‘PLAYSOUND’ Y ‘PYDUB’

Saludos y bienvenidos un año más a vuestro blog sobre programación en lenguaje Python. En un día en el que para romper el hielo tras las vacaciones navideñas, os traemos un curioso script mediante el que podemos generar código Morse, a partir de un texto que nosotros le introduzcamos. El funcionamiento de este programa es bien sencillo: Se introduce un texto en una variable, convirtiendo cada carácter del mismo a su correspondiente en código Morse utilizando un diccionario predefinido. Una vez hecha la conversión, se iterará sobre el mensaje codificado, reproduciendo dos archivos de audio (‘tono_largo.wav‘ y ‘tono_corto.wav‘) en función de si el carácter leído es ‘.‘ o ‘‘:

GENERANDO TONOS DE AUDIO:

Pero antes de ponernos con nuestro programa (al que llamaremos ‘morse.py‘) Lo primero que haremos será generar los archivos de audio correspondientes a los tonos largo y corto. Para ellos usaremos otro script al que llamaremos ‘generate_morse_tones.py‘ el cual hará uso de la librería ‘pydub‘ la cual deberemos tener instalada previamente:

Instalación de ‘pydub’.
‘generate_morse_tones.py’

Como se ve, el procedimiento para generar los dos archivos de audio comienza definiéndose la duración en milisegundos, tanto del tono corto (que asociaremos con el ‘.’) como del tono largo (‘-‘), que será de 80 y 320 milisegundos respectivamente. A su vez, definiremos también la frecuencia de los tonos (teniendo en cuenta que valores mas bajos, generarán tonos más graves y valores más altos producirán tonos más agudos). En este caso hemos elegido una frecuencia de 600. Una vez establecidos estos valores, los usaremos como argumentos en la función ‘Sine()‘ (Ya que el tipo de onda que queremos que tenga la señal es de tipo sinusoidal) para generar sendos audios que después exportaremos a sendos archivos ‘.wav‘ que son los que usaremos en nuestro ‘morse.py’.

CREANDO PROGRAMA ‘morse.py’:

Una vez ejecutado el script anterior, tendremos los archivos ‘tono_corto.wav‘ y ‘tono_largo.wav‘ listos para ser usados por nuestro script, para cuya ejecución exitosa, deberemos tener instalada la librería ‘playsound‘:

A su vez, dado que uno de los pasos previos que ha de hacer nuestro programa, es convertir el texto introducido a código Morse, definiremos un diccionario (‘translate_dict‘) en el que a cada letra, asociaremos su correspondiente secuencia en Morse, de acuerdo a la siguiente tabla, de la que tomaremos solo los caracteres alfabéticos y numéricos:

Una vez hecho esto, generaremos el código en el que tras pedir la entrada e texto al usuario, utilizamos el diccionario ‘translate_dict‘ para efectuar la conversión de texto a Morse (secuencia de puntos y líneas). Finalmente, en la función ‘play_morse_code()‘, iteraremos sobre dicha secuencia para que la función ‘playsound()‘ reproduzca el audio ‘tono_corto.wav‘ o ‘tono_corto.wav‘ en función de si el signo actual es ‘.’ o ‘-‘ respectivamente. Todo ello lo englobaremos en una sentencia ‘try‘/’except‘ para capturar posibles errores:

OUTPUT:

CONCLUSIÓN:

En resumen, el programa desarrollado demuestra una implementación básica de la traducción de un mensaje a código Morse y su reproducción utilizando tonos cortos y largos como representación auditiva. A través de la combinación de bibliotecas como ‘playsound‘ para la reproducción de audio y un diccionario de traducción predefinido, este programa ofrece una introducción clara a la codificación y reproducción de mensajes en Morse.

La utilización de ‘pydub‘ y ‘playsound‘ junto con la representación de los tonos en archivos de audio ofrece una manera efectiva de presentar los conceptos de codificación y decodificación de código Morse, brindando una experiencia auditiva que ilustra la distinción entre puntos y rayas, así como las pausas que separan las letras y palabras.

Este proyecto podría ser ampliado agregando la capacidad de grabar mensajes en código Morse, decodificarlos de vuelta a texto legible o incluso implementar una interfaz gráfica para una experiencia más interactiva. En esencia, sirve como punto de partida para proyectos más ambiciosos que involucren la codificación y decodificación de información utilizando el código Morse como base.

Saludos.

DETECCIÓN DE TEXTO EN IMAGENES EN PYTHON, CON ‘EasyOCR’.

El Reconocimiento óptico de caracteres (‘ROC‘ u ‘OCR‘ por sus siglas en inglés), consiste en la extracción y detección de texto en imágenes. Se trata una tarea común en el campo de la visión por computadora que es ampliamente utilizada en aplicaciones tales como la captura y digitalización de documentos, traducción, detección de fraudes o reconocimiento de información en imágenes medicas. Así, esta semana vamos a aprender a extraer texto de una imagen, utilizando ‘EasyOCR‘ una librería en Python que nos permitirá realizar dicha tarea de una forma rápida y sencilla. Librería que deberemos instalar previamente en nuestro sistema, mediante el comando ‘pip install easyocr‘.

USO BASICO:

Una vez explicado el objetivo de nuestra practica, pasaremos a la extracción de texto de archivos de imagen. En esta ocasión usaremos el entorno de ‘Google Colab‘ en el que empezaremos realizando la instalación de ‘EasyOCR‘:

Tras ello pasaremos a importar la librería en cuestión, para a continuación, crear el objeto ‘reader‘ especificando el idioma (inglés en este caso) del texto que vamos a extraer:

Empezaremos extrayendo texto, en distintos tamaños, de una imagen en blanco y negro:

image.png

Para la lectura del texto en la imagen, usaremos aquí, la función «readtext()» pasando como argumento la ruta al archivo que contiene el texto que queremos obtener:

Esta función nos devolverá tres informaciones de cada línea de texto detectada: Las coordenadas de la imagen en las que se encuentra el área de texto (concebida como caja), el texto detectado y e nivel de confianza entendida como la probabilidad de que el texto detectado por el algoritmo ‘OCR‘ sea correcto. A su vez, podemos usar un bucle para acceder a estas tres informaciones de modo aislado:

Como se ve, el texto detectado en las líneas coincide con el presente en la imagen, lo que resulta coherente con los valores de probabilidad obtenidos.

A su vez, podemos usar «matplotlib» para mostrar el texto detectado en una etiqueta, para cada línea detectada en la imagen:

También podemos utilizar la información almacenada en la variable ‘bbox‘, para dibujar un recuadro que enmarque el área de la imagen ocupada por el texto:

Lo que hemos hecho sobre una imagen en blanco y negro, podremos hacerlo igualmente sobre una imagen a color como esta a la que hemos dado el nombre de «color_image.png«:

color_image.png

CONCLUSIÓN:

EasyOCR es una herramienta poderosa y fácil de usar para detectar texto en imágenes. Su capacidad para manejar múltiples idiomas, su precisión y su facilidad de integración lo hacen útil para una variedad de aplicaciones, desde la automatización de tareas hasta el procesamiento de documentos. En este artículo hemos visto, de un modo básico, como podemos usarle para extraer la información inherente al texto presente un un archivo de imagen y el modo en que podemos usar dicha información para mostrar gráficamente dicho texto en la imagen.

Saludos.

ENTENDIENDO LA COLA DE EVENTOS EN PYTHON: CONCEPTO Y EJEMPLOS

En el desarrollo de software, especialmente en entornos de interfaz de usuario y aplicaciones multihilo, la gestión eficiente de eventos es fundamental. Aquí, las colas de eventos, una estructura de datos clave en programación, desempeñan un papel crucial en la coordinación de operaciones asíncronas y en la gestión de eventos del sistema.

Se trata, pues, de una estructura de datos que sigue el principio de «primero en entrar, primero en salir» (FIFO, por sus siglas en inglés: First-In-First-Out). En programación, esta cola almacena eventos, que pueden ser señales, notificaciones o cualquier tipo de mensaje. Los eventos se insertan al final de la cola y se procesan en el mismo orden en el que fueron agregados. Las colas de eventos son fundamentales en entornos donde múltiples procesos o hilos comparten recursos o interactúan entre sí, como en interfaces gráficas de usuario (GUI), sistemas operativos y aplicaciones web.

IMPLEMANTACIÓN EN PYTHON:

Visto resumidamente en que consisten estas colas de eventos, pasaremos a continuación a ver un sencillo ejemplo de implementación en Python (aquí podemos utilizar el módulo ‘queue‘). Para ello vamos a escribir un sencillo script que simule el sistema de procesamiento de pedidos en una hipotética cafetería:

Tenemos aquí, un código que simula una cafetería en la que se reciben pedidos, los cuales, ven agregándose (mediante la función «put()«) a la cola «self.pedidos» (la cual hemos definido previamente con «self.pedidos = Queue()«). De modo que a continuación, cada pedido se procesa después de un tiempo simulado (establecido con «time.sleep()«) y se marca como completado. El programa principal simula el flujo de pedidos y espera a que todos se completen antes de finalizar.

OUTPUT:

Tal y como hemos señalado con anterioridad, las colas de eventos pueden ser muy útiles cuando estamos trabajando con interfaces gráficas. A continuación se muestra un sencillo código en el que se puede apreciar como podemos manejar tareas introducidas por el usuario:

Este código crea una interfaz gráfica simple con «Tkinter«. En donde hay un campo de entrada para agregar tareas, un botón para agregarlas a la lista, una lista donde se muestran las tareas agregadas y otro botón para procesar las tareas en la lista:

Así, al hacer clic en el botón «Add Task«, la tarea se agrega a la cola de eventos y se muestra en la lista. Y al hacer clic en «Process Tasks«, se procesan las tareas, mostrando una ventana emergente con el nombre de cada tarea y eliminándolas de la lista a medida que se procesan.

CONCLUSION:

Las colas de eventos son herramientas esenciales para gestionar la sincronización y el procesamiento de eventos en entornos de programación complejos. Su capacidad para manejar eventos asíncronos y coordinar múltiples operaciones las hace fundamentales en una amplia gama de aplicaciones, desde interfaces de usuario interactivas hasta sistemas de alto rendimiento. Al comprender su funcionamiento y aplicaciones, los desarrolladores pueden aprovechar al máximo las colas de eventos para crear sistemas más robustos y receptivos.

Saludos.

APLICANDO LA ‘TRANSFORMADA DE FOURIER’ EN PYTHON, CON ‘numpy’.

La ‘Transformada de Fourier‘ (cuyo nombre proviene del matemático y físico francés Joseph Fourier) es un método matemático que descompone una señal en sus componentes de frecuencia. En otras palabras, toma una señal en el dominio del tiempo y la convierte en su representación en el dominio de la frecuencia. Esto es útil para analizar las frecuencias presentes en una señal, como ondas sonoras y señales eléctricas, entre otras.

Joseph Fourier (1768-1830)

En las siguientes líneas vamos a ver un sencillo ejemplo de aplicación de esta técnica sobre una serie de tiempo que definiremos nosotros.

Antes de continuar, deberemos asegurarnos de tener instaladas las librerías que vamos a necesitar: ‘numpy‘ para la aplicación de la transformada y ‘matplotlib‘ para las representaciones gráficas:

Una ves instaladas las librerías que vayamos a emplear, crearemos un archivo de nombre ‘fourier.py‘ en el que tras hacer las importaciones pertinentes, empezaremos definiendo la serie de tiempo sobre la que vamos a aplicar la transformada. Serie de tiempo que crearemos con ‘np.arange()‘ y que irá de 0 a 10, incrementándose 0.01 cada vez:

Lo que hará nuestro script es mostrar simultáneamente la gráfica de la señal original y la resultante, tras aplicarle la transformada. Por ello utilizaremos a continuación ‘matplotlib‘ para mostrar dicha señal en una ventana destinada también a mostrar la gráfica resultado:

Una vez definida la señal original y su representación gráfica, es el momento de aplicarle la ‘Transformada de Fourier‘ con ‘numpy‘. Para lo cual, usaremos la función ‘fft()‘ del módulo ‘np.fft‘ a la que pasaremos nuestra señal original, definiendo las frecuencias con la función ‘fftfreq()‘ con un intervalo de muestreo de 0.01:

Tras ello, volveremos a emplear las funciones de ‘matplotlib‘ para generar la gráfica de la serie transformada, la cual mostraremos junto a la original:

Así, con todo, nuestro sencillo script quedaría de la siguiente manera:

OUTPUT:

En este ejercicio nos hemos limitado a utilizar la función ‘fft()‘ para calcular la ‘Transformada de Fourier’ discreta de una secuencia unidimensional. Sin embargo, hemos de tener en cuenta que el módulo ‘np.fft‘ de ‘numpy‘ ofrece una gran variedad de funciones para trabajar con la ‘Transformada de Fourier’. A continuación os mostramos algunas de las más comunes:

1-‘np.fft.fft()‘: Calcula la Transformada de Fourier discreta de una secuencia unidimensional.

2-‘np.fft.ifft()’: Calcula las Transformada Inversa de Fourier discreta de una secuencia unidimensional.

3-‘np.fft.fft2()’: Calcula la Transformada de Fourier bidimensional de una matriz.

4-‘np.fft.ifft2()’: Calcula la Transformada Inversa de Fourier bidimensional de una matriz.

5-‘np.fft.fftfreq()’: Genera las frecuencias correspondientes a las salidas de ‘fft‘.

6-‘np.fft.shift()’: Cambia el dominio de frecuencia de salida para centrarlo alrededor de cero.

7-‘np.fft.ishift()’: Deshacer el cambio generados por la función ‘shift()‘.

8-‘np.fft.rfft()’: Calcula la Transformada de Fourier discreta de valores reales.

9-‘np.fft.irfft()’: Calcula la Transformada Inversa de Fourier discreta para valores reales.

Estos métodos son ampliamente utilizados para realizar cálculos de transformadas de Fourier en diferentes dimensiones y tipos de datos, desde datos unidimensionales hasta matrices bidimensionales y valores reales. Permiten realizar análisis frecuencial, filtrado de señales, entre otros procesamientos fundamentales en el procesamiento de señales y el análisis de datos.

Saludos.

OPTIMIZACION DE FUNCIONES CON PYTHON Y ‘SciPy’: EXPLORANDO EL METODO ‘SLSQP’ PARA MINIMIZACIÓN DE UNA FUNCION

La minimización de funciones es un proceso matemático que busca encontrar el valor mínimo de una función, es decir, el punto donde la función alcanza su valor más bajo. Este valor mínimo puede representar un punto crítico, como un máximo o mínimo local, o el mínimo absoluto de la función en un intervalo determinado. Esta se usa para un amplio abanico de problemas como puede ser el ajuste de modelos, procesamiento de señales y optimización de funciones en finanzas.

Para ello, contamos en Python con ‘SciPy‘. Una herramienta poderosa que ofrece diversas técnicas para encontrar mínimos y máximos de funciones. En este artículo, usaremos el método ‘Sequential Least Squares Programming‘ (SLSQP) para encontrar el mínimo de una función cuadrática (concretamente de la expresión «Y=(x−1.5)**2«), usando dicha librería, que deberemos tener instalada en nuestro sistema:

Para ello, crearemos un nuevo archivo Python con el nombre «optimize_example.py» que constará de dos funciones:

La primera de ellas es la que hemos llamado «f()«. Esta se encarga de calcular el valor de «Y» en función de «x» según la expresión antes referida, utilizando la fórmula cuadrática. El propósito principal de esta función es representar una función objetivo para el método de optimización. Esta función irá mostrando los valores de «Y» y «x» cada vez que vaya siendo llamada, permitiéndonos rastrear el modo en que van cambiando estos durante el proceso de optimización.

La otra función que utiliza nuestro código es la que hemos llamado «test_run()«:

Esta es la función principal, que se encarga de ejecutar el código de prueba llevándose a cabo la optimización de la función «f()» empleando para ello, el método «spo.minimize()» de la librería «scipy» usando el referido método «SLSQP» y partiendo de un valor inicial para «x» (que será el que tome «f()«) definido en la variable «Xguess«. La ejecución del script nos devolverá una serie de datos (valor mínimo encontrado, el número de iteraciones, evaluación de funciones y gradientes…) entre los que se destaca los valores mínimos de «x» e «Y» (siendo estos 1.5 y 0.5 respectivamente).

OUTPUT:

A su vez, podemos usar la librería «matplotlib» (que deberemos tener también instalada) para representar graficamente dicho punto dentro de la función. Quedando nuestro script de la siguiente manera:

OUTPUT:

Representación grafica del valor mínimo de ‘x’ e ‘Y’.

CONCLUSION:

El método «SLSQP» de «SciPy» es una herramienta de gran utilidad para encontrar mínimos de funciones, especialmente en problemas no lineales. Este ejemplo ilustra cómo utilizar este método para optimizar una función cuadrática y visualizar el resultado. En resumen, «SciPy» proporciona una amplia gama de métodos de optimización que pueden ser aplicados a diferentes problemas, ofreciendo soluciones eficientes y precisas.

Saludos.

ALGORITMOS DE ORDENACIÓN EN PYTHON: ORDENACIÓN POR MEZCLA.

Continuamos, esta semana, con el repaso a los principales algoritmos existentes, para ordenar los elementos de una lista y sus respectivas implementaciones en Python. Hoy es el turno del llamado ‘ordenamiento por mezcla‘ (‘merge sort‘ en inglés). Consistente en una técnica eficiente basada en la estrategia «divide y vencerás». Esta metodología implica dividir repetidamente el arreglo en partes más pequeñas, ordenar cada parte por separado y luego combinarlas en un arreglo finalmente ordenado.

COMO FUNCIONA.

La singularidad del ‘ordenamiento por mezcla‘ radica en su enfoque recursivo, consistente en dividir el arreglo hasta alcanzar sub-listas de un solo elemento (lo que se conoce como el caso base). Luego, se fusionan estas sub-listas de forma ordenada, creando gradualmente una lista ordenada completa. Este algoritmo es conocido por su eficiencia en la ordenación de grandes conjuntos de datos y su estabilidad al preservar el orden de elementos con claves iguales.

IMPLEMENTACIÓN EN PYTHON.

La implementación de este algoritmo en Python se basa en la división recursiva del arreglo y la combinación de las sub-listas ordenadas. Veamos un sencillo ejemplo en el que usaremos una función (a la que hemos llamado ‘merge_sort()‘) que tomará como argumento una lista de valores desordenados (‘lista_elementos‘) y nos devolverá dicha lista ordenada (que se almacenará en la variable ‘lista_ordenada‘):

Aquí, la función ‘merge_sort()‘ va dividiendo recursivamente un arreglo en mitades más pequeñas hasta que quedan solo elementos individuales. Luego, combina y ordena esas mitades en un solo arreglo ordenado. Todo ello verificando si el arreglo tiene más de un elemento, (dividiéndolo en dos mitades en tal caso). Para después, ordenar recursivamente cada mitad y fusionar las mitades ordenadas en un solo arreglo. El proceso de fusión compara los elementos de las mitades ordenadas y los coloca en orden en el arreglo original. Después, copia cualquier elemento restante de las mitades en el arreglo. Terminado este proceso, devuelve la lista ordenada que será almacenada en la variable «lista_ordenada» que es la finalmente será impresa.

OUTPUT:

CONCLUSION:

El ‘ordenamiento por mezcla‘ destaca por su eficiencia en grandes conjuntos de datos y su estabilidad al mantener el orden entre elementos iguales. Sin embargo, puede requerir más memoria que otros algoritmos debido a su enfoque de dividir y fusionar. Además, la implementación recursiva podría impactar el rendimiento con arreglos enormes. No obstante, constituye una eficaz herramienta de ordenación utilizada en diversas aplicaciones donde se necesita una ordenación estable y eficiente de datos.

Saludos.

INTRODUCCIÓN AL APRENDIZAJE AUTOMATICO CON ‘SCIKIT-LEARN’ EN PYTHON.

El aprendizaje automático es una rama de la inteligencia artificial, la cual, se ha convertido en una herramienta esencial en la resolución de problemas y la toma de decisiones en una amplia variedad de campos. Desde la detección de fraudes hasta la recomendación de productos y la visión por computadora, el aprendizaje automático desempeña un papel crucial en la automatización de tareas complejas. Python, con su rica colección de bibliotecas, es uno de los lenguajes más populares para trabajar en aprendizaje automático, y ‘scikit-learn‘ es una de las bibliotecas más destacadas en este campo.

En este artículo, exploraremos los conceptos básicos del aprendizaje automático y cómo puedes comenzar a usar ‘scikit-learn‘ para crear tus propios modelos de aprendizaje automático en Python.

¿QUE ES EL APRENDIZAJE AUTOMATICO?

El aprendizaje automático es una disciplina que se enfoca en el desarrollo de algoritmos y modelos que permiten a las computadoras mejorar su rendimiento en tareas específicas a través de la experiencia. En lugar de programar reglas explícitas para realizar una tarea, el aprendizaje automático permite a las máquinas aprender de los datos y hacer predicciones o tomar decisiones basadas en esa experiencia. Este proceso suele constar de una serie de pasos que, a continuación, pasamos a enumerar:

1- Recopilación de datos: Reunir un conjunto de datos que contenga ejemplos y etiquetas. Los ejemplos son las entradas, y las etiquetas son las salidas deseadas.

2- Preprocesamiento de datos: Limpiar, normalizar y transformar los datos para que sean adecuados para su uso en modelos de aprendizaje automático.

3- Selección del modelo: Elegir el tipo de modelo de aprendizaje automático adecuado para la tarea, como regresión, clasificación o clustering.

4- Entrenamiento del modelo: Utilizar los datos de entrenamiento para ajustar los parámetros del modelo y permitir que «aprenda» de estos.

5- Evaluación del modelo: Probar el modelo en un conjunto de datos de prueba para evaluar su rendimiento.

6- Predicción y toma de decisiones: Utilizar el modelo entrenado para hacer predicciones o tomar decisiones en función de nuevos datos.

EJEMPLO DE USO DE ‘SCIKIT-LEARN’.

scikit-learn, a menudo abreviado como ‘sklearn‘, es una biblioteca de código abierto ampliamente utilizada en la comunidad de Python para el aprendizaje automático. Proporciona una amplia gama de algoritmos y herramientas para tareas comunes de aprendizaje automático, como clasificación, regresión, clustering y reducción de dimensionalidad. A continuación, veremos cómo comenzar a trabajar con ‘scikit-learn‘.

Para poder empezar a trabajar con ‘scikit-learn‘ antes deberemos realizar la oportuna instalación de esta librería en nuestro sistema:

Una vez hecha la instalación pasaremos a ver un sencillo ejemplo en el que nos propondremos a crear un modelo para clasificar flores, para el cual usaremos el conjunto de datos ‘Iris‘ y el algoritmo ‘K-Nearest Neighbors (KNN)‘. Para ello, empezaremos importando los recursos de ‘scikit-learn‘ que vamos a necesitar. Donde ‘datasets‘ contiene conjuntos de datos de ejemplo, ‘train_test_split‘ se utiliza para dividir los datos en conjuntos de entrenamiento y prueba, y ‘KNeighborsClassifier‘ es una implementación del algoritmo de ‘K-Nearest Neighbors (KNN)‘ para clasificaciones:

Tras ello, pasamos a cargar el conjunto de datos ‘Iris‘ (el cual, se utiliza habitualmente en ejemplos de aprendizaje automático). En este conjunto, ‘iris.data‘ contendrá las características (o atributos) de las flores, e ‘iris.target‘ contendrá las etiquetas (las clases) que nos indican a que especie de flor pertenece cada conjunto de atributos. Estos datos se almacenarán en la variable ‘X‘ y las etiquetas en la variable ‘y‘:

Una vez que tenemos los datos con los que vamos a trabajar, el siguiente paso será dividir estos datos en un conjunto de entrenamiento (‘X_train‘ e ‘y_train‘) y otro para probar el modelo entrenado (‘X_test‘ e ‘y_test‘). Para establecer esta división usaremos el método ‘train_test_split()‘ en donde mediante el argumento ‘test_size = 0.2‘ estaremos indicando que queremos emplear el 20% de los datos como datos de prueba ( y por tanto, el 80% como datos de entrenamiento ):

A partir de esta división de los datos en conjuntos de entrenamiento y prueba, podemos proceder a la creación entrenamiento y prueba de nuestro modelo:

Para ello, empezamos creando un clasificador ‘KNN‘ (que guardamos en la variable ‘knn‘) con un valor de ‘n_neighbors‘ igual a 3. Indicándole al algoritmo ‘KNN‘ que considere los tres vecinos más cercanos para tomar una decisión de clasificación. Tras ello, usaremos el método ‘fit‘ del clasificador ‘KNN‘ para entrenar el modelo a partir del conjunto de datos de entrenamiento. De esta forma, el modelo aprenderá a asignar los datos de entrada ‘X_train‘ a las etiquetas correspondientes de ‘y_train‘.

Una vez que nuestro modelo esté entrenado, pasaremos a realizar las predicciones. Para ello, podremos utilizar el método ‘predict()‘ que realizará las predicciones en el conjunto de prueba ‘X_test‘, almacenándose estas en la variable ‘predictions‘:

OUTPUT:

Finalmente, calculamos la precisión del modelo comparando las predicciones con las etiquetas reales de prueba ‘y_test‘, mediante el método ‘.score()‘. Mostrándose el grado de precisión:

OUTPUT:

CONCLUSION:

scikit-learn‘ es una muy útil librería para el aprendizaje automático en Python, la cual, permite crear modelos de manera sencilla y eficaz. Este artículo ha proporcionado una introducción básica al aprendizaje automático y cómo empezar a trabajar con ‘scikit-learn‘. A medida que explores más, descubrirás que esta librería ofrece una amplia gama de algoritmos y herramientas para abordar una variedad de problemas de aprendizaje automático. ¡Así que no dudes en sumergirte en el emocionante mundo del aprendizaje automático con Python y scikit-learn!

Saludos

AJUSTE DE BRILLO Y CONTRASTE EN IMAGENES, CON ‘OpenCV’ Y ‘Python’.

El ajuste de brillo es una técnica común en el procesamiento de imágenes y visión por computadora. Permite corregir imágenes oscuras, realzar detalles en imágenes sobreexpuestas y ajustar la calidad visual en diversas aplicaciones, como fotografía, detección de objetos y más. En este artículo, exploraremos cómo ajustar el brillo de una imagen utilizando ‘OpenCV‘ y Python. Mostrando varios ejemplos para que puedas comprender y aplicar esta técnica de manera efectiva. Como es habitual, utilizaremos una imagen de muestra para realizar las operaciones:

Como es habitual, antes de empezar deberemos asegurarnos de tener instalados los recursos y librerías necesarios para efectuar las operaciones que queremos realizar. Para esta ocasión, deberemos instalar previamente (si no lo hemos hecho ya) las librerías ‘OpenCV‘ (para manipulación de imágenes) y ‘Numpy‘ (para trabajar con arreglos):

Una vez que tengamos instalado todo lo necesario para trabajar, crearemos un nuevo archivo ‘ajuste_brillo.py‘ en el que empezaremos importando las librerías necesarias para, a continuación, cargar la imagen original (bien introduciendo el nombre de la misma si se encuentra en el mismo directorio del de trabajo, bien introduciendo la ruta hasta la misma en caso contrario):

Una vez cargada la imagen, podremos empezar a ajustar el brillo de la misma. Para ello existen dos funciones en ‘OpenCV‘: ‘cv2.add()‘ con la que podremos incrementar el brillo de la imagen y ‘cv2.subtract()‘ para disminuirlo. Ambas funciones toman dos argumentos: El nombre de la imagen fuente, una matriz que contiene valores de brillo (matriz creada con ‘numpy‘) la cual multiplicaremos por un factor de incremento o decremento de brillo. Empecemos con un ejemplo en el que vamos a incrementar el brillo de la imagen original mediante la función ‘cv2.add()‘ y un factor de incremento de 50, almacenado en la variable ‘brightness_increase‘:

OUTPUT:

Tal y como hemos señalado, podemos disminuir el brillo de nuestra imagen, usando la función ‘cv2.subtract’, multiplicando la matriz de la imagen original por un factor de decremento (variable brightness_decrease‘) de 50. Como en el caso anterior, usaremos la función ‘cv2.imshow()‘ para mostrar tanto la imagen original como su versión modificada:

OUTPUT:

Por otra parte, el ajuste de brillo por sí solo puede no ser suficiente en algunos casos. Para un control más completo, podemos combinar el ajuste del brillo con el del contraste. Para ello podemos usar la función ‘cv2.convertScaleAbs()‘. Esta función toma tres argumentos: la imagen, el factor de escala para el contraste (alpha) y el valor de desplazamiento para el brillo (beta). A continuación mostramos dos ejemplos en los que aumentamos y disminuimos el brillo y contraste de nuestra imagen fuente:

OUTPUT:

OUTPUT:

Como se ve, es muy fácil el efectuar el ajuste de brillo y contraste sobre una imagen usando Python y la librería ‘OpenCV‘. Estos ajustes son útiles en diversas aplicaciones, desde el mejoramiento de imágenes hasta la visión por computadora. A partir de aquí puedes experimentar con los ejemplos proporcionados y personalizar los valores para obtener los resultados deseados en tus imágenes.

Saludos.

ALGORITMO ‘GLC’ PARA GENERACIÓN DE VALORES PSEUDO ALEATORIOS, E IMPLEMENTACIÓN EN PYTHON.

El generador lineal congruente (‘GLC‘ o ‘LCG‘ por sus siglas en inglés) es uno de los algoritmos más simples para generar secuencias de números pseudo aleatorios. El cual, funciona mediante la aplicación de una serie de operaciones matemáticas (usando un conjunto de variables) a un valor inicial (al que solemos llamar «semilla«) para generar una secuencia de números que parecen ser aleatorios. No siéndolo en realidad, ya que, introduciendo un mismo valor para la «semilla», se obtendrá siempre la misma secuencia de valores.

COMO FUNCIONA:

La idea detrás de un GLC es bastante simple: se comienza con un valor inicial llamado «semilla» y se utiliza una serie de operaciones matemáticas para generar una secuencia de números. Efectuándose los cálculos de manera recursiva, mediante la siguiente fórmula:

Xn + 1​=(a x Xn ​+ c) x mod m

En donde ‘Xn+1‘​ es el siguiente número en la secuencia, ‘Xn‘​ es el número actual en la secuencia, ‘a‘ es un multiplicador, ‘c‘ es un incremento constante y ‘m‘ es el módulo, que determina el rango de los números generados.

Aquí, el valor de la semilla inicial ​ ‘X0‘ es crucial, ya que determina completamente la secuencia de números que se generará. De modo que si conocemos esta y los parámetros ‘a‘, ‘c‘, y ‘m‘, podemos predecir el resto de valores de la secuencia. Esto es útil en aplicaciones donde se necesita reproducibilidad, como pruebas o simulaciones.

Sin embargo, elegir valores apropiados para ‘a‘, ‘c‘, y ‘m‘ es esencial para obtener una secuencia de números pseudo aleatorios que parezcan aleatorios y que no exhiban patrones predecibles. Los valores de estos parámetros deben cumplir ciertas propiedades matemáticas para garantizar que la secuencia sea lo más uniforme y «aleatoria» posible. Elegir valores inadecuados puede resultar en secuencias con patrones evidentes o ciclos cortos.

IMPLEMENTACIÓN EN PYTHON:

Una vez visto en que consiste y como funciona el algoritmo ‘GLC‘ es hora de poner un sencillo ejemplo de implementación usando Python. Para ello crearemos un archivo al que llamaremos ‘lcg.py‘ con el siguiente código:

Como puede verse hemos creado una clase ‘LCG‘ que definimos con el constructor ‘__init__‘ que toma los cuatro parámetros: ‘seed‘ (semilla inicial), ‘a‘ (multiplicador), ‘c‘ (incremento constante), y ‘m‘ (módulo). Tras ello, el método ‘random‘, el generador actualiza su estado (almacenado en ‘self.state‘) usando la fórmula del GLC de la que hablamos más arriba pero aplicada a nuestro código Python: ‘self.state = (self.a * self.state + self.c) % self.m’. Para luego, devolver un número pseudo aleatorio normalizado en un rango de 0 a 1 mediante la división de ‘self.state‘ por ‘self.m‘. Ya fuera de la clase, se establecen los valores para los parámetros de un ‘LCG‘ específico: ‘seed‘, ‘a‘, ‘c‘, y ‘m‘. Siendo estos valores los que determinarán la secuencia resultante. Finalmente tras crear la instancia de la clase ‘LCG‘, (a la que hemos llamado ‘generador()‘) ejecutamos un bucle que llama al método ‘random‘ del generador 5 veces e imprime los números pseudo aleatorios obteniendo 5 valores pseudo aleatorios:

OUTPUT:

Obtenemos una secuencia de valores con apariencia de aletoriedad que en realidad vienen determinados por la semilla inicial (42 en este caso) introducida y el resto de variables. A su vez, podemos enmarcar ese último bucle (que se repetirá 10 veces) dentro de otro que se repita 3, para ilustrar como la secuencia generada es siempre la misma:

OUTPUT:

CONCLUSIÓN:

En conclusión, hemos explorado el algoritmo Generador Lineal Congruente (GLC) y su implementación en Python. De modo que hemos visto como estos constituyen una forma simple pero poderosa de generar números pseudo aleatorios a partir de una semilla inicial mediante el empleo de operaciones matemáticas. A pesar de su simplicidad, son ampliamente utilizados en una variedad de aplicaciones, desde simulaciones y juegos hasta experimentos y modelado de procesos. Sin embargo, es crucial tener en cuenta que los parámetros de un GLC deben ser seleccionados cuidadosamente para evitar patrones predecibles en la secuencia de números generados. Además, los GLCs no son apropiados para aplicaciones críticas de seguridad, donde se requieren generadores de números aleatorios criptográficamente seguros. En resumen, comprender el GLC y su implementación en Python proporciona una base sólida para la generación de números pseudo aleatorios en una variedad de contextos, permitiendo la creación de aplicaciones y simulaciones más realistas y efectivas.

Saludos.