07.02 - DESIGN ML ALGORITHMS

!wget --no-cache -O init.py -q https://raw.githubusercontent.com/rramosp/20201.xai4eng/master/content/init.py
from init import init; init(force_download=False)
Copy to clipboard

Cómo se diseña un algoritmo ML

  1. Elegir de qué parámetros depende una predicción se define cómo es un modelo.

  2. Definir una función que mida el error de la predicción.

  3. Determinar qué valores de los parámetros minimizan el error de predicción.

## KEEPOUTPUT
from IPython.display import Image
Image(filename='local/imgs/mldesign.jpg', width=800)
Copy to clipboard
../_images/NOTES 07.02 - DESIGNING ML ALGORITHMS_3_0.jpg

Ejemplo

Los Trilotrópicos son insectos imaginarios que viven en las latitudes tropicales. Conocer su densidad de escamas es muy importante para poder saber qué insecticida aplicar. Pero es muy costoso contar las escamas.

Creemos que existe una relación entre la longitud y la densidad de escamas y queremos un modelo que prediga la densidad a partir de la longitud.

Esto es una tarea de regresión, ya que la predicción R

Tenemos datos anotados (alguien contó las escamas de unos cuantos trilotrópicos) estamos ante una tarea de aprendizaje supervisado

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from scipy.optimize import minimize
%matplotlib inline
Copy to clipboard
## KEEPOUTPUT
d = pd.read_csv("local/data/trilotropicos.csv")
print (d.shape)
plt.scatter(d.longitud, d.densidad_escamas)
plt.xlabel(d.columns[0])
plt.ylabel(d.columns[1]);
Copy to clipboard
(150, 2)
Copy to clipboard
../_images/NOTES 07.02 - DESIGNING ML ALGORITHMS_6_1.png

1. Elegimos la forma del modelo

Entrada

  • x(i): longitud del trilotrópico i

Salida esperada

  • y(i): densidad de escamas del trilotrópico i

**Predicción ** decidimos que nuestro modelo tiene la siguiente forma

  • ˆy(i)=θ0+θ1x(i)

La siguiente es una posible combinación de θ0 y θ1 seleccionada aleatoriamente. Ejecútalo varias veces para entender el error.

def linear_prediction(t, x):
    t0,t1 = t
    return t0 + t1*x
Copy to clipboard
## KEEPOUTPUT
t0 = np.random.random()*5+10
t1 = np.random.random()*4-3
p = d.iloc[np.random.randint(len(d))]
long = p.longitud
dens = p.densidad_escamas
print ("RANDOM t0 = %.3f, t1 = %.3f"%(t0,t1))
print ("\nlong = %.3f\ndens = %.3f"%(long, dens))
print ("\npred = %.3f (WITH RANDOM t0 t1)"%linear_prediction([t0,t1], long) )
Copy to clipboard
RANDOM t0 = 10.693, t1 = -1.336

long = 4.770
dens = 7.159

pred = 4.320 (WITH RANDOM t0 t1)
Copy to clipboard
## KEEPOUTPUT
def plot_model(t, prediction):
    xr = np.linspace(np.min(d.longitud), np.max(d.longitud), 100)
    plt.scatter(d.longitud, d.densidad_escamas, s=40, alpha=.2, color="blue", label="")
    plt.plot(xr,prediction(t,xr), lw=2, color="black")
    plt.title("   ".join([r"$\theta_%d$=%.2f"%(i, t[i]) for i in range(len(t))]));

    p = d.iloc[np.random.randint(len(d))]
    pred = prediction(t, p.longitud)
    plt.plot([p.longitud, p.longitud], [p.densidad_escamas, pred], ls="--", color="gray", label=u"error de predicción")
    plt.scatter(p.longitud, p.densidad_escamas, s=70, alpha=.5, color="red", label="random trilobite")
    plt.scatter(p.longitud, pred, s=70, alpha=1., color="black", label=u"predicción")
    plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))

    plt.xlabel(d.columns[0])
    plt.ylabel(d.columns[1]);
    

plot_model([t0,t1], linear_prediction)
Copy to clipboard
../_images/NOTES 07.02 - DESIGNING ML ALGORITHMS_10_0.png

2. Definimos una medida de error

Para un dato cualquiera (i) $err(i)=(ˆy(i)y(i))2=(θ0+θ1x(i)y(i))2$

Para todo el dataset

