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

Como ponerle un alias a una tabla

laravel

Suele suceder que tengamos la necesidad de ponerle un alias a una tabla, si nos vemos obligado a ello, podemos hacer esto.

Otros posts sobre Laravel

$cars = Car::from('cars as c')
    ->join('marcas as m',function($join){
        $join->on('c.roles_id','=','m.id')->where('m.estado','=',1);
    })    
    ->select("c.*","m.name")
    ->where('c.estado','=',1)
    ->get();

Y listo, esto es todo.

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

Gracias.

…., si avanzo sígueme, si me detengo empújame, si retrocedo mátame…….

Ordenar las relaciones, en Laravel

laravel

En Laravel podemos ordenar las relaciones de acuerdo a diferentes parámetros, por ejemplo size()

class Category extends Model
{
	public function shoes()
	{
		return $this->hasMany('App\Shoe')->orderBy('size');
	}
}

Otro orden que podemos conseguir es al usar las tablas pivotes, para las relaciones belongsToMany.

Post sobre Laravel

En el siguiente ejemplo tenemos el modelo Role y el modelo User,  y estamos mostrando en una vista, la relación entre ambos de forma descendente, según la fecha en que fue creado, en grupos  de 15, por página.

class Role extends Model
{
	public function users()
	{
		return $this->belongsToMany('Role\User')->withTimestamps();
	}
}

@if ($roles->users->count() > 0)
	Asignación
	@foreach ($roles->users()->orderBy('rol_user.created_at', 'desc')->take(15)->get() as $user)
		...
	@endforeach
@endif

Y listo, esto es todo.

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

Gracias.

Subir montañas hermana a los hombres……

Crear prefijos a tabla y usarlos en consultas

laravel

Crear prefijos a tablas y usarlos en consultas, es algo perfectamente posible de hacer en Laravel

Podemos  crear un  prefijo a todas las tablas de nuestra Base de Datos,  basta con ir al archivo  config/database.php, y en la opción prefix, y añadir el que queremos usar

'mysql' => [
    'driver'    => 'mysql',
    'host'      => env('DB_HOST', 'localhost'),
    'database'  => env('DB_DATABASE', 'database'),
    'username'  => env('DB_USERNAME', 'root'),
    'password'  => env('DB_PASSWORD', ''),
    'charset'   => 'utf8',
    'collation' => 'utf8_unicode_ci',
    'prefix'    => 'prefijo_',
    'strict'    => false,
    'options' => array(),
],

En el caso de que realicemos consultas puras o  del tipo DB::raw tendremos que recordarle a Laravel el prefijo que usamos.

Leer otro articulo de Laravel
Primero  obtenemos el prefijo.

$db_prefix = DB::getTablePrefix();

Ahora dentro de la función DB::raw ingresamos el prefijo 

$productos = App\Producto::join("tipos","productos.tipos_id","=","tipos.id")
  ->leftJoin(DB::raw("(SELECT * FROM {$db_prefix}materials where {$db_prefix}materials.estado=1) as materials"),
    function($join){
      $join->on('productos.id','=','materials.productos_id');
    }
  )
  ->select(DB::raw("{$db_prefix}productos.*"))
  ->addSelect(DB::raw("DATE_FORMAT({$db_prefix}materials.created_at,'%d/%m/%Y %h:%i %p') AS materials_creado"))
  ->where('productos.estado','=',1)
  ->where('materials.pruebas_count','>',0)
  ->whereRaw(DB::raw("{$db_prefix}materials.etiquetas !=''"))
  ->get();
 $sql = "SELECT * FROM {$db_prefix}productos WHERE {$db_prefix}productos.estado = ? AND {$db_prefix}productos.fecha_caducidad < ?";
DB::select($sql,array(1,20));

Y listo, esto es todo.

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

Gracias.

….un sueño es casi todo  y más que  nada, más que todo al soñarlo, casi nada después……

Buscar una palabra en la base de datos, en Laravel

laravel

Un elemento común en una aplicación es que nos toque buscar una palabra en la base de datos, en Laravel. Aquí les muestro una forma de hacerlo que funciona.

Buscando una palabra en varias columnas o en todo un modelo

Lo que haremos es crear una variable query  y con el uso “use” y  de orWhere, nos compare el contenido de la columna con el valor de la búsqueda.

