script

jueves, 29 de mayo de 2014

Regresión lineal: Varias variables

Ya vimos en la entrada anterior como a partir de un conjunto de entrenamiento \((X, Y)\) podíamos generar una función que aproxime su comportamiento y utilizarla para estimar otros valores. Supongamos ahora que tenemos un conjunto de n variables de entrada y una salida; siguiendo la idea de la entrada anterior, tendríamos un conjunto como el siguiente:
\[ (X_1^1, X_2^1, ...,  X_j^1, ..., X_n^1, Y^1) \\ (X_1^2, X_2^2, ...,  X_j^2, ..., X_n^2, Y^2) \\ ... \\ (X_1^i, X_2^i, ...,  X_j^i, ..., X_n^i, Y^i) \\ ... \\ (X_1^m, X_2^m, ...,  X_j^m, ..., X_n^m, Y^m) \].

Como se puede ver en el ejemplo, vamos a seguir utilizando un superindice i para notar los indices dentro del conjunto pero ademas, vamos a agregar un subindice j de tamaño m para hacer referencia a la j-esima variable dentro de mi i-esimo elemento del conjunto. Nuestra función hipótesis, recordemos entonces, tenia la siguiente forma para el caso de una única variable:
\[h(x) = \theta_0 + X^i\theta_1\]
Extender esta idea a nuestro nuevo conjunto de entrada es relativamente sencillo, así que nuestra nueva hipótesis queda de la siguiente manera:
\[h(x_1, ..., x_n) = \theta_0 + X_1 \theta_1\ + ... + X_n \theta_n\]
Recordemos siempre que asumimos el valor por defecto de \(X_0 = 0\).
Veamos ademas que si tomamos la entrada de nuestra función \(h(x_1, ..., x_n)\) como un vector que contiene a dichas variables, el calculo de nuestra función se transforma simplemente en la multiplicación de dos matrices.

\[ \theta^T * X^i = \begin{bmatrix}
\theta_1, & \theta_2, & ..., & \theta_j, & ..., & \theta_n \end{bmatrix} *
\begin{bmatrix}
X_1  \\
X_2 \\
... \\
X_j \\
... \\
X_n \end{bmatrix} \]


En particular, no lo mencione pero necesitamos transponer el vector \([\theta_1, ..., \theta_n]\) por cuestiones de la multiplicación de matrices. Luego, utilizando este calculo que traduce todo en una sola multiplicación (a la hora de llevar todo esto a código, va a ser un alivio, créanme) podemos adaptar nuestras variables \(\theta\) de la siguiente manera:

                    mientras no converga {
                                con j desde 0 hasta n {
                                      \(\theta_j = \theta_j - a * \frac{1}{m} \sum\limits_{i=1}^m (h(X^i) - Y^i)^2 * X_i^j\)
                                }
                    }


Con esto, y dado que hicimos la introducción mas pesada en el calculo de una variable, ya tenemos los cambios necesarios para el calculo de la regresión lineal multivariada.

Para quienes gusten de mirar un poco de código, ya esta subido a mi GitHub (por el momento solo en Java, pero mas adelante podría agregar código en algún lenguaje mas, probablemente Clojure, para darle su versión funcional al tema). Si no usan Maven para importar las librerías, va a ser necesario que agreguen este .jar: EJML. Es una librería de matrices que use para no tener que implementar todo de cero y poder enfocarnos en el código que interesa. Cualquier duda, tienen a su disposición los comentarios.






miércoles, 28 de mayo de 2014

Regresión lineal: Primeras noción


La regresión lineal es un algoritmo que trata de predecir un valor real por medio de una función lineal de una o mas variables reales de entrada. Es uno de los algoritmos de aprendizaje estadístico mas utilizado y con el cuidado adecuado puede llegar a funcionar verdaderamente bien. Ademas, su simpleza y claridad permiten analizar muchas características útiles para otros modelos. Esto lo convierte en el punto de partida ideal para entender otros algoritmos de aprendizaje estadístico.


Antes de poner manos a la obra, aclaremos algunos puntos. Por si todavía no quedo claro, la regresión lineal es un algoritmo de aprendizaje supervisado y como ya dijimos en la entrada anterior (les dije que iba a ser útil toda esa introducción) se necesita de un conjunto de "datos y respuestas correctas" para realizar el entrenamiento. Siendo \(m\) un natural que representa el tamaño de nuestro conjunto definamos entonces la siguiente notación: \(X^i\) para referirnos a nuestros datos de entrada (empecemos primero por el caso mas sencillo, una sola variable, mas adelante extenderemos la noción a varias) y \(Y^i\) para mencionar a las salidas esperadas siendo el super indice \(i\) la i-esima posición en nuestro conjunto de datos. Juntando toda esta nueva notación, tenemos entonces que los datos con los que contamos para caracterizar a nuestro problema (osea, entrenar a nuestro algoritmo), podrían listarse en tuplas de la forma (dato de entrada, salida esperada) de la siguiente manera \[ (X^1, Y^1) \\ (X^2, Y^2) \\ ... \\ (X^i, Y^i) \\ ... \\ (X^m, Y^m) \].
Bien, supongamos ahora entonces que contamos con el siguiente conjunto de entrenamiento \( (1, 1), (3 , 3), (4, 4) \) representado en el siguiente gráfico donde el eje horizontal representa a mis valores de \(X\) y el vertical o sus respectivas respuestas, osea \(Y\):

