Cambiar de lugar la leyenda de un gráfico, en Matplotlib

matplotlib

Si necesitas cambiar de lugar la leyenda en Matplotlib, puedes hacerlo directamente en la librería.

import matplotlib.pyplot as plt
sns.set(style="whitegrid")

grafico = sns.load_dataset("titanic")

g = sns.factorplot("class", "survived", "sex",
                   data=grafico, kind="bar",
                   size=6, palette="muted",
                   )
g.despine(left=True)
plt.legend(loc='upper left') 			#colocando la leyenda arriba a la izquierda
g.set_ylabels("survival probability")

… siempre habrá poesía

G.A. Becquer

Errores en Python

python error

En Python se dan dos tipos de errores principales. Los errores de sintaxis  y las excepciones

Los errores de sintaxis o interpretación, son muy comunes.

Su estructura suele ser la que aparece en el ejemplo siguiente:

>>> while True print('Hello world')
  File "<stdin>", line 1
    while True print('Hello world')
                   ^
SyntaxError: invalid syntax

En este caso el intérprete de Python, reproduce la línea responsable del error y muestra una “flecha” que apunta al primer lugar donde se detectó este.

En el ejemplo, el error se detecta en la función print(), ya que faltan dos puntos (‘:’) antes del mismo.

El error ha sido provocado (o al menos detectado) en el elemento que precede a la flecha. Dentro de la declaración del error se muestran el nombre del archivo y el número de línea, lo cual te permitirá localizar con facilidad su ubicación exacta.  

Excepciones

Se llama excepciones a errores detectados durante la ejecución del código que no son incondicionalmente fatales.

Esto quiere decir que pueden ser resueltos con una condición y por ello Python nos ofrece condiciones para manejarlos.

Cuando no son gestionadas por el código, resultan en en mensajes de error:

Veamos algunos ejemplos.

>>> 10 * (1/0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>> 4 + spam*3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'spam' is not defined
>>> '2' + 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "int") to str

Explicando un poco el ejemplo vemos que estrutura tiene.

En Python existen diferentes tipos de excepciones y el tipo a que corresponde se imprime como parte del mensaje.

En el ejemplo los tipos son: ZeroDivisionErrorNameError y TypeError.

La cadena mostrada como tipo de la excepción es el nombre de la excepción predefinida que ha ocurrido.

Esta convención es válida para todas las excepciones predefinidas del intérprete, y aunque no tiene por que ser así para excepciones definidas por el usuario, se recomienda su uso.

La parte anterior del mensaje de error muestra el contexto donde ocurrió la excepción, en forma de seguimiento de pila.

En general, contiene un seguimiento de pila que enumera las líneas de origen; sin embargo, no mostrará las líneas leídas desde la entrada estándar.

El resto del mensaje provee información basado en el tipo de la excepción y qué la causó.

La última línea de los mensajes de error indica qué ha sucedido.

Por último debemos saber que los nombres de las excepciones estándar son identificadores incorporados al intérprete (no son palabras clave reservadas).

En otro articulo hablare de como capturar las excepciones

Rotar los tick labels en matplotlib

seaborn

Puedes rotar los  tick labels  en Matplotlib, empleando el método tick_params() sobre los ejes (Axes objects), con que trabaja la librería, indicándole exactamente que quieres hacer.

ax.tick_params(axis='x', rotation=60)
#Esto rotará 60 grados las etiquetas, sobre el eje de las x.

Conoce mas como trabajar con los ticks en este árticulo

Espero modestamente que este artículo, sirva de ayuda a alguien.

Gracias

…..lo que realmente importa no es lo que te da la vida, sino lo que haces con ello….

Análisis de regresión simple.Python

logo python

En este post realizaré un análisis de regresión, en el que tomaremos una set de datos preparado previamente.

El problema real al que nos enfrentamos, es determinar la relación que pueda existir entre la cantidad de ventas de la empresa “El Dorado”, y el numero de vendedores que la han integrado durante el periodo que se estudia, que son 36 meses o sea los últimos 3 años.