J(θ0,θ1)=1mm1i=0(θ0+θ1x(i)y(i))2

si asumimos que

  • ¯θ=[θ0,θ1]

  • x(i)=[1,x(i)]

entonces podemos escribir de manera más compacta la expresión anterior:

J(¯θ)=1mm1i=0(¯θ˙x(i)y(i))2
def J(t, x, y, prediction):
    return np.mean( (prediction(t,x)-y)**2)
    
Copy to clipboard
J([t0,t1], d.longitud, d.densidad_escamas, linear_prediction)
Copy to clipboard
27.289016766830752
Copy to clipboard

3. Obtenemos los parámetros que minimizan el error de predicción

observa cómo usamos un algoritmo genérico de optimización

## KEEPOUTPUT
r1 = minimize(lambda t: J(t, d.longitud, d.densidad_escamas, linear_prediction), np.random.random(size=2))
r1
Copy to clipboard
      fun: 2.7447662570802733
 hess_inv: array([[ 5.56677384, -1.08863729],
       [-1.08863729,  0.233761  ]])
      jac: array([-3.87430191e-07, -2.65240669e-06])
  message: 'Optimization terminated successfully.'
     nfev: 36
      nit: 8
     njev: 9
   status: 0
  success: True
        x: array([12.68999889, -0.7180593 ])
Copy to clipboard
## KEEPOUTPUT
plot_model(r1.x, linear_prediction)
print ("error total %.2f"%(J(r1.x, d.longitud, d.densidad_escamas, linear_prediction)))
Copy to clipboard
error total 2.74
Copy to clipboard
../_images/NOTES 07.02 - DESIGNING ML ALGORITHMS_16_1.png

fíjate que son los mismos valores que la regresión lineal clásica

## KEEPOUTPUT
from sklearn.linear_model import LinearRegression

lr = LinearRegression()
lr.fit(d.longitud.values.reshape(-1,1), d.densidad_escamas)
t0, t1 = lr.intercept_, lr.coef_
print (t0, t1)
plot_model([t0,t1], linear_prediction)
print ("error total %.2f"%(J([t0, t1], d.longitud, d.densidad_escamas, linear_prediction)))
Copy to clipboard
12.689998055222224 [-0.71805908]
error total 2.74
Copy to clipboard
../_images/NOTES 07.02 - DESIGNING ML ALGORITHMS_18_1.png

WARN!! Black box optimization can only be used for VERY SIMPLE models

in ML normally you have to:

  • compute the partial derivatives of the parameters of the cost function

  • use optimizers specially designed for ML

Otra forma de modelo

esta vez con tres parámetros y un término cuadrático

ˆy(i)=θ0+θ1x(i)+θ2(x(i))2
def quad_prediction(t, x):
    t0,t1,t2 = t
    return t0 + t1*x + t2*x**2

r2 = minimize(lambda t: J(t, d.longitud, d.densidad_escamas, quad_prediction), np.random.random(size=3))
r2
Copy to clipboard
      fun: 0.5533076730536329
 hess_inv: array([[ 50.71906017, -23.19602691,   2.42715945],
       [-23.19602691,  11.05458208,  -1.18794883],
       [  2.42715945,  -1.18794883,   0.1304395 ]])
      jac: array([-2.98023224e-08,  2.23517418e-08,  2.23517418e-07])
  message: 'Optimization terminated successfully.'
     nfev: 80
      nit: 14
     njev: 16
   status: 0
  success: True
        x: array([26.75881715, -7.61054361,  0.75701901])
Copy to clipboard
## KEEPOUTPUT
plot_model(r2.x, quad_prediction)
print ("error total %.2f"%(J(r2.x, d.longitud, d.densidad_escamas, quad_prediction)))
Copy to clipboard
error total 0.55
Copy to clipboard
../_images/NOTES 07.02 - DESIGNING ML ALGORITHMS_23_1.png

observa como indirectamente hacemos lo mismo con la regresión lineal de sklearn añadiendo explícitamente una columna con la longitud al cuadrado

lr = LinearRegression()
lr.fit(np.r_[[d.longitud.values, d.longitud.values**2]].T, d.densidad_escamas)
t0, (t1, t2) = lr.intercept_, lr.coef_
t0, t1, t2
Copy to clipboard
(26.75883713364987, -7.61055346692438, 0.7570201016172385)
Copy to clipboard