Python Básico: Preparando nuestro entorno de desarrollo de Machine Learning con Python

En el presente capítulo aprenderemos qué es Python y cómo preparar nuestro entorno para desarrollar soluciones de Machine Learning empleando la distribución de Python Anaconda, el editor de código Visual Studio Code y los Jupyter Notebooks.

Python

Python es un lenguaje de programación orientado a objetos de código abierto que popularmente se emplea para:

  • Desarrollo del lado del servidor de aplicaciones web
  • Desarrollo software con bases de datos
  • Matemáticas complejas
  • Estadística
  • Machine learning
  • Ejecución de comandos de sistema

En el mercado podemos encontrar una variedad de distribuciones o implementaciones de Python como: CPython, IronPython, WinPython, Jython, PyPy, MicroPython, Anaconda, ActivePython, entre otros. Cada uno de ellos aporta ventajas especiales para determinados sistemas, plataformas de desarrollo o tipos de soluciones.

Particularidades

  • Python emplea saltos de línea para completar las instrucciones, a diferencia de otros lenguajes de programación que suelen usar “;”.
  • Python hace uso de la sangría (caracteres en blanco al comenzar una instrucción) para definir el contexto de los bucles, funciones o clases, a diferencia de otros lenguajes de programación que suelen utilizar corchetes para este propósito.

Anaconda

Descargar Python 3 desde https://www.python.org instalar cada uno de los paquetes necesarios para trabajar en Data Science puede ser tedioso, sobretodo para aquellos que recién estamos empezando. Por ello, una de las mejores alternativas para levantar nuestro entorno es Anaconda, la cual es una distribución de Python que viene lista con todo lo que necesitamos para Machine Learning y Data Science, asímismo cuenta con una intuitiva interfaz gráfica que nos permitirá organizar, instalar, actualizar y desinstalar los paquetes de forma muy sencilla y amigable.

Descarga

Para nuestro objetivo de aprendizaje, lo ideal será descargar la Edición Individual desde https://www.anaconda.com

El instalador de Python 3.8 para Windows (64-bits) pesa aproximadamente 468 MB.

Instalación

Antes de empezar la instalación asegurémonos de tener todos los permisos o privilegios de administrador en el sistema que nos encontremos.

Hagamos doble click sobre el instalador y sigamos por el asistente de instalación. Notemos que el espacio requerido para la instalación es de aproximadamente de 2.7 GB

Seleccionemos la opción avanzada “Registrar Anaconda3 como el Python 3.8 de sistema” y continuemos para que el asistente pueda instalar Python y cada uno de los paquetes que necesitaremos.

En la carpeta de destino de la instalación también se creará un ejecutable llamado Uninstall-Anaconda3.exe que nos permitirá efectuar la desinstalación en el momento que se requiera.

Configuración

Una vez completada la instalación, vayamos a “Propiedades del Sistema“. Podemos ingresar a través de la ruta “Panel de Control > Seguridad o Sistema > Sistema” o haciendo click derecho sobre Mi PC e ingresando a Propiedades.

Desde la parte inferior de la sección de “Avanzado“, ingresemos a la vista de “Variables de Entorno“, seleccionemos “Path” y demos en Editar. En esta parte debemos agregar una nueva entrada que apunte a la carpeta Scripts en el lugar instalación de Anaconda, que en nuestro caso sería “C:\anaconda3\Scripts”.

Luego, ejecutemos Anaconda Navigator desde nuestra lista de programas instalados en el sistema.

En la vista de inicio, esta aplicación nos permite instalar o ejecutar otras aplicaciones relacionadas al desarrollo de Machine Learning, Minería de Datos o Estadística. Algunas de ellas, como Glueviz o Orange 3, nos pueden ayudar en la visualización de datos a través de una interfaz gráfica, pero son limitadas en relación al desarrollo de modelos de Deep Learning con redes neuronales o proyectos que requieran la integración con un sistema de control de versiones y de despliegue.

En la vista de ambientes, podemos actualizar, eliminar o degradar los paquetes de un ambiente de desarrollo hacia alguna versión específica que necesitemos.

También podemos crear nuevos ambientes y personalizarlos para que trabajen con paquetes y versiones distintas de Python en caso necesitemos varios ambientes de desarrollo con diferente conjunto de paquetes para diferentes proyectos.