El departamento ha cambiado de responsable en varias ocasiones, y cada uno ha aplicado políticas diferentes de ventas, algunas intensivas, buscando mayor productividad en las ventas, a bases de estímulos como bonos, primas, ascensos,  etc; y en otras ocasiones, en cambio,  se han aplicado medidas extensivas incrementando el numero de vendedores, en una afán por ampliar la cobertura de ventas.

Lo que vamos a hacer es implementar un análisis de regresión lineal.

La regresion lineal es una técnica estadística, que el machine learning adoptó y que incluye como uno de los algoritmos supervisados.

He escrito hace unos meses algún articulo sobre regresion lineal y resumiendo lo que hara este análisis es obtener una recta que se acerque lo mas posible a todos los puntos de datos representados en un plano.

En nuestro caso es una regresion simple (participan dos variables ) y la recta que buscamos obtener es, la mejor posible.

Esto quiere decir que de todas las rectas esta sea la que mejor se adapte al conjunto de puntos, lo que le permitirá tendencialmente  estimar o predecir valores, dentro del contexto de datos estudiados.

La recta tiene forma esta forma Y = mX + b;  donde Y es el resultado obtenido, X es la variable, m la pendiente (o coeficiente) de la recta y b el valor constante, que gráficamente expresa el “punto donde cuando X tiene valor cero, se produce la intercepción o corte con el eje Y.

 Su optimización o ajuste se logra aplicándole una función llamada de mínimos cuadráticos, o también conocida de error cuadrático.

Su nombre obedece a que esa funcion intenta minimizar el error existente entre los puntos o dados y los obtenidos, elevendo al cuadrado sus valores para evitar que se anulen.

De este modo el algoritmo, se centra en minimizar el coste de dicha función

Recordemos que los algoritmos de Machine Learning Supervisados, aprenden por sí mismos.

Utilizaremos un archivo de datos que ya tenemos, y que muestra el número de  ventas y vendedores por meses; o sea tendremos dos columnas: vendedores y ventas.

Y nuestro en nuestro análisis de regresión, lo que vamos a intentar  es determinar a partir de los vendedores que tenemos,  que valor podemos esperar en la ventas de acuerdo, a la relación dada entre ambas variables.

Trabajaremos con Jupiter Notebook,utilizaremos las librerías Pandas, SkLearn, Seaborn, Numpy, de modo que comenzaremos por ahí.

Importamos las librerías

Cargamos nuestro archivo en un dataset de pandas después de leerlo, definiendo el separador de columnas.

Adquirimos  la información de nuestro dataset, con el método info(). Observamos que tenemos dos tipos de datos : enteros en columna vendedores y decimales en la columna ventas.

Comprobamos la estructura del dataset, con el método shape, que nos dice que tenemos efectivamente dos columnas y 36 registros en cada una.

Con head(), visualizamos las 6 primeras filas de nuestro dataset

Convertimos por comodidad la columna venta a tipo entero, empleando el método astype() y guardamos esa transformación en un nuevo dataset, que es con el que continuaremos trabajando.

Definimos con columns(), los encabezados de las columnas

Obtenemos los valores estadísticos de nuestro dataset con el método describe()

Observamos entre otros valores,  que la media de vendedores es 23, con una desviación de 4,63; mientras que la de ventas es 42 millones y su desviación es de 7.12.

Visualizamos los datos, en gráficos, mostrando las columnas por separados

Empleando scatter mostramos  los puntos coloreados, separando los colores a partir de la media de vendedores (23)

En este punto creamos nuestra recta de regresion y visualizamos los coeficientes que la componen nuestra recta.

Nuestro error cuadrático no es elevado pero es alto y nuestra varianza esta más cerca de 0 que de 1, por lo que este modelo tal vez podría mejorarse.

La intersección (b), tiene un valor de 9,67…. donde se corta la recta cuando el valor en X es 0

En función de observar el comportamiento del modelo, asignamos valores diferentes para ver su comportamiento

Ahora visualicemos la recta dentro de nuestro gráfico

Podemos observar nuestros datos de diferentes formas, en este caso con la librería seaborn, vemos el comportamiento de los datos en los diferentes periodos y su relación.

Para mejorarla tenemos varios caminos, podemos aplicar métodos como el gradiente, podemos hurgar en los datos y añadir más variables predictivas, referidas por ejemplo a la competencia, la innovación o la aceptación de los productos, pasando de una regresión simple a una regresión múltiple, podríamos también ampliar la cantidad de registros buscando mas años, desechar los valores extremos, etc.