$busqueda = 'Palabra o termino a encontrar;
$descripcion = Descripcion::from('descripcion as a')
    ->where(function ($query) use ($busqueda) {
      $query = $query->orWhere('a.titulo','like',"%$busqueda%");
      $query = $query->orWhere('a.nombre','like',"%$busqueda%");
      $query = $query->orWhere('a.explicacion','like',"%$busqueda%");
      $query = $query->orWhere('a.etiquetas','like',"%$busqueda%");
    });
$posts = $posts->where('a.estado','=',1)
    ->get();

Leer mas sobre Laravel en este blog

En el ejemplo de abajo, estaremos, buscando diferentes  palabras en varias columnas del modelo Usuario,  solo en aquellos  registros que están activos

$columnasbusqueda = ['nombre','apellidos','apodo'];
$terminos = 'Palabras a buscar';
$palabras = explode(" ",$ terminos);
$usuarios = Usuario::from('usuarios as a')
    ->where(function ($query) use ($columnasbusqueda,$ palabras) {
        foreach ($palabras as $palabra) {
            $query = $query->where(function ($query) use ($columnasbusqueda,$palabra) {
                foreach ($columnasbusqueda as $columna) {
                    $query->orWhere($columna,'like',"%$palabra%");
                }
            });
        }
    });
$usuarios = $usuarios->where('a.estado','=',1)
    ->get();

Y listo, esto es todo.

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…

Auth con el uso de modelos

logo laravel

Manejando algo del código, podemos emplear Auth con el uso de modelos, y crear un sistema de autenticación mediante el uso de sus relaciones, lo cual reforzará la seguridad de nuestra web.

Ver Como Instalar Laravel
En el ejemplo siguiente, creamos una función managePages(), dentro de la clase AdminPolicy, que nos indica una determinada condición para el usuario que intenta acceder, en este caso limita su uso solo a aquellos con los roles Admin y Editor.
Luego declaramos su validez dentro de Providers, específicamente en el constructor del AuthServiceProvider. Para esto lo que hacemos es pasarle la ruta exacta del GateContract y una variable que nos traerá los datos del user. Con el uso de un foreach le damos un valor dinamico al acceso.

// app/Policies/AdminPolicy.php
class AdminPolicy
{
public function managePages($user)
{
return $user->hasRole(['Admin', 'Editor']);
}
}
// app/Providers/AuthServiceProvider.php
public function boot( \Illuminate\Contracts\Auth\Access\GateContract $gate)
{
foreach (get_class_methods(new \App\Policies\AdminPolicy) as $method) {
$gate->define($method, \App\Policies\AdminPolicy::class . "@{$method}");
}
$this->registerPolicies($gate);
}

Luego en cada uno de los espacios donde necesitamos acceder, colocamos una clausula de acceso, que llamara a la clase que hemos creado.

Este post puede interesarte Error al intentar acceder al login en laravel

Y listo, esto es todo.

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

Gracias.

…………….subir montañas hermana hombres……..

Git, el concepto de branch

Sabemos que Git nos ofrece un sistema de ramas o  branchs,  que  al igual que otras herramientas de control de versiones, soporta la administración de ramificaciones en los proyectos.

Sin ánimo de ahondar demasiado, digamos que la diferencia básica que Git aporta, es que en vez de crear un directorio adicional para guardar una nueva rama, lo hace de forma inmediata sin crear nuevos directorios,  almacenando solo copias instantáneas, de como está el archivo en ese momento, junto a  los nodos padres, lo cual también es una gran ventaja, al momento de gestionar la fusión entre las ramas con que contamos.

¿Que son las ramas?

Podríamos decir, si queremos ser muy escuetos que:  una rama  en Git es solo  un apuntador en movimiento que redirige a su respectivo commit.

Lo explico así: al  iniciar un proyecto y hacer tu primer commit, estas creando una rama principal de trabajo, también llamada master.

A medida que creas tu código,  y vas avanzando buscando una solución, tal vez necesites caminos alternativos, que te lleven a determinado punto y hasta tanto  no lo alcances, no   querrás  incorporarlo a lo que has hecho en tu rama principal, incluso pudiera ser que nunca alcances ese punto, y simplemente necesites regresar adonde estabas antes.