Anaconda Prompt o terminal

Para trabajar con Python a través de una interfaz de línea de comandos (CLI) en Windows, debemos ejecutar “Anaconda Prompt (anaconda 3)“, y, si nos encontramos en macOS o Linux, debemos abrir la terminal.

Y seguido de ello, debemos ejecutar el comando python.

Visual Studio Code

Segun Wikipedia, Visual Studio Code es un editor de código fuente desarrollado por Microsoft para Windows, Linux y macOS. Incluye soporte para la depuración, control integrado de Git, resaltado de sintaxis, finalización inteligente de código, fragmentos y refactorización de código.

Descarga

Parece algo útil así que descargémoslo desde https://code.visualstudio.com

El instalador de Visual Studio Code 1.53 para Windows (64-bits) pesa aproximadamente 68 MB.

Instalación

Hagamos doble click sobre el instalador y sigamos por el asistente de instalación. El espacio que se requerirá para la instalación es de aproximadamente de 259.7 MB

Seleccionemos la opción “Add to PATH” y ambos “Add ‘Open with Code’ action to Windows Explorer” ya que el primero permitirá la ejecución del comando code desde la línea de comandos de sistema y el segundo agregará un acceso rápido para abrir archivos y carpetas con Visual Studio Code.

Terminada la instalación, ejecutemos Visual Studio Code e ingresemos a la vista de Extensiones (“Ctrl+Shift+X”) para buscar e instalar las siguientes 2 extensiones: Python (Microsoft) y Jupyter (Microsoft)

Nuevo archivo Python

Abramos nuestra carpeta de trabajo con “Abrir con Code”.

Y notemos que, ya sea creando los archivos Python (.py) desde el Explorador de Archivos del sistema o desde Visual Studio Code, igual se muestran en el siguiente explorador:

Para ejecutar Python debemos ubicarnos en la línea de código de interés o seleccionar las líneas de código que deseamos ejecutar y presionar “Shift+Enter”.

Jupyter Notebook