En otros artículos iré aplicando algunos de estos métodos, haciendo referencia a estos mismos datos.

Espero modestamente que este artículo, sirva de ayuda a alguien.

Gracias

«El amor es la guerra perdida, entre el sexo y la risa»

R.Arjona

Usar las ticks en matplotlib

seaborn

Las ticks en Matplotlib, son los marcadores que indican los puntos de datos en los ejes.

Normalmente  en Matplotlib, los  localizadores y formateadores predeterminados de  los ticks, están diseñados para ser suficientes en la mayor parte de los casos comunes, sin embargo la posición y las etiquetas de las ticks , se pueden manejar explícitamente para adaptarlos a nuestros requisitos.

Las funciónes xticks() y yticks(),  toma un objeto de lista como argumento y los elementos de la lista indican las posiciones de la acción correspondiente donde se mostrarán los ticks.

ax.set_xticks ([3,6,9,12,15])

En este caso, el método marcará los puntos de datos, en aquellas posiciones dadas con ticks.

Si lo que deseas en manejar los grados, y sus etiquetas, se pueden hacer mediante las funciones set_xlabels() y set_ylabels() respectivamente.

ax.set_xlabels ([«tres», «seis», «nueve», «doce», «quince»])

Esto mostrará las etiquetas de texto debajo de los marcadores en el eje x.

Veamos un ejemplo completo

import matplotlib.pyplot as plt
import numpy as np
import math
x = np.arange(0, math.pi*3, 0.05)
fig = plt.figure()
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8]) # eje principal
y = np.sin(x)
ax.plot(x, y)
ax.set_xlabel(‘angle’)
ax.set_title('sine')
ax.set_xticks([0,3,9,12])
ax.set_xticklabels(['cero','tres','nueve','doce'])
ax.set_yticks([-1,0,1])
plt.show()

Quién va en busca de montañas no puede detenerse a recoger las piedras del camino.

J. Martí

Error _io.TextIOWrapper

python error

Hablemos del mensaje de error _io.TextIOWrapper, que suele aparecer cuando intentamos imprimir un determinado archivo en Python.

Realmente aunque lo consideramos un error no lo es, sino que es mas bien un mensaje que nos indica que estamos intentando imprimir algo que no es correcto.

Veamos un ejemplo de como debería estar planteado nuestro código:

def  imprimir():
    #Abrimos el archive para imprimir.txt.
    nuevo_file = open('imprimir.txt', 'r')

    #lo leemos
    contenido = nuevo_file.read()

    #Imprimimos los datos dentro del objeto contenido
    print(contenido)

Revisa bien los elementos del código y recuerda que en Python todo, son objetos a los cuales les vamos aplicando funciones, cuyo tipo no necesita ser definido de antemano y que pueden variar su contenido.

Espero modestamente, que este post, sirva de ayuda  a alguien.

La turba enardecida se convierte en manada, y la manada mata.

Y.

Calcular el porcentaje de una columna en pandas

logo python

Veamos como  calcular el porcentaje de una columna en Pandas, para lo cual usaremos sus propia función sum()

Como sabemos Pandas trabaja con dataframes o marcos de datos y también queda claro, que el porcentaje se obtiene dividiendo  el valor total entre  la suma de todos los valores y luego multiplicando ese resultado por 100.

Lo que hacemos, no es otra cosa que aplicar este mismo procedimiento a la columna que deseamos analizar.

Primero sumaremos toda la columna con sum(), que es el método que se emplea para sumar en Pandas.

La sintaxis seria esta:

df [porcentaje] =(df ['resultado'] / df ['column_a_sumar'].sum()) * 100

Otros post sobre Python

Viéndolo en un ejemplo practico seria esto:

import pandas as pd 
import numpy as np 

#tenemos una matriz accesorios con dos columnas (periodos y cantidad)   
accesorios = { 
     'periodos': ['periodo_1', 'periodo_2', 'periodo_3', 
             'periodo_4', 'periodo_5', 'periodo_6', 
             'periodo_7'], 
     'cantidad': [100, 40, 47, 78, 89, 78, 64]} 