Y se nos pide, por alguna razón, calcular cual debería ser la salida en el caso de que nuestro próximo valor de entrada sea un 2. No es para nada complicado darse cuenta que, siguiendo el crecimiento que llevan nuestros valores, la respuesta debería ser la siguiente:
Básicamente, lo que nuestro cerebro esta haciendo (y que trataremos de llevar a nuestro algoritmo) es trazar una linea (osea, generar una función, asumo que si están leyendo esto tienen nociones matemáticas básicas) que pase por la mayor cantidad posible de puntos, cosa que no siempre es posible:

Esta función, que notaremos \(h(x)\) es nuestra hipótesis, aquella que debería representar con la mayor precisión posible a nuestro conjunto de datos. Veamos entonces como gracias a \(h(x)\) también podemos saber los valores de \(h(2,5)\), \(h(3,7)\) e incluso podríamos extenderla hacia adelante obteniendo valores para, por ejemplo \(h(6)\). Tenemos así una relación entre nuestras variables de entrada y nuestra variables de salida. 
Siendo \(h(x)\) una funcional lineal que depende de una sola variable, podemos asumir entonces que tiene la siguiente forma: \(h(x)=X^i.\theta_1\), donde \(\theta\) varia la pendiente o inclinación de la linea que estamos trazando. Pensemos ademas que si queremos que no pase solamente por el origen debemos darle la altura inicial indicada con un valor que en particular, va a estar acompañado siempre de un \(X_0 = 1\). Luego, nuestra función hipótesis queda de la siguiente manera:
\[h(x) = \theta_0 + X^i\theta_1\]

Ahora, supongamos que nuestro conjunto de entrenamiento es un poco mas complicado y se esta representado por el siguiente gráfico:

Se ve a simple vista que, a pesar de poder hacernos una mínima idea de por donde debería ir nuestra hipótesis, es claro que no podríamos definirla con exactitud a simple vista. Volvamos, entonces, a detenernos un segundo y pensar en lo que estamos tratando de buscar. Queremos que para los valores que ya conocemos, la diferencia entre nuestra función y el valor real que debemos obtener (que desde ahora llamaremos costo), sea el menor posible. Si lo pensamos un segundo, lo que buscamos es que \(h(X^i) - Y^i\) sea lo mas cercano posible a cero para todos los valores de entrenamiento. O dicho de otra manera, queremos que al sumar los costos para cada variable, este lo mas cercana a cero. Definamos una función J que en base a los valores de \(\theta\) genere esta idea a la cual llamaremos, como es de esperarse, función de costo:
\[ J(\theta_0, \theta_1) = \frac{1}{2m} \sum\limits_{i=1}^m (h(X^i) - Y^i)^2 \]

Esta función que acabamos de presentar, se conoce como Error Cuadrático Medio (o MSE por sus siglas en ingles). Difiere levemente de la idea que estábamos manejando (cada termino se eleva al cuadrado y al final todo se multiplica por \(\frac{1}{2m}\) porque es un estimador que esta relacionado con la varianza y otras ideas estadísticas) pero la idea que representa es la misma.