Jupyter Notebook (.ipynb) es un tipo de documento en formato JSON, que contiene toda la información necesaria para construir una lista ordenada de celdas de entrada/salida que pueden contener código (Python, C#, R, etc.), Markdown y gráficos.

No necesitamos descargar ni instalar nada puesto que Anaconda y Visual Studio Code ya gestionaron todo lo necesario para emplear este tipo de documento en nuestros proyectos.

Nuevo Jupyter Notebook

Abramos la lista de comandos de Visual Studio Code con “Ctrl+Shift+P” y ejecutemos “Jupyter: Create New Blank Jupyter Notebook” para crear nuestro primer documento.

Si deseamos abrir un archivo .ipynb con Visual Studio Code solo debemos darle click derecho y seleccionar la opción “Abrir con Code”.

Finalmente, podemos presionar “Shift+Enter” o usar alguna de las opciones disponibles en la parte superior del documento para ejecutar la(s) celda(s) de nuestro Jupyter Notebook.

Otras lecturas

Eche un vistazo a algunos de estos:

Artículos

Working with Jupyter Notebooks in Visual Studio Code
https://code.visualstudio.com/docs/python/jupyter-support

Getting started with Anaconda — Anaconda documentation
https://docs.anaconda.com/anaconda/user-guide/getting-started/

[Xamarin] ¿Primera vez publicando con Visual Studio y iOS 11.2?

Si es tu primera vez publicando una aplicación iOS 11.2 usando Visual Studio para Windows, hay algunas cosas que quiero compartirte.

1. Assets Catalog

Usa un Asset Catalog para los logos de tu aplicación en vez de la carpeta Resources. Si hay logos en la carpeta Resources, recomiendo eliminarlos juntos con las referencias que existan en el archivo Info.plist porque ya no son necesarios. Con ayuda de tu explorador de archivos asegurate que el Asset Catalog con el cual estas trabajando se ubique dentro de la carpeta Resources, si es necesario modificar el .csproj y reiniciar Visual Studio, tendrás que hacerlo. Si no sabes como generar el Asset Catalog puedes ayudarte del iOS Manifest Editor, dando click derecho sobre el Info.plist, seleccionando Abrir Con… y ubicándote en la sección Visual Assets.

2. Provisioning Profiles

Conseguir un perfil de aprovisionamiento dependerá de la vigencia de tu cuenta en el portal de desarrollo de apple y es algo que no cubriré en este momento. Mayor información sobre el perfil de aprovisionamiento lo pueden conseguir acá: https://docs.microsoft.com/en-us/xamarin/mac/deploy-test/publishing-to-the-app-store/profiles

Lo que quiero resaltar acá es que luego de configurar los perfiles de aprovisionamiento adecuados tenemos que refrescarlos en el ambiente de desarrollo de la siguiente forma: XCode > Preferences > Accounts.

3. IPA

Con respecto al IPA solo recordermos que tenemos que seleccionar el perfil de aprovisionamiento adecuado, si es que vamos a desplegar a un iPhone usaríamos un perfil de Desarrollo, pero si vamos a publicarlo en la tienda ya sea para producción o test, tendremos que seleccionar un perfil de Distribución. Luego de eso, seleccionamos la opción Ad Hoc para el build apuntando a un iPhone.

Una vez que damos Build tenemos que permitir el uso de la firma registrada a nuestra instancia de la MAC para compilar correctamente.

Luego buscamos el archivo .ipa en bin > Ad Hoc y lo subimos al AppStore usando el Application Loader. Cuando termine de subir tenemos que esperar el correo de confirmación de Apple para saber si el build es una compilación válida.

4. TestFlight

Ahora ingresemos a itunesconnect.apple.com/, creamos nuestra aplicación indicando algunos datos y concentrémonos en TestFlight. Apple no permite subir aplicación de prueba a la tienda, así que si quieres probar alguna aplicación, tendrás que usar TestFlight.

Del lado izquierdo creamos nuestros grupos de usuarios de pruebas y del lado derecho podemos relacionarlos con algún build en específico que hayamos subido.

Es una interfaz muy intuitiva, mientras vamos agregando usuarios, ellos van recibiendo un correo para poder probar nuestra aplicación y todos felices.

[Xamarin] Usando Mapbox en Xamarin.Android

¿Alguna vez has tenido la necesidad de usar un proveedor de mapas diferente al de Google Maps? Pues hoy quiero presentarte una alternativa y no te hablo de mostrar un mapa a través de un webview o algo similar, sino de MapBox y como es que lo puedes usar nativamente en Xamarin.Android.

Mapbox

Lo primero que tenemos que hacer es registrarnos en la página oficial de MapBox (https://www.mapbox.com), es un procedimiento gratuito que no toma mucho tiempo y con una cuenta dada de alta ya tenemos un token que nos permitirá inicializar los servicios de MapBox en nuestros futuros proyectos, si deseas más detalles sobre para qué sirve el token puedes visitar la siguiente página: https://www.mapbox.com/help/how-access-tokens-work/

Map Style

Seguido de ello tenemos que elegir con que estilo de mapa queremos trabajar ingresando a la página de mapas de MapBox https://www.mapbox.com/maps/. Vale mencionar que MapBox también te permite crear tus propios estilos para personalizar los mapas, pero no entraremos en esos detalles, así que simplemente elijamos con qué estilos deseamos trabajar.

Nuget

Lo que viene ahora es crear el proyecto y mediante Nuget descargar los componentes correspondientes a Naxam.Mapbox.Droid 5.3.2

Ya con los componentes listos, podemos proceder a hacer lo siguiente para disfrutar de nuestro nuevo mapa.


[.NET] Entendiendo el Patrón de Repositorio

Implementar el patrón de repositorio es una práctica muy común en aquellos proyectos que necesitan trabajar con datos externos, ya sea esto a través de bases de datos, servicios web, archivos u otros.

Este patrón nos ayuda mejorar la mantenibilidad y la capacidad de prueba. Con la correcta separación de intereses, nuestra lógica de negocio ya se puede concentrar en el negocio en sí y no preocuparse en operaciones de bajo nivel, como abrir una conexión a una base de datos o algún socket.

Este patrón nos habla de una capa intermedia entre la lógica de negocio y la fuente de datos, pero hay muchas formas de entenderlo así que exploremos algunos puntos.

1. Reponsabilidad única

En el siguiente programa estamos accediendo a una base de datos para obtener un listado y también para mostrarlo en pantalla, pero todo se encuentra en una sola clase violando el principio de diseño de responsabilidad única.

Lo ideal sería mover la lógica correspondiente a la conexión a base de datos a una una clase aparte en otro proyecto de librería de clases.

Y terminar con la clase principal de la siguiente forma:

2. Repositorios genéricos

En muchas operaciones con datos, creamos, modificamos, eliminamos o consultamos registros, por ello es usual considerar la creación de una interfaz para un repositorio genérico.

Sin embargo, esta idea nos puede llevar a encontrarnos con situaciones muy parecidas a estas:

No es que se acabe el mundo, pero hay que tomarlo en consideración ya que podría dificultar el diseño de nuestras aplicaciones y viola un principio de diseño.

3. Segregación de interfaces

Implementar las interfaces adecuadamente nos ayuda a tener mejores resultados. Si creamos una interfaz como esta:

Tendremos la capacidad de trabajar con diferentes implementaciones según la ocasión.

Y en nuestro programa principal solo nos preocupariamos de la interface y de como se realizaría la instanciación que necesitamos.

Algunos extienden esto usando inyección de dependencias, otros se organizan usando espacios de nombre y otros hacen cosas diferentes. La resolución o complejidad de esto ya depende de los requisitos del proyecto o elección de cada uno.

[.NET] ¿Cómo trabajar async con Enterprise Library?

Digamos que tienes un web service, sí, un web service. Y este, acaba de recibir una petición, si tu web service desea sobrevivir, lo que tendrá que hacer es hacer uso de algún Thread dentro de su Thread Pool. Mientras el procesamiento de cada petición no le tome demasiado a un Thread, podría no haber problema.

Pero en el caso contrario podriamos no solo dejar varias solicitudes en espera, sino también afectar el rendimiento de las demás tareas.

Antes de continuar, recordemos que la creación de un Thread es costosa en términos de memoria (1MB) y tiempo(500ms). Hay escenarios que lo justifican, pero aquellos dónde un Thread se queda bloqueado por esperar el resultado de alguna operación, simplemente no.

Lo bueno de este asunto es que desde .NET 4.5 y C# 5, la programación asíncrona nos permite fácilmente lidear con esta clase de situaciones, un claro ejemplo sería la forma en que HttpClient trabaja, pero igual nos podemos encontrar con casos que no estan listos para esto, por eso ahora veremos como trabajar asíncronamente con Enterprise Library.

En el siguiente código podemos apreciar un controllador que devuelve una lista de elementos.

Y en este otro, un método que logra establecer una conexión a una base de datos para recuperar algunos resultados.

Si una solicitud llega a nuestro servicio y nuestro Thread queda bloqueado por esperar el resultado de una gran consulta o la ejecución de una operación larga, la inmediata próxima solicitud exigirá que se tenga que usar otro Thread o se tenga que crear uno nuevo. Para este sencillo e hipotético ejemplo tendremos que realizar las siguientes modificaciones.

[.NET] ¡No hagan Dispose() en HttpClient!

Cuando desarrollamos un sistema conectado en .NET es probable que lo terminemos haciendo con HttpClient, esto es por todas las ventajas que nos trae:

  1. Fue diseñado especialmente para la creciente necesidad de las solicitudes bajo una arquitectura REST y Henrik F. Nielson, el autor inicial de HTTP, esta involucrado en su desarrollo y diseño.
  2. Puede ser usado en aplicaciones de escritorio para Windows, Linux o Mac, así como para aplicaciones móviles en Android o iOS y aplicaciones de IoT con Windows 10.
  3. Puede reusar DNS resueltos y te permite configurar facilmente headers y cookies.
  4. Una única instancia de HttpClient puede hacer solicitudes concurrentes.
  5. La API es sencilla y eso es genial para hacer pruebas.
  6. Todas las operaciones de espera son asíncronas.

Y otras ventajas más, pero el punto de este post esta en relación al error en la que solemos caer algunos cuando nos damos cuenta que HttpClient implementa la interfaz IDisposable.

¿Qué es lo que sucede?

En el siguiente ejemplo tenemos un programa que crea una nueva instancia de HttpClient por cada solicitud que se realiza.

Y al ejecutarlo, si bien las operaciones culminan con aparente normalidad, la verdad es que dejan varias conexiones abiertas.

Esto es porque las conexiones sobre TCP/IP no se cierran en su totalidad para permitir que los paquetes lleguen fuera de orden o que se vuelvan a transmitir. TIME_WAIT indica que el punto final de nuestro lado ha cerrado las conexiones, pero las conexiones se mantienen para que los paquetes retrasados puedan manejarse correctamente. Una vez que esto sucede, las conexiones se eliminarán luego de un período de tiempo de espera de 4 minutos.

Nuestro programa pudo haber abierto hasta 10 nuevos sockets hacia el servidor, pero ¿te imaginas qué podría pasar en el backend de algún proyecto? Simplemente nos veremos frente a un error similar este:

Unable to connect to the remote server
System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted

¿Qué podemos hacer?

La mejor solución es reusar una única instancia de nuestro HttpClient en vez de crear una para cada solicitud. Y no hay de qué preocuparse porque casi todas las operaciones son thread-safe: CancelPendingRequests, DeleteAsync, GetAsync, GetByteArrayAsync, GetStreamAsync, GetStringAsync, PostAsync, PutAsync y SendAsync.

Ahora, al reutilizar una instancia de HttpClient significa que se mantiene el socket hasta que se cierre, por lo que si se tiene una actualización de registro DNS en el servidor, el cliente nunca lo sabrá hasta que se cierre ese socket. Y esto puede ser otro gran problema, ¿qué pasaría si para nuestro backend hacemos un switch de IPs para pasar una actualización del proyecto a producción? ¡El cliente todavía estaría conectándose a la instancia anterior, osea a la versión anterior del proyecto!

HttpClient no verifica los registros DNS cuando la conexión está abierta y tiene sentido. Por eso tenemos que ir un poco más allá y establecer el valor por defecto de por cuánto tiempo el socket TCP, para un endpoint determinado, puede permanecer abierto.

Pero eso no es todo, una vez cerrada la conexión, nada te asegura de que al momento de que el HttpClient establezca una nueva conexión usando el mismo DNS, resuelva y se conecte a la nueva IP del servidor y esto ocurre porque la resolución del DNS se guarda en memoria. Por ello es que finalmente, también tenemos que hacer lo siguiente.

[.NET] ¿Cómo crear y publicar un paquete NuGet?

Es un hecho de que en la mayoría de proyectos software los desarrolladores reutilizamos componentes y librerias. Para los que trabajamos con Visual Studio, NuGet es uno de los facilitadores de paquetes, es genial, pero ¿cómo así aquellos paquetes aparecen en esa lista? ¿hay que pagar algo? Estas interrogantes las resolveremos en unos sencillos pasos:

Crear o seleccionar un proyecto de librería de clases

Lo primero que hay que hacer es crear o seleccionar un proyecto de librería de clases, para este ejemplo estoy usando un proyecto .NET Standard.

Configurar las propiedades del paquete

El segundo paso es configurar las propiedades del paquete, para ello vamos a propiedades del proyecto y nos ubicamos en la configuración de paquete. Aquí encontraremos los metadatos de nuestro de librería de clases. No todos los campos son obligatorios, solo asegúrense de tener un Id de paquete único.

Observemos que los campos de la licencia, proyecto y repositorio corresponden a un proyecto en GitHub y es que este proyecto lo he subido ahí. Probablemente se hagan preguntas sobre la licencia, pero no se precoupen por ello, porque si entramos a GitHub nos daremos cuenta que nos ayudan a generar uno.

Volviendo a los metadatos, solo queda mencionar que la imagen correspondiente al icono debes subirla a algun lado.

Ejecutar el comando de empaquetado

Ahora el tercer paso solo involucra hacer click en la opción empaquetar del proyecto, asegurándonos claro que este en Release.

Una vez hecho esto, solo confirmemos que nuestro paquete se generó correctamente.

Publicar el paquete

El cuarto y último paso, consiste en ingresar a nuestra cuenta de nuget.org, para ello solo iniciemos sesión gratuitamente con nuestra cuenta de Microsoft. Una vez hecho eso seleccionemos la opción Subir Paquete y busquemos nuestro archivo.

Luego solo revisemos que los metadatos son los que corresponden y en la parte de documentación podemos hacer referencia a nuestro README.

Simplemente copiando y pegando el enlace que obtenemos al dar click en Raw. Confirmamos que la documentación es la nuestra y damos en publicar.

Ahora para que nuestro paquete este disponible para el mundo deben pasar algunas horas, si queremos actualizar la documentación, podemos darle edit package y hacemos algo muy similar a lo que hicimos hace un momento.

Si ahora desde nuestro perfil seleccionamos la opción ver listado de paquetes, nos daremos cuenta que no estará nuestra última versión ahí, hay que esperar.

Pero si tenemos una anterior, desde ahí podremos darnos cuenta en la parte inferior que nuestra última versión esta pasando por un proceso de validación.

[.NET] Principio de Inversión de Dependencias (D)

Ahora veremos el último de los Principios de Diseño Orientado a Objetos, para el cual les recomiendo antes, revisar y entender el Principio de Responsabilidad Única, el de Abierto/Cerrado y el de Segregación de Interfaces.

Dicho esto, ya podemos empezar con el Principio de Inversión de Dependencias, el cual sostiene dos puntos clave, el primero de ellos es:

“Los módulos de alto nivel no deben depender de módulos de bajo nivel. Ambos deben depender de abstracciones.”

Entendamos los módulos de alto nivel como aquellos elementos de nuestro sistema que están más cerca de nuestro cliente, que bien podría ser una persona u otro sistema, y los de bajo nivel como aquellos que están más cerca al núcleo o centro de nuestro sistema.

El siguiente punto clave es:

“Las abstracciones no deben depender de detalles, son los detalles los que deben depender de abstracciones.”

Por ejemplo, cuando vamos a comprar a un supermercado y debemos recibir algún comprobante, independientemente a que sea una boleta o una factura, existe la operación “Emitir Comprobante”, y del mismo modo cuando falta poco tiempo para que acabe el servicio mensual de luz o agua, hay una suerte de “Enviar Notificación”, que bien puede ser por correo electrónico, un documento físico o una llamada telefónica.

Las abstracciones deben capturar el flujo o comportamiento esencial de nuestro sistema sin caer en especificaciones del detalle de su implementación.

Dejando estos dos puntos claros pasemos al siguiente ejemplo:

Podemos apreciar que hay una serie de operaciones en relación al pago de un carro de compras y se podría decir que no hay problema, pero la verdad es que esta situación esta cometiendo algunas infracciones. Y esto es así porque estamos trabajando con detalles, con implementaciones concretas, además de tener una clase que no solo es responsable de hacer un Checkout, sino también de inicializar los servicios que usaremos en todo el proceso.

Antes de proseguir con esto, debo mencionar que así como existen los principios de diseño orientado a objetos también existen una variedad de patrones de diseño que nos pueden ayudar dependiendo a la situación y en esta ocasión, elegiremos la inyección de dependencias por constructor.

Entonces, para el anterior ejemplo, lo adecuado sería definir las siguientes interfaces según las operaciones que hemos identificado:

Una vez definidas, ya podremos conseguir la siguiente actualización para la clase en cuestión y, como se puede apreciar, en el constructor de la clase se reciben las interfaces que previamente hemos definido.

La pregunta que viene ahora, ya que tenemos varias interfaces que eventualmente deben inicializarse, es: ¿Dónde inicializamos los objetos? Esto se puede realizar a través de un contenedor de inversión de control (IoC Container) o definiendo un constructor por defecto, pero para este ejemplo, las inicializaremos manualmente. Primero asegurémonos de implementar las interfaces:

Y una vez hecho eso, ya podemos continuar de la siguiente forma, definiendo clases concretas según las interfaces y enviando como parámetros de constructor todo lo necesario para hacer nuestro Checkout.

Como pueden ver, resulto un poco más trabajoso entender este principio, pero la verdad es que trae interesantes oportunidades. Por ejemplo, podemos tener diferentes implementaciones de las interfaces y realizar pruebas con mucha facilidad.

Para terminar, os quiero hacer acordar que estos principios de diseño son guías, si sientes que tu proyecto no amerita ser estricto con alguno de ellos, no te hagas problemas, lo importante es que sea eficiente.