# instanciamos accesorios como un dataframe de pandas,
# y definimos sus columnas
   
accesorios = pd.DataFrame(accesorios,  
                   columns = ['periodos', 
                             'cantidad']) 
# calculamos la columna porcentaje, la cual se añade automaticmente # al dataframe accesorios. Dividimos la cantidad entre la suma de 
# la columna y la multiplicamos por 100
accesorios['porcentaje'] = (accesorios['cantidad'] / 
                  accesorios['cantidad'].sum()) * 100
  
accesorios

Como ven hemos calculado el porcentaje de la columna para saber que magnitud del total representa cada período.

La salida es:

Out[1]:
	periodos	cantidad	porcentaje
0	periodo_1	100	20.161290
1	periodo_2	40	8.064516
2	periodo_3	47	9.475806
3	periodo_4	78	15.725806
4	periodo_5	89	17.943548
5	periodo_6	78	15.725806
6	periodo_7	64	12.903226

Y esto es todo, espero ayudar a alguien con este post.

No discutas nunca con un imbécil, te llevará a su terreno y allí te ganará por experiencia

D.

Redondear decimales en Pandas con round y decimal

logo pandas

En esta ocasión hablaré de como redondear decimales en Pandas con round() y decimal().

Ya en antes, he hablado, de lo que significa, y cómo aplicar el redondeo de la mejor forma posible en Python.

Sabemos, que existen múltiples ocasiones, en las que podemos necesitar sustituir un valor de tipo entero, por otro con una cantidad de decimales dada;  o directamente asignar solo una cantidad de decimales a todos los valores dentro de una dataframe.

Veamos un ejemplo para mostrar las diferentes opciones.

Primero importamos las librerías.

Importamos el dataframe

Redondear decimales usando round() en Pandas

Es una función que  redondea un número de coma flotante, al número de lugares decimales proporcionados como segundo argumento de la función.

Su sintaxis es round(value, numero de decimales)

En este ejemplo redondeamos la columna 2 de un dataframe

Primero aplicamos la función series() de Pandas, definimos la función round() con los espacios que deseamo, para luego aplicar un bucle for, para recorrer la columna.  

En este caso la labor de round(), es colocar una coma flotante, y dejar la cantidad de decimales que le indicamos al redondear, como segundo parámetro.

Format() como apoyo

Otra forma, es utilizar format(), pero como su nombre indica, por si sola, no redondea, sino que formatea la salida de la cadena, dandole la estructura que deseamos.

format() es una propiedad de string, o sea trabaja con una cadenas, y por lo tanto no debe confundirse con valores numéricos

La sintaxis es algo como lo que sigue, cuando la usamos en solitario, aunque existen multiples combinaciones para aplicar formato.

En este caso estamos formateando la salida de un valor a porcentaje con solo dos decimales.

df['columna3'] = pd.str(["{0:.2f}%".format(val * 100) for val in df[' columna3']])

El formato de cadena le permite representar los números como desee. Puede cambiar el número de lugares decimales que se muestran cambiando el número antes de la f.  

Redondear decimales usando Decimal

Cuando necesitamos una adecuada precisión es recomendable usar decimal, ya que es mucho mas adecuado que round(), si buscamos exactitud.

Puedes ver este articulo sobre la diferencia entre round() y decimal()

La construcción de la sintaxis es como se ve en el ejemplo:

En el primer caso, solo ejecutamos una división, donde obtenemos un número de coma flotante.

En los ejemplos siguientes, lo que hacemos en indicarle a Python que estamos esperando un resultado en formato decimal.

En el segundo tomamos algunas de las propiedades del contexto y le decimos a Decimal que tipo de redondeo queremos.

En el tercer y ultimo calculo, solo tomamos el contexto predeterminado e indicamos el nivel de precision que deseamos.

En todos los casos hemos redondeado a dos espacios pero podríamos haber fijado cualquier cantidad de dígitos, que necesitáramos.

..se me ha olvidado ya el lugar de donde vengo, y puede que no exista el sitio adonde voy…

J.Sabina

Error IsADirectoryError

python error

IsADirectoryError  es un  tipo de error que puede aparecer en Python, cuando intentamos acceder a un archivo de forma errónea.