Ya tenemos dos funciones fundamentales: Una que representa la idea que queremos construir (\(h(x)\)), y otra que nos sirve para saber cuan lejos estamos del objetivo (\(J(\theta_0, \theta_1)\)). Nuestro objetivo entonces, es tratar de minimizar \(J(\theta_0, \theta_1)\) para acercarla lo mas posible a cero. Para esto, vamos a utilizar la noción de derivada y de descenso por gradiente. Para todo aquel que no tenga nociones de calculo, la derivada de una función en un punto me da la pendiente en ese punto, que vendría a ser cuan inclinada y en que dirección esta la función en el punto donde me encuentro parado. El descenso por gradiente entonces no es mas que esta noción aplicada a buscar un mínimo y consiste en actualizar los valores de \(\theta\) en la dirección donde se produce un descenso. Ahora, si derivamos \(J(\theta_0, \theta_1)\) respecto de \(\theta_0\) y \(\theta_1\) obtenemos lo siguiente:
\[\theta_0' = \frac{1}{m} \sum\limits_{i=1}^m (h(X^i) - Y^i)^2\]
\[\theta_1' = \frac{1}{m} \sum\limits_{i=1}^m (h(X^i) - Y^i)^2 * X^i\]

Y para actualizar los valores de \(\theta\) deberíamos actualizar estos valores hasta alcanzar un error lo suficientemente pequeño o un punto donde ya no se realizan mas actualizaciones (también podria usarse como criterio de parada una cantidad p de actualizaciones):

                                mientras no converga { 
                                      \(\theta_0 = \theta_0 - a * \frac{1}{m} \sum\limits_{i=1}^m (h(X^i) - Y^i)^2\)
                                      \(\theta_1 = \theta_1 - a * \frac{1}{m} \sum\limits_{i=1}^m (h(X^i) - Y^i)^2 * X^i\)
                                }


Con todo esto entonces ya tenemos una noción básica de como, a partir de un conjunto de datos de entrenamiento podemos aproximar una función con la intención de representarla lo mas fielmente posible y así poder conseguir valores fuera de nuestro conjunto con cierta precisión. En la próxima entrega vamos a extender esta noción a funciones de varias variables (en particular utilizando matrices, para facilitar los cálculos y poder computar de forma mas eficiente) y mas adelante vamos a llevar todo esto a código.
Espero haber sido claro, aunque de todas formas, cualquier sugerencia es bienvenida.



martes, 27 de mayo de 2014

Machine Learning: Introduccion.

Machine Learning (o Aprendizaje Automático) es una rama de la Inteligencia Artificial (dentro de las Ciencias de la Computación) que se encarga, básicamente, del estudio de los algoritmos que evolucionan basados en su propia experiencia con el fin de realizar una determinada tarea cada vez mejor. El objetivo principal de estos algoritmos es el de crear una hipótesis sobre los casos existentes para poder dar respuesta a nuevas situaciones. Por ejemplo, un juego de Damas que aprenda en cada partida sobre la forma de jugar de su oponente y mejore su performance frente a este. 


Definición

Siendo mas estrictos, un programa de computadora que realiza cierta tarea T se dice que aprende de la experiencia E si su desempeño, medido por P, mejora gracias a esta. 

Así, por ejemplo, podríamos definir un problema de la siguiente manera:
T: Jugar a las damas.
P: Cantidad de partidas ganadas.
E: Practicar jugando contra si mismo.


Clasificación

Existen dos tipos de algoritmos (en realidad son mas, como el aprendizaje reforzado, pero estas son las principales):
  • Algoritmos de aprendizaje supervisados
  • Algoritmos de aprendizaje no supervisados

- Los algoritmos de aprendizaje supervisados son aquellos en donde se conoce un subconjunto de "respuestas correctas" utilizadas para entrenarlo. Para que quede mas claro, veamos el siguiente ejemplo.
Supongamos que tengo un conjunto de datos que representa una variedad de tumores de acuerdo a su tamaño (el eje horizontal) y a su condición (malignos/benignos) y que se representan en el siguiente gráfico, donde 0 quiere decir que es benigno y 1 que es maligno:


Este conjunto de datos seria el utilizado para entrenar a nuestro algoritmo. Ahora, supongamos que se nos presenta un nuevo caso de un tumor con el tamaño representado por la traza celeste:


La idea de los algoritmos de aprendizaje supervisado es la de tratar de, a partir de los datos de entrenamiento utilizados, poder intuir la respuesta a nuevos casos. En particular, este tipo de problemas donde las variables de salida son discretas (cero o uno, que representan el tipo de tumor) se llaman problemas de "Clasificación". En los casos donde las variables de salida tomen valores continuos (por ejemplo el precio de X activo de acuerdo a sus características, lease el precio de una casa de acuerdo a su superficie en metros cuadrados) se los conoce como problemas de "Regresión".


- Por el otro lado, los algoritmos de aprendizaje no supervisados son aquellos en los que nuestro conjunto de datos no presenta ningún tipo de etiqueta que nos permita diferenciarlos entre si (para que quede mas claro, en el ejemplo anterior las etiquetas eran "maligno" y "benigno"). La idea de estos algoritmos entonces, es la de tratar de caracterizar a nuestro conjunto de datos en subconjuntos que presenten características similares. Por ejemplo, supongamos que contamos con la base de datos de clientes de una compañia que, basados en dos características principales, se ordenan de la siguiente manera (supongamos, edad en el eje horizontal y gasto mensual en efectivo en el eje vertical):


Una algoritmo de aprendizaje no supervisado se encargaría de realizar una segmentación de datos para separar a los clientes en distintas categorías con rasgos compartidos, lo que daría la siguiente salida:


Es verdad, entiendo que los dos ejemplos son bastante sencillos y superficiales, pero lo importante de ambos es que se vea que en un caso tengo distintos elementos para realizar una "aproximación" y en el otro estoy descubriendo características sin tener ningún ejemplo de guía. 

Bastante "teórico" por ahora, pero en próximas entregas prometo empezar a puntualizar mas todavía cada situación.



Introduccion.

Este es un blog sin intenciones. Los post no son mas que una recopilación de ejemplos, apuntes y notas, explicadas con la mayor sencillez posible como una forma de aprender/entender mejor ("no sabes algo hasta que no sepas explicárselo a los demás") los temas tratados, que hago públicos solo por el hecho de que quizás exista alguien a quien le sean de utilidad. La idea principal es tratar temas de Machine Learning pero la temática puede terminar siendo tan variada como quieran mis gustos.
Todas las sugerencias/criticas/comentarios son bienvenidos.

Que lo disfruten.