#!/usr/bin/env python # coding: utf-8 # # Factorización de Matrices con Python # *Esta notebook fue creada originalmente como un blog post por [Raúl E. López Briega](http://relopezbriega.com.ar/) en [Matemáticas, Analisis de datos y Python](http://relopezbriega.github.io). El contenido esta bajo la licencia BSD.* # Factorización de Matrices con Python # ## Introducción # # Cuando trabajamos en problemas de [Machine Learning](http://relopezbriega.github.io/tag/machine-learning.html), muchas veces nos vamos a encontrar con enormes [conjuntos de datos](https://es.wikipedia.org/wiki/Conjunto_de_datos), con cientos o miles de características o *features*. Una forma simple de reducir las dimensiones de estas características es aplicar alguna técnica de **[Factorización de matrices](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n_de_matrices)**. La **[Factorización de matrices](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n_de_matrices)** tiene enormes aplicaciones en todo tipo de problemas relacionados a la [inteligencia artificial](https://es.wikipedia.org/wiki/Inteligencia_artificial), ya que la [reducción de dimensionalidad](https://en.wikipedia.org/wiki/Dimensionality_reduction) es la esencia de la *[cognición](https://es.wikipedia.org/wiki/Cognici%C3%B3n)*. # # Asimismo, la **[Factorización de matrices](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n_de_matrices)** es también un tema unificador dentro del [álgebra lineal numérica](http://relopezbriega.github.io/tag/algebra.html). Una amplia variedad de [algoritmos](https://es.wikipedia.org/wiki/Algoritmo) se han desarrollado a lo largo de muchas décadas, proporcionando una plataforma numérica para operaciones de matrices tales como, la resolución de [sistemas de ecuaciones lineales](https://es.wikipedia.org/wiki/Sistema_de_ecuaciones_lineales), la [descomposición espectral](https://es.wikipedia.org/wiki/Teorema_de_descomposici%C3%B3n_espectral), y la identificación de [subespacios vectoriales](https://es.wikipedia.org/wiki/Subespacio_vectorial). Algunos de estos algoritmos también han demostrado ser de utilidad en problemas de [análisis estadístico de datos](http://relopezbriega.github.io/tag/estadistica.html), como es el caso de la [descomposición en valores singulares](https://es.wikipedia.org/wiki/Descomposici%C3%B3n_en_valores_singulares) o [SVD](https://es.wikipedia.org/wiki/Descomposici%C3%B3n_en_valores_singulares), por sus siglas en inglés, que es la base del [análisis de componentes principales](https://es.wikipedia.org/wiki/An%C3%A1lisis_de_componentes_principales) o [PCA](https://es.wikipedia.org/wiki/An%C3%A1lisis_de_componentes_principales), que es una técnica muy utilizada para reducir el tamaño de los datos. Muchas investigaciones actuales en [Machine Learning](http://relopezbriega.github.io/tag/machine-learning.html) han centrados sus esfuerzos en el uso de la **[Factorización de matrices](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n_de_matrices)** para mejorar el rendimiento de los sistemas de aprendizaje. Principalmente en el estudio de la [factorización de matrices no negativas (NMF)](https://en.wikipedia.org/wiki/Non-negative_matrix_factorization), la cual se centra en el análisis de matrices de datos cuyos elementos son positivos (no negativos), una ocurrencia muy común en los [conjuntos de datos](https://es.wikipedia.org/wiki/Conjunto_de_datos) derivados de textos e imágenes. # # # ## ¿Qué es la factorización de matrices? # # En [matemáticas](https://es.wikipedia.org/wiki/Matem%C3%A1ticas), la [factorización](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n) es una técnica que consiste en la descomposición de una expresión matemática (que puede ser un número, una matriz, un [tensor](https://es.wikipedia.org/wiki/C%C3%A1lculo_tensorial), etc.) en forma de producto. Existen distintos métodos de factorización, dependiendo de los objetos matemáticos estudiados; el objetivo es simplificar una expresión o reescribirla en términos de «bloques fundamentales», que reciben el nombre de *factores*. Así por ejemplo, el número 6 se puede descomponer en el producto de 3 y 2. Si extendemos este concepto al mundo de las matrices, entonces podemos decir que la **[Factorización de matrices](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n_de_matrices)** consiste en encontrar dos o más matrices de manera tal que cuando se multipliquen nos devuelvan la matriz original. Por ejemplo: # # $$\left(\begin{matrix}3 & 4 & 5\\6 & 8 & 10 \end{matrix}\right) = \left(\begin{matrix}1\\2 \end{matrix}\right) \cdot \left(\begin{matrix}3 & 4 & 5 \end{matrix}\right) # $$ # # Los métodos de **[Factorización de matrices](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n_de_matrices)** han ganado popularidad últimamente al haber sido aplicados con éxito en [sistemas de recomendación](https://es.wikipedia.org/wiki/Sistema_de_recomendaci%C3%B3n) para descubrir las características latentes que subyacen a las interacciones entre dos tipos de entidades, como por ejemplo usuarios y películas. El algoritmo que ganó el [desafío de Netflix](http://netflixprize.com/) fue un sistema basado en métodos de **[Factorización de matrices](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n_de_matrices)**. # # ## Factorización de matrices en sistemas de ecuaciones lineales # # Dos de las **[Factorización de matrices](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n_de_matrices)** más utilizadas y que tal vez mucha gente las haya escuchado nombrar alguna vez son la [factorización LU](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n_LU) y la [factorización QR](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n_QR); las cuales se utilizan a menudo para resolver [sistemas de ecuaciones lineales](https://es.wikipedia.org/wiki/Sistema_de_ecuaciones_lineales). # # ### Factorización LU # # $$A = LU$$ # # En [álgebra lineal](http://relopezbriega.github.io/tag/algebra.html), la [factorización o descomposición LU](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n_LU) (del inglés Lower-Upper) es una forma de [factorización](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n) de una matriz como el producto de una [matriz triangular](https://es.wikipedia.org/wiki/Matriz_triangular) inferior y una superior. La [factorización LU](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n_LU) expresa el [método de Gauss](https://es.wikipedia.org/wiki/M%C3%A9todo_de_Gauss) en forma matricial. Así por ejemplo, tenemos que $PA = LU$ donde $P$ es una [matriz de permutación](https://es.wikipedia.org/wiki/Matriz_de_permutaci%C3%B3n). Una condición suficiente para que exista la factorización es que la matriz $A$ sea una [matriz no singular](https://es.wikipedia.org/wiki/Matriz_no_singular). # # En [Python](https://www.python.org/) podemos encontrar la [descomposición LU](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n_LU) con la ayuda de [SciPy](http://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.lu_factor.html) de la siguiente forma: # In[1]: # # importando modulos necesarios import matplotlib.pyplot as plt import numpy as np import scipy.sparse as sp import scipy.linalg as la import nimfa from sklearn.decomposition import NMF, PCA from sklearn.preprocessing import StandardScaler import seaborn as sns import pandas as pd # graficos incrustados get_ipython().run_line_magic('matplotlib', 'inline') # parámetros de estilo sns.set(style='darkgrid', palette='muted') pd.set_option('display.mpl_style', 'default') pd.set_option('display.notebook_repr_html', True) plt.rcParams['figure.figsize'] = 8, 6 # In[2]: # Ejemplo factorización LU A = np.array([[7, 3, -1, 2] ,[3, 8, 1, -4] ,[-1, 1, 4, -1] ,[2, -4, -1, 6]]) P, L, U = la.lu(A) # In[3]: # Matriz A A # In[4]: # Matriz de permutación P # In[5]: # Matriz triangular inferior L # In[6]: # Matriz triangular superior U # In[7]: # A = LU L @ U # ### Factorización QR # # $$A = QR$$ # # La [descomposición o factorización QR](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n_QR) consiste en la descomposición de una matriz como producto de una [matriz ortogonal](https://es.wikipedia.org/wiki/Matriz_ortogonal) ($Q^T \cdot Q = I$) por una [matriz triangular superior](https://es.wikipedia.org/wiki/Matriz_triangular). la [factorización QR](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n_QR) es ampliamente utilizada en las finanzas cuantitativas como base para la solución del problema de los [mínimos cuadrados lineales](https://es.wikipedia.org/wiki/M%C3%ADnimos_cuadrados_ordinarios), que a su vez se utiliza para el análisis de [regresión estadística](https://es.wikipedia.org/wiki/Regresi%C3%B3n_lineal). # # En [Python](https://www.python.org/) podemos encontrar la [descomposición QR](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n_LU) con la ayuda de [SciPy](http://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.lu_factor.html) de la siguiente forma: # In[8]: # Ejemplo factorización QR A = np.array([[12, -51, 4], [6, 167, -68], [-4, 24, -41]]) Q, R = la.qr(A) # In[9]: # Matriz A A # In[10]: # Matriz ortogonal Q Q # In[11]: # Matriz triangular superior R R # In[12]: # A = QR Q @ R # ## Matrices dispersas y no negativas # # En muchas ocasiones cuando trabajamos con matrices para representar el mundo físico, nos vamos a encontrar con que muchas de estas matrices están dominadas por mayoría de elementos que son cero. Este tipo de matrices son llamadas [matrices dispersas](https://es.wikipedia.org/wiki/Matriz_dispersa), es decir, matrices de gran tamaño en que la mayor parte de sus elementos son cero. Como sería ineficiente almacenar en la memoria de la computadora todos los elementos en cero, en las [matrices dispersas](https://es.wikipedia.org/wiki/Matriz_dispersa) solo vamos a almacenar los valores que no son cero y alguna información adicional acerca de su ubicación. # # Asimismo muchos datos del mundo real son no negativos y los componentes ocultos correspondientes tienen un sentido físico solamente cuando son no negativos. En la práctica, ambas características, ser dispersas y no negativas son a menudo deseable o necesario cuando los componentes subyacentes tienen una interpretación física. Por ejemplo, en el [procesamiento de imágenes](https://en.wikipedia.org/wiki/Image_processing) y [visión artificial](https://es.wikipedia.org/wiki/Visi%C3%B3n_artificial), las variables involucradas y los parámetros pueden corresponder a píxeles, y la [factorización de matrices dispersas y no negativas](https://en.wikipedia.org/wiki/Non-negative_matrix_factorization) está relacionada con la extracción de las partes más relevantes de las imágenes. La representación *dispersa* de los datos por un número limitado de componentes # es un problema importante en la investigación. En [Machine Learning](http://relopezbriega.github.io/tag/machine-learning.html), las [matrices dispersas](https://es.wikipedia.org/wiki/Matriz_dispersa) está estrechamente relacionada con la [selección de atributos](http://relopezbriega.github.io/blog/2016/04/15/ejemplo-de-machine-learning-con-python-seleccion-de-atributos/) y ciertas generalizaciones en algoritmos de aprendizaje; mientras que la *no negatividad* se relaciona a las [distribuciones de probabilidad](http://relopezbriega.github.io/blog/2016/06/29/distribuciones-de-probabilidad-con-python/). # # En [Python](https://www.python.org/), podemos representar a las [matrices dispersas](https://es.wikipedia.org/wiki/Matriz_dispersa) con la ayuda de [scipy.sparse](http://docs.scipy.org/doc/scipy/reference/sparse.html). # In[13]: # Ejemplo matriz dispersa con scipy A = sp.diags([1, -2, 1], [1, 0, -1], shape=[10, 10], format='csc') A # In[14]: A.data # In[15]: A.indices # In[16]: A.indptr # In[17]: A.todense() # ## La descomposición en valores singulares (SVD) y el análisis de componentes principales (PCA) # # El [SVD](https://es.wikipedia.org/wiki/Descomposici%C3%B3n_en_valores_singulares) y el [PCA](https://es.wikipedia.org/wiki/An%C3%A1lisis_de_componentes_principales) son herramientas ampliamente utilizadas, por ejemplo, en el análisis de imágenes médicas para la [reducción de dimensionalidad](https://en.wikipedia.org/wiki/Dimensionality_reduction), la construcción de modelos, y la comprensión y exploración de datos. Tienen aplicaciones en prácticamente todas las áreas de la ciencia, [machine learning](http://relopezbriega.github.io/tag/machine-learning.html), [procesamiento de imágenes](https://en.wikipedia.org/wiki/Image_processing), [ingeniería](https://es.wikipedia.org/wiki/Ingenier%C3%ADa), [genética](https://es.wikipedia.org/wiki/Gen%C3%A9tica), [computación cognitiva](https://en.wikipedia.org/wiki/Cognitive_computing), [química](https://es.wikipedia.org/wiki/Qu%C3%ADmica), [meteorología](https://es.wikipedia.org/wiki/Meteorolog%C3%ADa), y [redes neuronales](http://relopezbriega.github.io/tag/redes-neuronales.html), sólo por nombrar algunas; en dónde nos encontramos con grandes [conjuntos de datos](https://es.wikipedia.org/wiki/Conjunto_de_datos). El propósito del [análisis de componentes principales PCA](https://es.wikipedia.org/wiki/An%C3%A1lisis_de_componentes_principales) es derivar un número relativamente pequeño de combinaciones lineales no correlacionadas (componentes principales) de una conjunto de variables aleatorias de [media](https://es.wikipedia.org/wiki/Media_aritm%C3%A9tica) cero mientras que conserva la mayor cantidad de información de las variables originales como sea posible. Entre los objetivos del [PCA](https://es.wikipedia.org/wiki/An%C3%A1lisis_de_componentes_principales) podemos encontrar los siguientes: # # 1. [Reducción de dimensionalidad](https://en.wikipedia.org/wiki/Dimensionality_reduction). # 2. Determinación de combinaciones lineales de variables. # 3. Selección de características o *features*: la elección de las variables más útiles. # 4. Visualización de datos multidimensionales. # 5. Identificación de las variables subyacentes. # 6. Identificación grupos de objetos o de [valores atípicos](https://es.wikipedia.org/wiki/Valor_at%C3%ADpico). # # Veamos algunos ejemplos con [Python](https://www.python.org/) # In[18]: # Ejemplo SVD con scipy.linalg.svd # Matriz A a factorizar A = np.array([[2, 4] ,[1, 3] ,[0, 0] ,[0, 0]]) A # In[19]: # Factorización con svd # svd factoriza la matriz A en dos matrices unitarias U y Vh, y una # matriz s de valores singulares (reales, no negativo) de tal manera que # A == U * S * Vh, donde S es una matriz con s como principal diagonal y ceros U, s, Vh = la.svd(A) U.shape, Vh.shape, s.shape # In[20]: # Matriz unitaria U # In[21]: # Valores singulares s # In[22]: # Matriz unitaria Vh # In[23]: # Generando S S = la.diagsvd(s, 4, 2) S # In[24]: # Reconstruyendo la Matriz A. U @ S @ Vh # ### Ejemplo de SVD y PCA con el dataset Iris # # Iris dataset # # El [dataset](https://es.wikipedia.org/wiki/Conjunto_de_datos) iris contiene mediciones de 150 flores de iris de tres especies diferentes. # # Las tres clases en el [dataset](https://es.wikipedia.org/wiki/Conjunto_de_datos) son: # # 1. setosa (n = 50). # 2. versicolor (n = 50). # 3. virginica (n = 50). # # # Las cuales están representadas por cuatro características: # # 1. longitud en cm del [sépalo](https://es.wikipedia.org/wiki/S%C3%A9palo). # 2. ancho en cm del [sépalo](https://es.wikipedia.org/wiki/S%C3%A9palo). # 3. longitud en cm del [pétalo](https://es.wikipedia.org/wiki/P%C3%A9talo). # 4. ancho en cm del [pétalo](https://es.wikipedia.org/wiki/P%C3%A9talo). # In[25]: # Ejemplo svd con iris dataset iris = sns.load_dataset("iris") print(iris.shape) iris.head() # In[26]: # Aplicando svd U, s, Vh = sp.linalg.svds((iris - iris.mean()).iloc[:,:-1],2) # In[27]: # Creando los componentes principales pc = U @ np.diag(s) pc = pc[:,::-1] # graficando el dataset reducido a 2 componenetes iris_svd = pd.concat((pd.DataFrame(pc, index=iris.index , columns=('c0','c1')), iris.loc[:,'species']),1) g = sns.lmplot('c0', 'c1', iris_svd, hue='species', fit_reg=False, size=8 ,scatter_kws={'alpha':0.7,'s':60}) # In[28]: # Ejemplo de PCA con Scikit-Learn e Iris dataset # Divido el dataset en datos y clases X = iris.ix[:,0:4].values y = iris.ix[:,4].values # Estandarizo los datos X_std = StandardScaler().fit_transform(X) pca = PCA(n_components=2) Y_pca = pca.fit_transform(X_std) # Visualizo el resultado for lab, col in zip(('setosa', 'versicolor', 'virginica'), ('blue', 'red', 'green')): plt.scatter(Y_pca[y==lab, 0], Y_pca[y==lab, 1], label=lab, c=col) plt.xlabel('Componente 1') plt.ylabel('Componente 2') plt.legend(loc='lower center') plt.tight_layout() plt.title('Ejemplo PCA') plt.show() # ## Factorización de matrices en sistemas de recomendación # # En un [sistemas de recomendación](https://es.wikipedia.org/wiki/Sistema_de_recomendaci%C3%B3n) como [Netflix](http://www.netflix.com/) o [MovieLens](https://movielens.org/), hay un grupo de usuarios y un conjunto de elementos (películas en los dos sistemas anteriores). Teniendo en cuenta que cada usuario ha valorado algunos elementos en el sistema, nos gustaría predecir cómo los usuarios calificarían los artículos que aún no se han valorado, de tal manera que podemos hacer recomendaciones a los usuarios. En este caso, toda la información que tenemos sobre las calificaciones existentes pueden ser representados en una matriz. Supongamos ahora que tenemos 5 usuarios y 4 películas y las calificaciones son números enteros de 1 a 5, la matriz resultante puede ser algo como la siguiente (el guión significa que el usuario aún no ha calificado la película): # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
P1P2P3P4
U153-1
U24--1
U311-5
U41--4
U5-154
# # Por lo tanto, la tarea de predecir las calificaciones que faltan se puede considerar como un problema de llenar los espacios en blanco (los guiones en la matriz) de tal manera que los valores resultantes serían consistentes con las calificaciones existentes en la matriz. # # La intuición detrás de usar **[Factorización de matrices](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n_de_matrices)** para resolver este problema es que deberían existir algunas características latentes que determinen cómo un usuario califica una película. Por ejemplo, dos usuarios darían una alta calificación a una cierta película si a ambos les gusta los actores / actrices de la película, o si la película es una película de acción, que es un género preferido por ambos usuarios. Por lo tanto, si podemos descubrir estas características latentes, deberíamos ser capaces de predecir una calificación con respecto a un determinado usuario y una cierta película, porque las características asociadas con el usuario deben coincidir con las características asociadas con la película. # # Al tratar de descubrir las diferentes características latentes, estamos suponiendo implícitamente que el número de características va a ser menor que el número de usuarios y el número de elementos. No debería ser difícil de entender este supuesto ya que no sería razonable que cada usuario está asociado con una característica única (aunque esto no es imposible). Y de todos modos, si este es el caso, no tendría sentido hacer recomendaciones, porque ninguno de estos usuarios estarían interesados en los artículos calificados por otros usuarios. # # Si llevamos este ejemplo sencillo a [Python](https://www.python.org/), podríamos modelarlo utilizando [Scikit-learn](http://scikit-learn.org/stable/) [NMF](http://scikit-learn.org/stable/modules/generated/sklearn.decomposition.NMF.html) o [Nimfa](http://nimfa.biolab.si/nimfa.methods.factorization.snmf.html). # In[29]: # Ejemplo en python # Matriz de ratings de los usuarios R = np.array([[5, 3, 0, 1] ,[4, 0, 0, 1] ,[1, 1, 0, 5] ,[1, 0, 0, 4] ,[0, 1, 5, 4]]) # In[30]: # Armado del modelo modelo = NMF(n_components= 2, init='random',random_state=1982, alpha=0.0002, beta=0.02, max_iter=5000) U = modelo.fit_transform(R) V = modelo.components_ # In[31]: # Reconstrucción de la matriz U @ V # In[32]: # Error del modelo modelo.reconstruction_err_ # In[33]: # Ejemplo utilizando nimfa snmf = nimfa.Snmf(R, seed="random_vcol", rank=2, max_iter=30, version='r', eta=1., beta=1e-4, i_conv=10, w_min_change=0) # In[34]: # Armando el modelo fit = snmf() U = fit.basis() V = fit.coef() # In[35]: # Reconstruyendo la matriz np.around(U @ V, decimals=2) # ## Librerías de Python para factorización de matrices # # Para concluir, podemos enumerar algunas de las librerías de [Python](https://www.python.org/) que nos pueden ser de mucha utilidad a la hora de trabajar con [Factorización de matrices](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n_de_matrices), como ser: # # * **[NumPy](http://www.numpy.org/)**: El popular paquete matemático de [Python](http://python.org/), nos va a permitir crear *[vectores](http://es.wikipedia.org/wiki/Vector)*, *matrices* y *[tensores](http://es.wikipedia.org/wiki/C%C3%A1lculo_tensorial)*; y poder manipularlos y realizar operaciones sobre ellos con mucha facilidad. # * **[SciPy](http://docs.scipy.org/doc/scipy/reference/index.html)**: El paquete que agrupa un gran número de herramientas científicas en [Python](https://www.python.org/). Nos va a permitir crear [matrices dispersas](https://es.wikipedia.org/wiki/Matriz_dispersa) y realizar [factorizaciones](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n) con facilidad. # * **[Scikit-learn](http://scikit-learn.org/stable/)**: Es una librería especializada en algoritmos para [data mining](http://es.wikipedia.org/wiki/Miner%C3%ADa_de_datos) y [machine learning](http://es.wikipedia.org/wiki/Machine_learning). Principalmente el submódulo de Descomposiciones en dónde vamos a encontrar las herramientas para [reducciones de dimensionalidad](https://en.wikipedia.org/wiki/Dimensionality_reduction). # * **[SymPy](http://www.sympy.org/es/)**: Esta librería nos permite trabajar con matemática simbólica, convierte a [Python](http://python.org/) en un [sistema algebraico computacional](http://es.wikipedia.org/wiki/Sistema_algebraico_computacional). Nos va a permitir trabajar con las [factorizaciones](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n) en forma analítica. # * **[Nimfa](http://nimfa.biolab.si/)**: [Nimfa](http://nimfa.biolab.si/) es una librería para [factorización de matrices no negativas](https://en.wikipedia.org/wiki/Non-negative_matrix_factorization). Incluye las implementaciones de varios métodos de [factorización](https://es.wikipedia.org/wiki/Factorizaci%C3%B3n), enfoques de inicialización y calificación de calidad. Soporta representaciones tanto de matrices densas como [dispersas](https://es.wikipedia.org/wiki/Matriz_dispersa). Se distribuye bajo [licencia BSD](https://es.wikipedia.org/wiki/Licencia_BSD). # # # Con esto termina este artículo, espero les haya parecido interesante y les sea de utilidad en sus proyectos. # # Saludos! # # *Este post fue escrito utilizando IPython notebook. Pueden descargar este [notebook](https://github.com/relopezbriega/relopezbriega.github.io/blob/master/downloads/MatrixFact.ipynb) o ver su version estática en [nbviewer](http://nbviewer.ipython.org/github/relopezbriega/relopezbriega.github.io/blob/master/downloads/MatrixFact.ipynb).*