El error suele tener esta forma:

Traceback (most recent call last):
  File "miprograma.py", line 38, in <module>
    archivo()
  File "miprograma.py", line 28, in archivo
    descarga = open('/Volumes/MasterData/tiendas/informatica/tienda01/descargas', 'wb').write(miarchivo.content)
IsADirectoryError: [Errno 21] Is a directory: '/Volumes/MasterData/tiendas/informatica/tienda01/descargas'

Como puede verse, lo que sucede es que hemos escrito mal la ruta y en vez de dirigirla la petición hacia un archivo, la estamos dirigiendo a una carpeta.

Esto puede suceder cuando copiamos y pegamos, generalmente porque no hemos escrito el nombre del archivo.

Otros post sobre errores en Python

Espero modestamente, que este post haya ayudado a alguien.

Tres cosas necesitan las ovejas para andar en manadas, el miedo al perro, la voz de amo y que la de atrás temiendo quedarse sola empuje.

Y.

Pickle. serializar datos con Python

logo python

Al manejar datos, de gran volumen, que necesitamos por ejemplo guardar en archivos, para manejarlos con mayor facilidad, lo màs adecuado es emplear un modulo como Pickle, para serializarlos. 

El modulo pickle de Python, de que hablaré en ese post,  lo que hace es, serializar objetos para que puedan guardarse en un archivo y tener la opción de volver a cargarlos más adelante.

pickle() se utiliza para serializar y deserializar estructuras de objetos de Python,  esta acción es también conocida cómo clasificación o aplanamiento de los datos.

La serialización, en su explicación más simple no es otra cosa que  convertir un objeto que tenemos en la memoria, en un flujo de bytes que se puede almacenar en el disco o enviar a través de una red,  y que puede ser posteriormente recuperado, transformándolo nuevamente en un objeto Python deserializado.

Las ventajas de serializar nuestros datos, no es solamente que se puedan guardar en el disco para continuar trabajando con ellos, y que podamos también enviar nuestros datos a otros por TCP, o una conexión de socket.

Pickle es igualmente poderosa porque a través de ella podemos almacenar objetos de Python en una base de datos.

Sobre todo cuando trabajamos con algoritmos de aprendizaje automático, conocer su uso nos evitará tener que reescribir todo o entrenar el modelo nuevamente, ya que podemos guardarlos y recuperarlos cuando queramos.   

Datos

Pickle(), nos permite  serializar los siguientes datos:

Cadenas,

Listas,

Tuplas

Enteros

Flotadores

Booleanos,

Números complejos,

Diccionarios que contienen objetos serializables.

Dataframes

 Pickle(), también puede serializar las clases y funciones, incluso las lambdas.  En el caso de estas últimas se usa dill(), un paquete adicional diseñado para ello, a partir de un fork de multiprocessing(), el paquete de multiprocesamiento de Python

A pesar de su capacidad, elementos como los dict predeterminados, las clases internas, o los generadores pueden tener problemas para ser serializados.

Los dicts predeterminados, necesitan ser creados con una función a nivel de módulo.

Serializando archivos

Importamos pickle()  

import pickle

Creamos un diccionario  y luego estructuramos un archivo de salida llamado alumnos_dic.

#escribimos un diccionario sencillo
alumnos_dict = {'Jose': 7,'Arnoldo': 8,'Mario': 5, 'Maria': 78,'Amara': 50,'Rolando': 67,'Hemeregildo': 78,'Prudencio': 79,'Zoraida': 0}

Abrimos un archivo utilizando la función open(), para poder escribirlo en formato binario. En este articulo, puede leerse un poco mas sobre las opciones para usar open().

#abrimos nuestro archivo para escribir en formarto binario
alumnos_pick= open('alumnos', 'wb')

Serializamos el archivo inicial y obtenemos un nuevo objeto file, luego cerramos la conexión

#usamos dump para serializar
pickle.dump(alumnos_dict, alumnos_pick)
alumnos_pick.close()

Deserializar nuestro archivo

El proceso de volver a cargar un archivo serializado en Python, no es complejo.

Usaremos la función open () nuevamente, pero esta vez con 'rb' como segundo argumento.

alumnos_pick.close()

Lo que haremos será leer el formato binario con que serializamos anteriormente.