Esto es posible hacerlo creando ramas de trabajo, o sea cada vez que creas una alternativa, podemos decir que estás trabajando en una rama, si a eso unimos, que sobre el propio proyecto, pueden estar trabajando diferentes integrantes de un equipo, tendremos varias ramificaciones, y al mismo tiempo  si cada uno de ellos quiere probar nuevas rutas para buscar un resultado  esperado, entonces crearán nuevas ramas, en un mismo árbol de proyecto.

Lo que hace a Git superior a otros,  es el modo rápido y eficaz en que maneja las ramificaciones, haciendo el avance o el retroceso entre distintas ramas, algo ágil , cómodo y sencillo, lo cual facilita   que durante el  desarrollo, las ramas puedan crearse y unirse entre si, tantas veces como necesitemos.

Es fácil entender entonces, que este enorme potencial es de gran ayuda, para agilizar y fortalecer el modo en que creamos código.  

El valor  del Commit

Al escribir git add . estas indicando a git que pase tus archivos a la zona conocida como stage, pero  lo que sucede realmente es que  se ejecuta una suma de control de ellos, en 40 caracteres (un resumen SHA-1), y se  almacena un blob (copia) de cada uno en el repositorio,  guardando cada suma de control, en el área de preparación (staging area):

Al crear una orden de confirmación  commit, estamos diciéndole a Git  que aceptamos  que los cambios añadidos previamente con el add al  área stage,  sean procesados,  y lo que hará el sistema es crear  y almacenar una impresión  del código de ese momento, con un grupo de metadatos explicativos como los que recoge la opción –m.

Nuestro commit, también creará un apuntador hacia esta impresión instantánea (piensa en una foto de ese momento), que permitirá identificarla, retornarla, o unirla a otra; o los apuntadores podrían ser varios, si lo que hay detrás de nuestro commit, es un merge que une varias ramas.

Suponiendo que estuvieras  trabajando con 5 subdirectorios, lo que sucederá al hacer commit es que Git realizará  sumas de cada uno, que  guardará  como objetos árbol en el repositorio Git y creará un objeto de confirmación con los metadatos y  además un apuntador al objeto árbol de la raíz del proyecto.

Hecho esto,  ahora  habría 7 objetos en el repositorio de tu proyecto, los 5 blobs, un árbol que no es más que la lista estructurada de lo  que contiene el repositorio, y la confirmación  de los cambios que el commit procesó  y que apunta directamente  a la raíz del árbol.

Entonces, si decides hacer más cambios y confirmarlos, el siguiente commit también tendrá un apuntador que se dirige al commit previo, de esa manera queda encadenado a la versión anterior y así sucesivamente.

 Por tanto, la  rama se mantiene en movimiento avanzando en cada commit, ese desplazamiento comienza al crear  la rama principal master, con el primer commit.

 ¿Cómo se crea una rama?

El comando utilizado para crear una rama es :

git branch nombre de la rama

Este comando lo que hará será crear un nuevo apuntador, disponible para que dirija al ultimo commit que has realizado.

Para crear la rama nuevo_test, escribe:  

$ git branch nuevo_test

El nuevo apuntador, dirigirá  al commit en el que estés. 

Aunque pueda parecer complicado, no lo es.

En este punto, habrá dos ramas, cada una con su apuntador que refieren al mismo commit, sin embargo la magia está en que existe un apuntador llamado HEAD, con una labor especial que es la de apuntar a la rama local en la que te encuentres, en este caso master, pues aunque se creó la rama nuevo_test, con el comando branch, aun no se ha entrado a ella.

El comando que maneja los logs, y que debemos tener siempre a mano para saber cómo vamos, y entre otras cosas, la estructura de nuestro árbol de proyecto:   git log , en su opción --decorate nos mostrará la estructura

Por ejemplo nos devolverá algo como esto

$ git log --oneline --decorate
g40ac (HEAD, master, nuevo_test) add feature ………. 

Donde g40ac  será el commit al que apuntan ambas ramas. 

Moviendose entre ramas

Para moverse de una rama a la otra el comando a usar es :

git checkout 

y la sintaxis si queremos ir a la rama nuevo_test es :

$ git checkout nuevo_test

Ahora el apuntador se apuntará a la rama nuevo_test

Si hacemos ahora un commit

$ git commit -a -m 'primer cambio'