#usamos dump para serializar
pickle.dump(alumnos_dict, alumnos_pick)
alumnos_pick.close()

Asignamos su valor  a infile.

infile = open('alumnos','rb')

Para cargar el archivo utilizamos pickle.load (), con infile como argumento, al que asignaremos  a nuevo_alumnos.

nuevo_alumnos = pickle.load(infile)

El contenido del archivo ahora está asignado a esta nueva variable.

Nuevamente,  cerramos  el archivo al final.

infile.close()
nuevo_alumnos
output:{'Jose': 7, 'Arnoldo': 8, 'Mario': 5, 'Maria': 78, 'Amara': 50, 'Rolando': 67, 'Hemeregildo': 78, 'Prudencio': 79, 'Zoraida': 0}

Comparamos los archivos.

#comparamos ambos archivos
print(nuevo_alumnos==alumnos_dict)
print(type(nuevo_alumnos))
output: True 
<class 'dict'>

Comprimir archivos

Si el tamaño del archivo es grande, por ejemplo datasets, voluminosos, podemos ahorrar espacio comprimiendo, el archivo deserializado.

Hay diferentes vías, dos de ellas son bzip2 y gzip.  Puede ver otras en este articulo.

Su diferencia en esencia, radica en que  gzip  es más rápido, pero los archivos que crea bzip2, ocupan  la mitad de espacio que los que crea gzip.

Una cuestión importante y que puede tender a confundir es que deserializar, no es lo mismo que comprimir.  

La deserialización es la conversión de un objeto de una representación (datos en la memoria de acceso aleatorio (RAM)) a otra (texto en el disco); mientras que la compresión es el proceso de codificación de datos con menos bits, para ahorrar espacio en el disco.

Lo primero es importar bz2

import bz2

Luego como primer parámetro del método BZ2File, pasaremos el nuevo nombre del nuevo archivo compactado que se creará al ejecutarse el script

sfile = bz2.BZ2File('compress_alumnos', 'w')
pickle.dump(alumnos_dict, sfile)

Multiproceso

Pickle es especialmente sensible al multiprocesamiento, pues hay elementos como las funciones lambda que no pueden ser fácilmente serializadas.

Cuando necesitamos realizar tareas complejas que ocupan mucho espacio de memoria, es común distribuir esta tarea en varios procesos.

El multiprocesamiento, es la subdivisión de un proceso en varios que se ejecutan simultáneamente, generalmente en varias Unidades Centrales de Procesamiento (CPU) o núcleos de CPU, ahorrando tiempo, como es el caso de operaciones de entrenamiento de modelos de aprendizaje automático, la creación de redes neuronales, todos ellos procesos intensivos.

En Python, esto se hace usando el paquete de multiprocesamiento multiprocessing().

La ventaja de trabajar de esta forma, es que los procesos en que se divide una tarea no comparten espacio de memoria, y comparten datos entre ellos serializados 

En el ejemplo lo que haremos será crear una especie de abstracción llamada pool, para que trabaje en segundo plano procesando una tarea, y al que indicaremos cuantos procesadores empleará para ello.

#trabajando con multiprocesamiento
#importamos el modulo y creamos con la la funcion cos una tarea
import multiprocessing as mp
from math import cos
p = mp.Pool(2)
p.map(cos, range(10))
output:[1.0, 0.5403023058681398, -0.4161468365471424, -0.9899924966004454, -0.6536436208636119, 0.2836621854632263, 0.9601702866503661, 0.7539022543433046, -0.14550003380861354, -0.9111302618846769]

Si quisiéramos ejecutar en vez de cos() un lambda, nos lanzara un error, indicando que Pickle no puede serializar un lambda.

p.map(lambda x: 2**x, range(10))
output: .......
PicklingError: Can't pickle <function <lambda> at 0x7fe84683a830>: attribute lookup <lambda> on __main__ failed

Afortunadamente existe un modulo para resolver esto dill(), que pertenece a un fork, llamado pathos.multiprocessing

Pathos esta en desarrollo aun, y debe ser instalado desde github, según recomendaciones de su creador. Puedes ver este articulo en stackoverflow

El amor siempre empieza soñando y termina en insomnio

R.Arjona
Translate »