Y corremos nuevamente log --decorate veremos que la rama nuevo_test apunta al  nuevo commit junto al apuntado HEAD.

 Si queremos regresar a la rama master, utilizaremos igualmente checkout, al hacerlo, se moverá nuevamente el apuntador HEAD a la rama master, y restituirá los archivos  dejándolos tal y como estaban en el último commit de esa rama principal.

Esto, no es otra cosa que rebobinar el proyecto, dando marcha atrás en el tiempo, por tanto  los cambios que hagas en adelante, serán diferentes de la versión anterior  del proyecto.  

Otro aspecto importante de Git,  es que si no es capaz de realizar este rebobinado de un modo limpio, o sea si no puede recuperar la impresión exacta del ultimo commit, no permitirá hacer el checkout.

En definitiva para moverte entre ramas los comando son tres, branch que crea la rama, commit que la confirma y checkout que te permite saltar de una a otra

Por supuesto al saltar entre ramas, cada  rama  tendrá diferencias en tu labor, para ver las diferencias podemos usar el comando log de este modo:

 git log --oneline --decorate --graph –all

Esto mostrará el historial de los commit, indicando dónde están los apuntadores de cada ramas y como ha variado el historial.

Si ahora analizamos lo que dijimos al inicio, sobre el modo en que se compone una rama, desde el punto de vista estructural, comprenderemos porque una rama Git es un simple archivo, con  los 40 caracteres de una suma de control SHA-1,  vinculado a un commit específico.

De ahí su simpleza,  velocidad y  eficiencia.

Y listo, esto es todo.

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

Gracias.

 ….un sueño es casi todo  y más que  nada;  más que todo al soñarlo, casi nada después……

Insertar una imagen responsive

Una cuestión muy importante en CSS, sobre todo en tiempos de mobile-first, es poder insertar una imagen responsive, capaz de verse bien en cualquier dispositivo, y esto adquiere mayor importancia cuando son imágenes de fondo.

Para hacerlo de modo exitoso es necesaria la propiedad background-size de CSS, la cual asimila  el valor cover, que es el encargado de decir escale el alto y ancho de la imagen de forma automática y proporcional de acuerdo a la ventana de visualización o viewport de que se trate.

Por supuesto que varia según el tamaño de la pantalla, si para pantallas grandes tipo PC, o televisiones,  una imagen con un tamaño de 5500x3600px es lo más adecuado, sin embargo no es lo recomendable para dispositivos más pequeños, como móviles, por tanto la opción de usar dos imágenes según el tamaño del display es útil y fácil de conseguir.

El uso de una imagen para una para dispositivos móviles y otra para equipos de más  alta resolución,  es una practica que ayuda mucho, teniendo en cuenta que queremos evitar que la imagen se pixele cuando se agrande, para cubrir el tamaño de la ventana del navegador, de lo que se trata es de hallar el tamaño adecuado, según nuestras necesidades

Para escribir la propiedad en el css, recordando que css es una hoja de cascada, por tanto las ordenes llevan un orden dado, nuestro código debería ser aproximadamente este:

// indicamos la ubicación de la imagen  

background-image: url(images/background-picture.jpg);

//centramos la imagen vertical y horizontalmente */

background-position: center center;

//evitamos que el navegador repita la imagen para llenar el espacio */

background-repeat: no-repeat;


//dejamos la imagen fija de modo que no cambie si cambia la ventana del navegador, además, rescalandose  

background-attachment: fixed;


// llamamos a la propiedad cover para indicar que cubrirá todo el ancho 
background-size: cover;

//garantizamos que si hay un error al cargar o demora se muestre un color mientras tanto

background-color: #66999;

este código puedes escribirlo o verlo escrito también en este formato

background: #66999 url(background-photo.jpg) center center cover no-repeat fixed;

Y listo, esto es todo.

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

Gracias.

Subir montañas hermana hombres……

Syntax error or access violation: 1071 Specified key was too long.Un error común al correr la migraciones

laravel error

Si recibes este error: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQL: alter table `users` add unique `users_email_unique`(`email`)), aplica esta soluci

Dentro de App/Providers ir a AppServiceProvider y corregir la función boot

public function boot()
    {
        //
    }

Por

use Illuminate\Support\Facades\Schema; // añadir  facade Schema
public function boot()
    {
       // corrigiendo error …….
        Schema::defaultStringLength(191);
    }

Y listo, esto es todo.

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

Gracias.

…..subir montañas hermana hombres…….

Translate »