Curso de Machine Learning Aplicado Con Scikit

Descargar como docx, pdf o txt
Descargar como docx, pdf o txt
Está en la página 1de 85

Curso de Machine Learning Aplicado con scikit-

learn

Juan Pablo Morales, CTO and Founder, Arara

Por qué es tan importante definir el problema?


Errores comúnes:
 No tienes problemas por resolver
 Existian soluciones más simples
 No puedes medir el impacto de tu modelo
 No sabes si el problema ya ha sido resuelto
 El problema era imposible de resolver
-> Definir UN PROBLEMA REAL de tu empresa o aplicación, de forma clara y precisa, para
saber si corresponde atacarlo con Machine Learning

Preguntas clave por responder


Reconoce el tipo de aprendizaje que necesitas
1. Qué beneficio piensas generar y para quién?
2. Cuál de los siguientes funcionalidades te sería más útil para lograr ese
objetivo:
A. Predecir alguna métrica
B. Predecir una etiqueta
C. Agrupar elementos similares
D. Optimizar un proceso con prueba y error
Los dos primeros corresponden a Aprendizaje supervisado. Nos enfocaremos en este ya
que es el que está teniendo más impacto en la industria (cf. Andrew NG).
Aterriza tu problema de aprendizaje supervisado
1. Lo que quieres predecir es un valor de qué
tipo?
A.Continuo
B.Discreto
2. Cuál es tu definición de éxito de una
predicción?
3. Con qué datos contarías para hacer esta
predicción?
4. La pregunta que estás tratando de resolver
pertenece a alguna disciplina en particular?
5. Considerando tu intuición en la disciplina,
crees que los datos te permitan predecir tu
objetivo?

Nuestro problema: Predicción de Ingresos de películas.


Contexto: Somos un ente gubernamental que quiere definir sus políticas de financiamiento de
producciones cinematográficas nacionales.
Reconoce el tipo de aprendizaje que necesitas
1. Ayudar a la producción de peliculas de calidad que no logran ser
autosustentables.
2. Nos sería útil saber que películas tienen más dificultad para recuperar en
sus presupuestos. Por consiguiente queremos predecir una métrica: el
ingreso mundial generado por una película.
Aterriza tu problema de aprendizaje supervisado
1. Los ingresos de una película corresponden a valores continuos.
2. Mi éxito será "qué tan cerca estoy del valor real de ingreso generado
por la pelicula".
3. Me basaré en bases de datos públicas de internet
4. El dominio de trabajo es la industria del cine, en particular de la
distribución de peliculas.
5. Sí, de forma general existen bastantes caracteristicas que me pueden
ayudar a saber que película será exitosa como: calidad, actores,
presupuesto, etc...
 Quiero predecir ingresos de péliculas, para tomar mejores decisiones de
financiamiento, con base a una regresión sobre datos de películas extraídos
de internet.
 Mi evaluación del éxito será la precisión de mis predicciones.
 Podré apoyarme en conocimientos específicos de la industria.

Un poco de terminología de ML
El ciclo de trabajo del Machine Learning

Configurar un ambiente Pydata de trabajo


 Scikit-learn es la librería de Machine Learning estandar más
popular según estadisticas de Github.
 Saber ocupar Scikit-learn es equivalente a saber hacer Machine Learning
con Python.
 Scikit-learn se apoya en una familia de librerías comunmente conocida como
el ambiente Pydata.
Para hacer machine learning de forma profesional es importante:
 Contar con librerias:
 cientificas (numpy, scipy, statsmodel),
 procesamiento de datos (pandas, dask),
 machine learning (scikit-learn, keras),
 visualizacion de datos (matplotlib, bokeh, seaborn).
 Contar con ambientes limpios y separados, que se puedan construir
rapidamente y de forma reproducible.
 Trabajar en un IDE adaptado a workflows de machine Learning
Instalar Docker
 Mac y Windows
Para estos dos sistemas operativos basta con ir a https://www.docker.com/ y descargar desde
la sección "Get Docker" el GUI installer apropiado para tu sistema operativo.
 Ubuntu (arquitectura X_86_64)

Copia y pega -una por una- estas lineas en tu terminal.


sudo apt-get remove docker docker-engine docker.io
sudo apt-get update
sudo apt-get install linux-image-extra-$(uname -r) linux-
image-extra-virtual
sudo apt-get install apt-transport-https ca-certificates curl
software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo
apt-key add -
sudo add-apt-repository "deb [arch=amd64]
https://download.docker.com/linux/ubuntu $(lsb_release -cs)
stable"
sudo apt-get update
sudo apt-get install docker-ce
Para confirmar que docker quedo bien instalado en tu computador corre el comando de test
siguiente, que te deberian printear un hola mundo en tu consola:
sudo docker run hello-world

Construir las imagenes


Antes de poder crear un contenedor docker en el cual trabajaremos debemos construir una
imagen. Una imagen corresponde de cierta forma a la "receta" desde la cual se instanciara
nuestro contenedor.
 Descargar Dockerfiles (Github)

Desde tu folder de trabajo (~/platzi-ml/):


[~/platzi-ml] $ git clone
https://github.com/JuanPabloMF/arara-docker-stacks.git
 Crear Imagenes
[~/platzi-ml] $ cd arara-docker-stacks/ararads-base
[~/platzi-ml/arara-docker-stacks/ararads-base] $ sudo docker
build -t ararads-base:1.0 .
[~/platzi-ml/arara-docker-stacks/ararads-base] $ cd
../ararads-tf-cpu
[~/platzi-ml/arara-docker-stacks/ararads-tf-cpu] $ sudo docker
build -t ararads-tf-cpu:1.0 .
Instanciar el contenedor
 Crear folder que sera montado en tus contenedores Docker
[~/platzi-ml] $ mkdir vol
Importante: En este folder es donde deberas descargar/copiar tus datasets para que puedas
verlos en el contenedor que estes trabajando.
$ sudo docker run -ti --name platzi-ml -v ~/platzi-
ml/vol:/home/juanpablo/work/vol -p 9000:8888 ararads-tf-
cpu:1.0 start-notebook.sh --NotebookApp.token=''
Con esto solo quedaria acceder desde chrome a http://localhost:9000/ y estamos listos para
trabajar!
Notas
-v es una opcion que permite conectar un archivo que tengas en tu computador con un archivo
que estara en tu contenedor. Esto es bueno para poder ingresar datos facilmente a tu
contenedor, o extraerlos de forma ordenada
-p te permite exponer un puerto interno del computador a traves de un puerto de tu maquina
local. En terminos simples por aqui es donde accederas a tu jupyter.
Las imagenes que construimos inicializan automaticamente un Jupyter que queda esperando
en su puerto.

Porque Numpy?
 list no tiene buen manejo para los indices cuando se trabaja con listas de
datos de más de dos dimensiones.
 list no posee metodos de algebra lineal, ni de transformaciones de datos.
 En otros lenguajes encontramos estructuras de datos altamente optimizadas
para poder hacer operaciones algebraicas sobre arrays.

Por sobre Numpy se erige todo un ecosistema de librerias muy utiles que iremos viendo en el
recorrido de este curso.
Crear Arrays
In [1]:
#Importar la librería
import numpy as np
In [3]:
a1 = np.array([1,2,3]) # con una lista
type(a1)
Out[3]:
numpy.ndarray
In [4]:
a2 = np.arange(10) # np.arange es un metodo similar al
range del tipo list
In [5]:
a2
Out[5]:
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [6]:
a3 = np.zeros((2,3)) # crear un lista de dos
dimensiones, pre-rellenada con zeros
a4 = np.ones((2,3)) # crear un lista de dos dimensiones,
pre-rellenada con unos

In [7]:
from IPython.display import display
display(a3);display(a4)
array([[ 0., 0., 0.],
[ 0., 0., 0.]])
array([[ 1., 1., 1.],
[ 1., 1., 1.]])
np.linspace(a,b,n) es una función que permite crear arrays de una dimensión, de largo
n, y que contienen puntos entre a y b, distanciados de forma regular. La distancia entre cada

punto sera de  .

In [9]:
a5 = np.linspace(0,1,11)
display(a5)
array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. ])
In [10]:
# Dtypes
a5.dtype
Out[10]:
dtype('float64')
Dimensión de un Array
In [11]:
display(a1)
array([1, 2, 3])
In [12]:
a1.shape # dimensión
Out[12]:
(3,)
In [16]:
display(a3)
array([[ 0., 0., 0.],
[ 0., 0., 0.]])
In [17]:
a3.shape # dimensión
Out[17]:
(2, 3)
In [20]:
a1D = np.array([1,2,3])
a2D = np.array([[1,2,3]])
display(a1D.shape)
display(a2D.shape)
(3,)
(1, 3)
In [21]:
# Son los dos arrays iguales?
np.array_equal(a1D,a2D)
Out[21]:
False
In [23]:
# Reshaping
new_dims = (1,a1D.shape[0])
a = a1D.reshape(new_dims)
In [25]:
np.array_equal(a,a2D)
Out[25]:
True
Acceso a elementos y Slicing

In [26]:
a = np.array([[1,0,3],[4,3,5],[6,10,-1]])
a
Out[26]:
array([[ 1, 0, 3],
[ 4, 3, 5],
[ 6, 10, -1]])
In [30]:
a[2,1]
Out[30]:
10

Para acceder a un elemento de un array de dimensión n, la síntaxis es  .


En este curso y frecuentemente en ML trabajaremos con arrays de dimensión 1 o dimensión
2, por lo que:

 Para un array de 1D: 

 Para un array de 2D: 

In [31]:
a = np.arange(10)
b = np.eye(3)
display(a);display(b)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
array([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.]])
In [34]:
a[:5]
Out[34]:
array([0, 1, 2, 3, 4])
In [36]:
b[0:3,1]
Out[36]:
array([ 0., 1., 0.])
In [37]:
b[2,0:3]
Out[37]:
array([ 0., 0., 1.])
In [38]:
b[:,:]
Out[38]:
array([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.]])
In [ ]:
# Slicing de arrays

# 5 primeros elementos del array a


# esta notación nos permite obtener la segunda
línea del array b
# tercera columna del array b
# todo el array b.

Operaciones sobre arrays


In [39]:
# Aritmetica
a = np.arange(4)

print("a =", a)
print("a + 5 =", a + 5)
print("a - 5 =", a - 5)
print("a * 2 =", a * 2)
print("a / 2 =", a / 2)
print("a // 2 =", a // 2)
print("-a = ", -a)
print("a ** 2 = ", a ** 2)
print("a % 2 = ", a % 2)
a = [0 1 2 3]
a + 5 = [5 6 7 8]
a - 5 = [-5 -4 -3 -2]
a * 2 = [0 2 4 6]
a / 2 = [ 0. 0.5 1. 1.5]
a // 2 = [0 0 1 1]
-a = [ 0 -1 -2 -3]
a ** 2 = [0 1 4 9]
a % 2 = [0 1 0 1]

Operato
ufunc
r

+ np.add
- np.subtract
* np.multiply
In [42]:
# Otras ufuncs interesantes
a = np.arange(4)
b = np.arange(1,5)

display(np.exp(a)) # exponencial
display(np.log(b)) # logaritmo natural
display(np.sqrt(a)) # raiz cuadrada
display(np.greater(a,b)) # superior o igual punto a punto
array([ 1. , 2.71828183, 7.3890561 , 20.08553692])
array([ 0. , 0.69314718, 1.09861229, 1.38629436])
array([ 0. , 1. , 1.41421356, 1.73205081])
array([False, False, False, False], dtype=bool)
In [44]:
a
Out[44]:
array([0, 1, 2, 3])
In [43]:
b
Out[43]:
array([1, 2, 3, 4])
Rendimiento
Las ufuncs corren a velocidad de código compilado C.
De poder utilizarse se deberían preferir a el uso de for loops.
Un código Numpy solo con funciones nativas, sin bucles, se le llama código "vectorizado".

In [2]:
import numpy as np
In [5]:
%%timeit
a = np.arange(1000000)
b = np.zeros(1000000)
i = 0
for el in a:
b[i] = el+el
i+=1
237 ms ± 14.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [9]:
%%timeit
a = np.arange(1000000)
a+a
1.61 ms ± 56.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [6]:
%%timeit
a+a
NameErrorTraceback (most recent call last)
<ipython-input-6-253a555a051d> in <module>()
----> 1 get_ipython().run_cell_magic('timeit', '', 'a+a')

/opt/conda/lib/python3.5/site-packages/IPython/core/interactiveshell.py
in run_cell_magic(self, magic_name, line, cell)
2101 magic_arg_s = self.var_expand(line, stack_depth)
2102 with self.builtin_trap:
-> 2103 result = fn(magic_arg_s, cell)
2104 return result
2105

<decorator-gen-61> in timeit(self, line, cell)

/opt/conda/lib/python3.5/site-packages/IPython/core/magic.py in
<lambda>(f, *a, **k)
185 # but it's overkill for just that one bit of state.
186 def magic_deco(arg):
--> 187 call = lambda f, *a, **k: f(*a, **k)
188
189 if callable(arg):

/opt/conda/lib/python3.5/site-packages/IPython/core/magics/execution.py
in timeit(self, line, cell)
1078 for index in range(0, 10):
1079 number = 10 ** index
-> 1080 time_number = timer.timeit(number)
1081 if time_number >= 0.2:
1082 break

/opt/conda/lib/python3.5/site-packages/IPython/core/magics/execution.py
in timeit(self, number)
158 gc.disable()
159 try:
--> 160 timing = self.inner(it, self.timer)
161 finally:
162 if gcold:

<magic-timeit> in inner(_it, _timer)

NameError: name 'a' is not defined


Estadística y aleatoridad
In [48]:
# Estadística
a = np.arange(10)

display(np.mean(a)) # promedio
display(np.median(a)) # mediana
4.5
4.5
In [49]:
np.percentile(a,40) # percentil
Out[49]:
3.6000000000000001
In [50]:
np.random.random(10) # Aleatoridad
Out[50]:
array([ 0.24532752, 0.19727378, 0.70780713, 0.77635632, 0.6175905 ,
0.17239969, 0.41967961, 0.66742302, 0.8488295 , 0.60224365])

In [1]:
# Importamos las librerias
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sb
In [2]:
# Esta linea permite que los graficos sean renderizados directamente en
nuestro Notebook
## Carguemos en un pandas dataframe nuestra base de datos
%matplotlib inline

Carguemos en un pandas dataframe nuestra base de datos


pd.read_csv es el metodo que nos permite importar los datos desde un CSV y cargarlo en
un **DataFrame**, que es la estructura de base de Pandas

In [3]:
movies = pd.read_csv('../vol/datasets/peliculas.csv',encoding='utf-8')
In [4]:
type(movies)
Out[4]:
pandas.core.frame.DataFrame
In [5]:
movies.head()
In [6]:
# Cuantas lineas y columnas tiene nuestro dataframe
### Un dataframe es una estructura de datos que se compone de los
elementos siguientes
movies.shape
Out[6]:
(5043, 19)
Un dataframe es una estructura de datos que se compone de los elementos siguientes
In [7]:
#visualizemos las columnas
movies.columns
Out[7]:
Index(['movie_title', 'title_year', 'color', 'aspect_ratio', 'duration',
'language', 'country', 'duration.1', 'genres', 'content_rating',
'plot_keywords', 'director_name', 'actor_1_name', 'actor_2_name',
'actor_3_name', 'cast_total_facebook_likes', 'budget',
'imdb_score',
'gross'],
dtype='object')
In [8]:
movies.index
Out[8]:
RangeIndex(start=0, stop=5043, step=1)
In [9]:
columna1 = movies['movie_title']
columna1.head()
Out[9]:
0 Avatar 
1 Pirates of the Caribbean: At World's End 
2 Spectre 
3 The Dark Knight Rises 
4 Star Wars: Episode VII - The Force Awakens  ...
Name: movie_title, dtype: object
In [10]:
linea = movies.loc[10,:]
linea
Out[10]:
movie_title Batman v Superman: Dawn of
Justice 
title_year
2016
color
Color
aspect_ratio
2.35
duration
183
language
English
country
USA
duration.1
183
genres Action|Adventure|
Sci-Fi
content_rating
PG-13
plot_keywords based on comic book|batman|sequel to a
reboot|...
director_name Zack
Snyder
actor_1_name Henry
Cavill
actor_2_name Lauren
Cohan
actor_3_name Alan D.
Purwin
cast_total_facebook_likes
24450
budget
2.5e+08
imdb_score
6.9
gross
3.30249e+08
Name: 10, dtype: object
In [11]:
movies.loc[:,'movie_title'].head()
Out[11]:
0 Avatar 
1 Pirates of the Caribbean: At World's End 
2 Spectre 
3 The Dark Knight Rises 
4 Star Wars: Episode VII - The Force Awakens  ...
Name: movie_title, dtype: object
Intentemos inspeccionar nuestros datos y entenderlos mejor
In [12]:
movies.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5043 entries, 0 to 5042
Data columns (total 19 columns):
movie_title 5043 non-null object
title_year 4935 non-null float64
color 5024 non-null object
aspect_ratio 4714 non-null float64
duration 5028 non-null float64
language 5031 non-null object
country 5038 non-null object
duration.1 5028 non-null float64
genres 5043 non-null object
content_rating 4740 non-null object
plot_keywords 4890 non-null object
director_name 4939 non-null object
actor_1_name 5036 non-null object
actor_2_name 5030 non-null object
actor_3_name 5020 non-null object
cast_total_facebook_likes 5043 non-null int64
budget 4551 non-null float64
imdb_score 5043 non-null float64
gross 4159 non-null float64
dtypes: float64(7), int64(1), object(11)
memory usage: 748.6+ KB
A diferencia de Numpy, Pandas permite cargar no solo datos numericos pero tambien **datos
de texto** que vemos por ejemplo en las columnas de actores y **mezclar distintos tipos de
datos**.
 int64 y float64 corresponden a los mismos dtypes de Numpy
 object es el dtype que permite manejar datos de texto

In [13]:
# columnas númericas y columnas de texto
movies.dtypes == float
Out[13]:
movie_title False
title_year True
color False
aspect_ratio True
duration True
language False
country False
duration.1 True
genres False
content_rating False
plot_keywords False
director_name False
actor_1_name False
actor_2_name False
actor_3_name False
cast_total_facebook_likes False
budget True
imdb_score True
gross True
dtype: bool
In [14]:
movies.dtypes == int
Out[14]:
movie_title False
title_year False
color False
aspect_ratio False
duration False
language False
country False
duration.1 False
genres False
content_rating False
plot_keywords False
director_name False
actor_1_name False
actor_2_name False
actor_3_name False
cast_total_facebook_likes True
budget False
imdb_score False
gross False
dtype: bool
In [ ]:

In [15]:
movies.dtypes == object
Out[15]:
movie_title True
title_year False
color True
aspect_ratio False
duration False
language True
country True
duration.1 False
genres True
content_rating True
plot_keywords True
director_name True
actor_1_name True
actor_2_name True
actor_3_name True
cast_total_facebook_likes False
budget False
imdb_score False
gross False
dtype: bool
In [16]:
num = (movies.dtypes == float) | (movies.dtypes == int)
num
Out[16]:
movie_title False
title_year True
color False
aspect_ratio True
duration True
language False
country False
duration.1 True
genres False
content_rating False
plot_keywords False
director_name False
actor_1_name False
actor_2_name False
actor_3_name False
cast_total_facebook_likes True
budget True
imdb_score True
gross True
dtype: bool
In [17]:
num.index
Out[17]:
Index(['movie_title', 'title_year', 'color', 'aspect_ratio', 'duration',
'language', 'country', 'duration.1', 'genres', 'content_rating',
'plot_keywords', 'director_name', 'actor_1_name', 'actor_2_name',
'actor_3_name', 'cast_total_facebook_likes', 'budget',
'imdb_score',
'gross'],
dtype='object')
In [18]:
for el in num.index:
print(el)
movie_title
title_year
color
aspect_ratio
duration
language
country
duration.1
genres
content_rating
plot_keywords
director_name
actor_1_name
actor_2_name
actor_3_name
cast_total_facebook_likes
budget
imdb_score
gross
In [19]:
num_cols = [c for c in num.index if num[c]]
In [20]:
num_cols
Out[20]:
['title_year',
'aspect_ratio',
'duration',
'duration.1',
'cast_total_facebook_likes',
'budget',
'imdb_score',
'gross']
In [21]:
movies.dtypes == object
Out[21]:
movie_title True
title_year False
color True
aspect_ratio False
duration False
language True
country True
duration.1 False
genres True
content_rating True
plot_keywords True
director_name True
actor_1_name True
actor_2_name True
actor_3_name True
cast_total_facebook_likes False
budget False
imdb_score False
gross False
dtype: bool
In [22]:
obj = (movies.dtypes == object)
obj_cols = [c for c in obj.index if obj[c]]
In [23]:
obj_cols
Out[23]:
['movie_title',
'color',
'language',
'country',
'genres',
'content_rating',
'plot_keywords',
'director_name',
'actor_1_name',
'actor_2_name',
'actor_3_name']
In [24]:
num_cols
Out[24]:
['title_year',
'aspect_ratio',
'duration',
'duration.1',
'cast_total_facebook_likes',
'budget',
'imdb_score',
'gross']
In [25]:
movies_num = movies[num_cols]
In [26]:
# Estadísticas de las columnas númericas
movies_num.describe()
Out[26]:

In [27]:
# Estadísticas de las columnas de texto
Para hacer nuestro primer modelo más simple para este trabajaremos solo con las columnas
númericas.
In [28]:
movies_num['duration'].hist()
Out[28]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f22bfda24a8>

In [29]:
movies_num['imdb_score'].hist()
Out[29]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f22bfd3ea58>
In [30]:
movies_num['budget'].hist()
Out[30]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f22bfc60ba8>

Para poder debuggear esta situación utilizaremos una tecnica muy tipica de pandas que se
llama **boolean filtering**. Basicamente construimos una serie de booleanos con el mismo
indice que nuestro dataframe (la serie clasicamente la llamaremos mask).

In [31]:
mask = (movies_num['budget'] > 1e9)
In [32]:
movies[mask]
Out[32]:
Tenemos un problema de limpieza de los datos. La BDD fue creada sin diferenciar:
 La moneda en la que se ingresaba el presupuesto y el ingreso.
 La zona (país/mundial) en la que se registro el ingreso
In [33]:
# Importar BBDD thenumbers.com## Ahora manejaremos los datos faltantes
(nulos o NaN).
In [34]:
pd.read_csv('../vol/datasets/thenumbers.csv')
Out[34]:
4341 rows × 8 columns
In [35]:
financials = pd.read_csv('../vol/datasets/thenumbers.csv')
In [36]:
financials =
financials[['movie_title','production_budget','worldwide_gross']]
In [37]:
gross_opening = pd.read_csv('../vol/datasets/opening_df.csv')
In [38]:
financials.shape
Out[38]:
(4341, 3)
In [39]:
movies.shape
Out[39]:
(5043, 19)
In [40]:
movies['movie_title']
Out[40]:
0 Avatar 
1 Pirates of the Caribbean: At World's End 
2 Spectre 
3 The Dark Knight Rises 
4 Star Wars: Episode VII - The Force Awakens  ...
5 John Carter 
6 Spider-Man 3 
7 Tangled 
8 Avengers: Age of Ultron 
9 Harry Potter and the Half-Blood Prince 
10 Batman v Superman: Dawn of Justice 
11 Superman Returns 
12 Quantum of Solace 
13 Pirates of the Caribbean: Dead Man's Chest 
14 The Lone Ranger 
15 Man of Steel 
16 The Chronicles of Narnia: Prince Caspian 
17 The Avengers 
18 Pirates of the Caribbean: On Stranger Tides 
19 Men in Black 3 
20 The Hobbit: The Battle of the Five Armies 
21 The Amazing Spider-Man 
22 Robin Hood 
23 The Hobbit: The Desolation of Smaug 
24 The Golden Compass 
25 King Kong 
26 Titanic 
27 Captain America: Civil War 
28 Battleship 
29 Jurassic World 
...
5013 Manito 
5014 Rampage 
5015 Slacker 
5016 Dutch Kills 
5017 Dry Spell 
5018 Flywheel 
5019 Exeter 
5020 The Ridges 
5021 The Puffy Chair 
5022 Stories of Our Lives 
5023 Breaking Upwards 
5024 All Superheroes Must Die 
5025 Pink Flamingos 
5026 Clean 
5027 The Circle 
5028 Tin Can Man 
5029 The Cure 
5030 On the Downlow 
5031 Sanctuary; Quite a Conundrum 
5032 Bang 
5033 Primer 
5034 Cavite 
5035 El Mariachi 
5036 The Mongol King 
5037 Newlyweds 
5038 Signed Sealed Delivered 
5039 The Following 
5040 A Plague So Pleasant 
5041 Shanghai Calling 
5042 My Date with Drew 
Name: movie_title, dtype: object
In [41]:
movies_num
In [42]:
movies_num = pd.concat([movies_num, movies['movie_title']],axis=1)
In [43]:
gross_opening = gross_opening.drop('Unnamed: 0',axis=1)
In [44]:
movies_v2 = pd.merge(financials,movies_num,on='movie_title',how='left')
In [45]:
movies_v2 = pd.merge(movies_v2,gross_opening,on='movie_title',how='left')
In [46]:
movies_v2.shape
Out[46]:
(4385, 13)
Ahora solucionaremos el problema de los datos faltantes
(nulos o NaN).
Los datos faltantes generan problemas con muchos algoritmos de ML. Es por esto que existen
distintas estrategias para lidiar con ellos.
In [47]:
help(pd.Series.value_counts)
Help on function value_counts in module pandas.core.base:

value_counts(self, normalize=False, sort=True, ascending=False,


bins=None, dropna=True)
Returns object containing counts of unique values.

The resulting object will be in descending order so that the


first element is the most frequently-occurring element.
Excludes NA values by default.

Parameters
----------
normalize : boolean, default False
If True then the object returned will contain the relative
frequencies of the unique values.
sort : boolean, default True
Sort by values
ascending : boolean, default False
Sort in ascending order
bins : integer, optional
Rather than count values, group them into half-open bins,
a convenience for pd.cut, only works with numeric data
dropna : boolean, default True
Don't include counts of NaN.

Returns
-------
counts : Series

In [48]:
movies_v2.notnull().apply(pd.Series.value_counts)

In [50]:
available = ((movies_v2 != 0) & (movies_v2.notnull()))
In [51]:
available.all(axis=1).value_counts()
Out[51]:
False 2252
True 2133
dtype: int64
No podemos entrenar nuestro algoritmo con datos cuya variable objetivo no esta definida o
sea nula (valor falso). Eliminemos esas líneas.
In [52]:
mask = available['worldwide_gross']
In [53]:
movies_v2 = movies_v2[mask]
In [54]:
((movies_v2 != 0) & (movies_v2.notnull())).worldwide_gross.value_counts()
Out[54]:
True 4104
Name: worldwide_gross, dtype: int64
En el caso de las features que no son la variable objetivo una mejor solución para lidiar con
los datos faltantes es remplazar estos datos por otros que sean manejables y no afecten la
calidad de las predicciones. La estrategia más comun es utilizar la media de todos los
ejemplos para la feature dada.

In [55]:
movies_v2 = movies_v2.drop('movie_title',axis=1)
In [56]:
movies_v2 = movies_v2.drop('duration',axis=1)
In [57]:
movies_v2 = movies_v2.drop('gross',axis=1)
In [58]:
movies_v2.head()

In [59]:
movies_v2 = movies_v2[available.screens]
/opt/conda/lib/python3.5/site-packages/ipykernel_launcher.py:1:
UserWarning: Boolean Series key will be reindexed to match DataFrame
index.
"""Entry point for launching an IPython kernel.
In [62]:
len(movies_v2)
Out[62]:
2221
In [61]:
from sklearn.preprocessing import Imputer
imputer = Imputer(missing_values=np.nan, strategy='mean')
In [63]:
values = imputer.fit_transform(movies_v2)
X = pd.DataFrame(values)
X.columns = movies_v2.columns
X.index = movies_v2.index
X.head()

In [64]:
len(X)
Out[64]:
2221
In [61]:
movies_v2.values
Out[61]:
array([[ 4.25000000e+08, 2.78391898e+09, 2.00900000e+03, ...,
7.90000000e+00, 7.70254810e+07, 3.45200000e+03],
[ 3.06000000e+08, 2.05866222e+09, nan, ...,
7.10000000e+00, nan, nan],
[ 3.00000000e+08, 9.63420425e+08, 2.00700000e+03, ...,
7.10000000e+00, 1.39802190e+08, 4.36200000e+03],
...,
[ 7.00000000e+03, 9.00000000e+02, 2.00500000e+03, ...,
7.80000000e+00, nan, nan],
[ 3.96700000e+03, 1.04430000e+04, 2.01200000e+03, ...,
6.30000000e+00, nan, nan],
[ 1.10000000e+03, 1.81041000e+05, 2.00400000e+03, ...,
6.60000000e+00, nan, nan]])
In [62]:
values
Out[62]:
array([[ 4.25000000e+08, 2.78391898e+09, 2.00900000e+03, ...,
7.90000000e+00, 7.70254810e+07, 3.45200000e+03],
[ 3.06000000e+08, 2.05866222e+09, 5.91165594e+08, ...,
7.10000000e+00, 5.91165594e+08, 5.91165594e+08],
[ 3.00000000e+08, 9.63420425e+08, 2.00700000e+03, ...,
7.10000000e+00, 1.39802190e+08, 4.36200000e+03],
...,
[ 7.00000000e+03, 9.00000000e+02, 2.00500000e+03, ...,
7.80000000e+00, 1.90568571e+03, 1.90568571e+03],
[ 3.96700000e+03, 1.04430000e+04, 2.01200000e+03, ...,
6.30000000e+00, 2.70237857e+03, 2.70237857e+03],
[ 1.10000000e+03, 1.81041000e+05, 2.00400000e+03, ...,
6.60000000e+00, 2.31883063e+04, 2.31883063e+04]])

In [65]:
X.to_csv('../vol/intermediate_results/X_opening.csv',index=False)
In [68]:
pd.Series(X.index).apply(lambda x: inv_map.loc[x])

NameErrorTraceback (most recent call last)


<ipython-input-68-27d06730cdf2> in <module>()
----> 1 pd.Series(X.index).apply(lambda x: inv_map.loc[x])

/opt/conda/lib/python3.5/site-packages/pandas/core/series.py in
apply(self, func, convert_dtype, args, **kwds)
2292 else:
2293 values = self.asobject
-> 2294 mapped = lib.map_infer(values, f,
convert=convert_dtype)
2295
2296 if len(mapped) and isinstance(mapped[0], Series):

pandas/src/inference.pyx in pandas.lib.map_infer (pandas/lib.c:66124)()

<ipython-input-68-27d06730cdf2> in <lambda>(x)
----> 1 pd.Series(X.index).apply(lambda x: inv_map.loc[x])

NameError: name 'inv_map' is not defined


In [ ]:
X.to_csv('../vol/intermediate_results/X.csv',index=False)
Antes de entrenar un modelo, aprendamos sobre el
funcionamiento y la API de scikit-learn
In [3]:
import numpy as np
import pandas as pd
Scikit-learn es la librería más usada de Machine Learning tradicional [Ver ranking de Github]
(https://github.com/showcases/machine-learning). La librería incluye funcionalidades de:
 Preprocesamiento de datos en  sklearn.preprocessing
 Algoritmos de Machine Learning
en sklearn.linear_model, sklearn.svm, sklearn.ensemble, y
muchos más.
 Evaluación de modelos
en sklearn.model_selection y sklearn.metrics

Scikit-learn sigue muy de cerca los resultados de la investigación e implementa los resultados
más maduros y probados en sus modulos. La [documentación](http://scikit-
learn.org/stable/modules/ensemble.html#forests-of-randomized-trees) extensa muestra como
la librería es un compendio de conocimiento en Machine Learning llevado a software
Una estructura de datos esencial en scikit-learn es el Estimator
Para poder escoger el estimator apropiado una excelente guia es el cheatsheet siguiente,
hecho por uno de los core-dev de scikit-learn.
Implementemos un modelo simple de regresión primero
In [4]:
X = pd.read_csv('../vol/intermediate_results/X.csv')
In [5]:
y = X['worldwide_gross']
In [6]:
X = X.drop('worldwide_gross',axis=1)
In [9]:
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test =


train_test_split(X,y,test_size=0.4,random_state=1)
In [10]:
print(len(X))
print(len(X_train))
print(len(X_test))
4104
2462
1642
In [11]:
X.head(1)

In [12]:
from sklearn.linear_model import Lasso

model = Lasso()
In [13]:
model.fit(X_train,y_train)
/opt/conda/lib/python3.5/site-
packages/sklearn/linear_model/coordinate_descent.py:491:
ConvergenceWarning: Objective did not converge. You might want to
increase the number of iterations. Fitting data with very small alpha may
cause precision problems.
ConvergenceWarning)
Out[13]:
Lasso(alpha=1.0, copy_X=True, fit_intercept=True, max_iter=1000,
normalize=False, positive=False, precompute=False, random_state=None,
selection='cyclic', tol=0.0001, warm_start=False)
In [13]:
predicted = model.predict(X_test)
In [15]:
predicted.shape
Out[15]:
(1642,)
In [19]:
import matplotlib.pyplot as plt
%matplotlib inline

plt.hist([predicted,y_test]);

Evaluemos de forma más fina el comportamiento de nuestro


modelo
Los estimadores y las funciones de sklearn vienen con el máximo de argumentos con valores
por defecto que suelen ser las mejores opciones si no tenemos algun conocimiento particular
el problema. En este caso particular la función estimator.score ya viene con una de las
métricas de sklearn.metrics, que es la métrica sklearn.metric.r2_score

El score R2 de una regresión es una de las formas más comunes de entender su poder
predictivo. Este mientras más cerca de 1 este, mejor es
Los valores que puede tomar son de -infinito hasta 1. Un score R2 negativo es malo, ya que
esto indica que la regresión es peor que si simplemente eligieramos un valor fijo como
predicción para todos los puntos, la media.

In [14]:
model.score(X_test,y_test)
Out[14]:
0.6021797062956975
Bastante bien para un primer modelo!
Un buen score R2 es importante para una regresión. Pero no lo es todo. De forma general los
scores hay que complementarlos con visualizaciones de los datos ya que una métrica no logra
siempre encodear todas las caracteristicas de una distribución de probabilidades. Un ejemplo
es el siguiente:
Siempre visualiza tus resultados, aunque tengas un buen score de performance.

In [22]:
residuals = y_test - predicted
In [23]:
plt.scatter(y_test,residuals)
Out[23]:
<matplotlib.collections.PathCollection at 0x7f3f6930fd30>

In [24]:
ap_residuals = np.abs(residuals) / y_test
In [25]:
plt.scatter(y_test,ap_residuals)
Out[25]:
<matplotlib.collections.PathCollection at 0x7f3f6927b048>
In [26]:
lap_residuals = np.log(ap_residuals)
In [28]:
plt.scatter(y_test,lap_residuals)
Out[28]:
<matplotlib.collections.PathCollection at 0x7f3f691be1d0>

In [30]:
plt.hist(lap_residuals,bins=100, normed=1, histtype='step',
cumulative=True);

In [32]:
plt.hist(lap_residuals, bins=100, normed=1,
histtype='step',cumulative=True);
plt.axis([-2,0,0,1])
np.power(np.exp(1)*np.ones(5),np.linspace(-2,0,5))
Out[32]:
array([ 0.13533528, 0.22313016, 0.36787944, 0.60653066, 1. ])
In [44]:
plt.scatter(np.arange(8),model.coef_)
Out[44]:
<matplotlib.collections.PathCollection at 0x7f3f68fb8b00>

In [79]:
X = pd.read_csv('../vol/intermediate_results/X.csv')
In [78]:
X = X.drop('gross',axis=1)
In [80]:
X = X.drop('worldwide_gross',axis=1)
In [81]:
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.4)


In [82]:
model = Lasso()
model.fit(X_train,y_train)
Out[82]:
Lasso(alpha=1.0, copy_X=True, fit_intercept=True, max_iter=1000,
normalize=False, positive=False, precompute=False, random_state=None,
selection='cyclic', tol=0.0001, warm_start=False)
In [83]:
model.score(X_test,y_test)
Out[83]:
0.87745681705925049
In [87]:
X.columns
Out[87]:
Index(['production_budget', 'title_year', 'aspect_ratio', 'duration.1',
'cast_total_facebook_likes', 'budget', 'imdb_score', 'gross'],
dtype='object')
In [92]:
for el in zip(list(X.columns),list(model.coef_)):
print(el)
('production_budget', 0.76287929242158148)
('title_year', 0.82847598230185637)
('aspect_ratio', 0.3963785144996036)
('duration.1', 1.5849161930072848)
('cast_total_facebook_likes', -218.60395867759215)
('budget', 0.0031745843702155035)
('imdb_score', 4426444.4687358243)
('gross', 2.1308279122355804)

Mejorar la performance de nuestros modelos no solo pasa por optimizar sus parametros.
Una de las partes clave, y según algunos expertos la más importante, es la de **diseñar la
representación en la que se entregan los datos a los modelos** para que estos los procesen.
Esto equivale, en palabras más simples, en definir de forma inteligente las features (columnas)
de nuestras tablas de datos.
Ejemplo de feature engineering:
El problema:

Supongamos que estamos tratando de resolver el problema siguiente.


 Tenemos un problema de reconocer si ciertos datos con una sola feature
son de una clase 1 o de una clase 2 (por ejemplo "el producto esta
deficiente" o "el producto esta funcional").
 Por lo tanto estamos resolviendo una clasificación.
 Para esta clasificación decidimos tomar un SVM, que es un modelo
poderoso que funciona buscando la "mejor" recta que separa los puntos de
cada clase.

Como podemos ver no existe un separador óptimo. Debemos para resolver el problema
buscar un modelo aún más poderoso? No necesariamente.

Agregemos una nueva feature:


Claramente con esta nueva feature vemos que existe una recta que separa los espacios de
puntos.
Esta recta tendra un score ampliamente mejor que cualquier solucion al primer problema.
Principios de diseño de Features
Diseñar tus features es un arte más que una ciencia (por lo que en general te recomendamos
ganar experiencia leyendo articulos cientificos y viendo soluciones
1. Features Informativas: Tus features son más utiles mientras más
correlación tengan tu variable objetivo.
2. Features Independientes: Para no tener redudancias tus features deberían
ser lo más independientes posible entre ellas.
3. Cantidad de Features controlada: Nuestra intuición nos falla en
dimensiones superiores a 3 (ver video maldicion de la dimensionalidad). En
la mayoría de los casos aumentar la cantidad de features afecta
negativamente la performance si no contamos con una gran cantidad de
datos. Por ultimo pocas features aseguran una mejor interpretabilidad de los
modelos
Ejemplo de Feature informativa y Feature no informativa
Predecir el **precio de una casa** en **función de sus metros cuadrados**.
Predecir el **precio de una casa** en **función de la temperatura del mar**.
Es importante entender la correlación entre la feature y la variable objetivo. Más sobre esto en
los siguientes videos.
Visualizar interdepencia entre variables
In [4]:
import pandas as pd
X =
pd.read_csv('../vol/intermediate_results/X.csv').drop('worldwide_gross',a
xis=1)
In [6]:
import seaborn as sns
%matplotlib inline

sns.heatmap(X.corr())
Out[6]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f4ff97f7198>

La maldición de la dimensión

Datasaurus Dozen y Anscombe's quartet:

Utilidad de la capacidad de entender los datos en 1, 2 y 3 dimensiones del ojo humano.


Maldición de la dimensionalidad:
En dimensión superior o igual a 4, nuestra capacidad de entender los datos se pierde, y
aún peor fenomenos extraños/contraproducentes ocurren
Ejemplo 1

Que largo debe tener cada arista de un hypercubo de dimension p que capture 10% del
volumen de un hypercubo de volumen 1 que lo contiene?

$$ V_{hypercubo} = a^p\ y\ si\ V_{hypercubo} = 0.1 \implies a = 0.1^{1/p}$$$$$$


In [7]:
import matplotlib.pyplot as plt
import numpy as np

x = np.arange(1,15)
y = np.power(0.1,1/x)
plt.plot(x,y)
Out[7]:
[<matplotlib.lines.Line2D at 0x7f4ff5e73438>]
En dimensión 10: Necesitamos un hypercubo que cubra 80% de cada una de las aristas para
solamente obtener 10% del volumen!
En alta dimensión es muy poco probable que tus ejemplos cubran todo el espacio de forma
densa.
Por ende en **alta dimensión necesitas una cantidad de datos que crece exponencialmente
para poder entrenar tus modelos**.
Te recomendamos tener cuidado al aumentar la dimensión de tus datos, no esta prohibido,
pero hacerlo de forma exagerada te puede llevar hacia estos problemas.

In [1]:
import warnings
warnings.simplefilter("ignore")
In [2]:
%matplotlib inline
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

Feedback de tus modelos


Ciertos modelos como la regresión o los arboles se dicen **"interpretables"**. Esto quiere decir
que de los resultados de los modelos podemos sacar conclusiones o **"insights"**.
En particular la regresión Lasso es interpretable:
 mientras más grande el coeficiente para una feature, más relevante es esta
para la regresión.
 la regresión Lasso trata de seleccionar un pequeño número de features
relevantes.
In [3]:
X = pd.read_csv('../vol/intermediate_results/X.csv')

y = X['worldwide_gross']
X = X.drop('worldwide_gross',axis=1)
In [4]:
from sklearn.linear_model import Lasso

model = Lasso()
In [5]:
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X,y)


In [7]:
len(X_train)/len(X)
Out[7]:
0.75
In [8]:
model.fit(X_train,y_train)
Out[8]:
Lasso(alpha=1.0, copy_X=True, fit_intercept=True, max_iter=1000,
normalize=False, positive=False, precompute=False, random_state=None,
selection='cyclic', tol=0.0001, warm_start=False)
In [9]:
model.score(X_test,y_test)
Out[9]:
0.53670649813230509
In [12]:
model.coef_
Out[12]:
array([ 2.89526507e+00, -1.40301472e+00, 1.66308214e-02,
3.33819964e+00, 2.15878265e+02, -8.00752044e-03,
2.53750354e+07])
In [15]:
var = np.floor(np.log10(np.abs(model.coef_)))
In [17]:
plt.rcParams["figure.figsize"] = [12,8]
plt.plot(var)
plt.xticks(np.arange(7),list(X.columns));
Esto nos guía a guardar únicamente:
 production_budget
 title_year
 duration
 cast_total_facebook_likes
 imdb_score
Correlación entre variables
In [18]:
import seaborn as sns

Z = pd.concat([X,y],axis=1)
sns.pairplot(Z)
Out[18]:
<seaborn.axisgrid.PairGrid at 0x7faf37e93400>
In [28]:
clase = pd.cut(X['production_budget'],8).cat.codes.rename('class')
Z2 = pd.concat([X,clase],axis=1)
In [29]:
sns.pairplot(Z2,hue='class')
Out[29]:
<seaborn.axisgrid.PairGrid at 0x7faf37ebc748>
In [31]:
Z3 = pd.concat([X,y],axis=1)
sns.heatmap(Z3.corr())
Out[31]:
<matplotlib.axes._subplots.AxesSubplot at 0x7faf2191fe10>
De esto concluimos, sin sorpresa, que son muy importantes:
 production_budget
 imdb_score
Metodos de selección automatica de features
Sklearn posee una serie de métodos para seleccionar las mejores features. Estos métodos los
puedes encontrar en sklearn.feature_selection

In [32]:
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import mutual_info_regression

selector = SelectKBest(mutual_info_regression, k=4)


selector.fit(X,y)
Out[32]:
SelectKBest(k=4,
score_func=<function mutual_info_regression at 0x7faf38ed7730>)
In [34]:
scores = selector.scores_
plt.rcParams["figure.figsize"] = [12,8]
plt.plot(scores)
plt.xticks(np.arange(7),list(X.columns));

Del analisis univariante obtenemos que las mejores features son:


 production_budget
 cast_total_facebook_likes
 budget
Guardaremos las 5 features entregadas por la interpretación de nuestra regresión Lasso
In [35]:
X2 =
X[['production_budget','title_year','duration.1','cast_total_facebook_lik
es','imdb_score']]
X3 = X[['production_budget','cast_total_facebook_likes','imdb_score']]

Veamos los resultados del modelo con estas features


In [36]:
X_train, X_test, y_train, y_test = train_test_split(X,y)
In [37]:
cols2 =
['production_budget','title_year','duration.1','cast_total_facebook_likes
','imdb_score']
X2_train, X2_test, y2_train, y2_test = X_train[cols2], X_test[cols2],
y_train, y_test

cols3 = ['production_budget','cast_total_facebook_likes','imdb_score']
X3_train, X3_test, y3_train, y3_test = X_train[cols3], X_test[cols3],
y_train, y_test
In [40]:
from sklearn.linear_model import Lasso

model1 = Lasso()
model2 = Lasso()
model3 = Lasso()

model1.fit(X_train,y_train)
model2.fit(X2_train,y2_train)
model3.fit(X3_train,y3_train)
Out[40]:
Lasso(alpha=1.0, copy_X=True, fit_intercept=True, max_iter=1000,
normalize=False, positive=False, precompute=False, random_state=None,
selection='cyclic', tol=0.0001, warm_start=False)
In [41]:
print(model1.score(X_test,y_test))
print(model2.score(X2_test,y2_test))
print(model3.score(X3_test,y3_test))
0.588827166128
0.5887559341
0.564313646779

In [ ]:

import warnings
warnings.simplefilter("ignore")
Escalamiento de los datos
In [ ]:

%matplotlib inline
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
Diversos algoritmos son sensibles a la escala en la que viene cada feature. **Re-escalarlos**
puede traer significativas mejoras de rendimiento.

Existen distintas estrategias de escalamiento de tus features, pero la más común es la


estandarización donde convertimos la variable para que la distribución de esta siga una
distribución que es Gaussiana de media 0 y de desviación estandar 1.
In [28]:

from sklearn.model_selection import train_test_split

X = pd.read_csv('../vol/intermediate_results/X.csv')
y = X['worldwide_gross']
X = X.drop('worldwide_gross',axis=1)
X_train, X_test, y_train, y_test = train_test_split(X,y)
In [ ]:

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
scaler.fit(X_train)
In [ ]:

scaler.mean_
In [ ]:

scaler.scale_
In [ ]:

X.values
In [ ]:

scaler.transform(X_train)
In [ ]:

X_train_scaled, X_test_scaled = (scaler.transform(X_train),


scaler.transform(X_test))
In [ ]:

from sklearn.linear_model import Lasso

model = Lasso()
model_scaled = Lasso()

model.fit(X_train,y_train)
model_scaled.fit(X_train_scaled,y_train)
In [ ]:

print(model.score(X_test,y_test))
print(model_scaled.score(X_test_scaled,y_test))
Los modelos de regresión no se ven afectados por el escalamiento de las features. Los de
clasificación sí.

Simplificar las transformaciones con pipelines


Para hacer tu código más reproducible, y para evitar tener que aplicar multiples veces una
misma transformación te recomendamos utilizar  sklearn.pipeline.make_pipeline
que permite encadenar transformaciones a tus modelos.

In [ ]:

from sklearn.pipeline import make_pipeline


model_scaled = make_pipeline(StandardScaler(),
Lasso())

model_scaled.fit(X_train,y_train)
In [ ]:

print(model_scaled.score(X_test,y_test))
Crear nuevas features de forma automática
In [ ]:

A = np.arange(6).reshape(3, 2)
A
In [ ]:

from sklearn.preprocessing import PolynomialFeatures

transformer = PolynomialFeatures(2)
transformer.fit_transform(A)

PolynomialFeatures transforma una matriz   a 


In [ ]:

X.shape
In [ ]:

transformer = PolynomialFeatures(2)
transformer.fit_transform(X).shape
In [25]:

model_poly = make_pipeline(PolynomialFeatures(2),
Lasso())
model_poly.fit(X_train,y_train)
model_poly.score(X_test,y_test)
/opt/conda/lib/python3.5/site-
packages/sklearn/linear_model/coordinate_descent.py:484:
ConvergenceWarning: Objective did not converge. You might want to
increase the number of iterations. Fitting data with very small alpha may
cause precision problems.
ConvergenceWarning)
Out[25]:

-7401097975.623044
In [27]:

model = Lasso()
model.fit(X_train,y_train)
model.score(X_test,y_test)
/opt/conda/lib/python3.5/site-
packages/sklearn/linear_model/coordinate_descent.py:484:
ConvergenceWarning: Objective did not converge. You might want to
increase the number of iterations. Fitting data with very small alpha may
cause precision problems.
ConvergenceWarning)
Out[27]:

0.57593747144784135
Crear features categóricas
En terminos de Machine Learning a las features que pueden tomar un número finito de valores
se les llama categóricas. Ejemplos para esto són: género, páis, grado académico, etc.

Un mapeo del tipo   tiene el problema de asignarle un ordén a los valores posibles de la
categoría. Este orden impacta de distintas maneras los algoritmos de Machine Learning, por

ejemplo aquellos que dependen de la topología de   y de la función de distancia entre


puntos en este espacio, considerarán que ciertas categorías se encuentran más cercanas
unas de otras, siendo que esto es generado puramente artificialmente por el encoding, y no
por las datos per se.

Para no introducir información falsa o erronéa en nuestro modelos existen formas más
inteligentes de encodear nuestros datos.
Encoding one-hot

Este encoding consiste en asignarle una columna a cada categoría y rellenarla con 0 y 1 de la
forma siguiente:
In [29]:

d = pd.DataFrame([['Chile','Colombia','Colombia','Venezuela'],
['hombre','mujer','hombre','mujer']])
d = d.T
d.columns = pd.Index(['pais','genero'])
d
Out[29]:

pais genero

0 Chile hombre

1 Colombia mujer

2 Colombia hombre
pais genero

3 Venezuela mujer

In [30]:
pd.get_dummies(d)
Out[30]:

p
p g
a g
a e
p i e
i n
a s n
s e
i _ e
_ r
s V r
C o
_ e o
o _
C n _
l h
h e m
o o
i z u
m m
l u j
b b
e e e
i r
l r
a e
a

0 1 0 0 1 0

1 0 1 0 0 1

2 0 1 0 1 0

3 0 0 1 0 1

Sklearn también ofrece un objeto OneHotEncoder pero es un poco más díficil de utilizar, así
que por criterios pedagogicos hemos elegido pd.get_dummies. Sin embargo el objeto de
sklearn tiene la ventaja de ser pipeable, por lo que es bueno considerarlo para ciertos casos
de uso.
Cuantas columnas generaríamos con un one-hot encoding de nuestras features categóricas?
In [31]:

movies_obj = pd.read_csv('../vol/intermediate_results/movies_obj.csv')
In [33]:

movies_obj.apply(pd.Series.nunique).sort_values()
Out[33]:

color 2
content_rating 18
language 47
country 65
genres 914
actor_1_name 2097
director_name 2398
actor_2_name 3032
actor_3_name 3521
plot_keywords 4760
movie_title 4917
dtype: int64
Las features más informativas son las del casting. Si embargo haciendo un one-hot encoding
de estas estaríamos aumentando la dimensión por 2000 y algo!!
Encoding Binario
Esta técnica no es canónica por lo que tendremos que buscarla en otra librería. Sin embargo
el autor tuvo la buena idea de hacer su API compatible con la de sklearn, así que no
tendremos ninguna dificultad en usarla.

In [34]:

!pip install category_encoders


Requirement already satisfied: category_encoders in
/opt/conda/lib/python3.5/site-packages
Requirement already satisfied: scikit-learn>=0.15.0 in
/opt/conda/lib/python3.5/site-packages (from category_encoders)
Requirement already satisfied: scipy>=0.9 in
/opt/conda/lib/python3.5/site-packages (from category_encoders)
Requirement already satisfied: statsmodels>=0.6.0 in
/opt/conda/lib/python3.5/site-packages (from category_encoders)
Requirement already satisfied: numpy>=1.8.0 in
/opt/conda/lib/python3.5/site-packages (from category_encoders)
Requirement already satisfied: pandas>=0.15.0 in
/opt/conda/lib/python3.5/site-packages (from category_encoders)
Requirement already satisfied: patsy>=0.4.0 in
/opt/conda/lib/python3.5/site-packages (from category_encoders)
Requirement already satisfied: python-dateutil>=2 in
/opt/conda/lib/python3.5/site-packages (from pandas>=0.15.0-
>category_encoders)
Requirement already satisfied: pytz>=2011k in
/opt/conda/lib/python3.5/site-packages (from pandas>=0.15.0-
>category_encoders)
Requirement already satisfied: six in /opt/conda/lib/python3.5/site-
packages (from patsy>=0.4.0->category_encoders)
In [35]:

categoricals =
pd.read_csv('../vol/intermediate_results/categoricals.csv').set_index('Un
named: 0')
In [36]:

categoricals.head(2)
Out[36]:

actor_1_n director_n
ame ame

Unnam
ed: 0

CCH James
0
Pounder Cameron

Doug Doug
1
Walker Walker

In [37]:
categoricals = categoricals.reset_index(drop=True).fillna(0)
In [38]:

X_binenc = pd.concat([X,categoricals],axis=1)
In [39]:

X_binenc.head()
Out[39]:
In [40]:
import category_encoders as ce
encoder = ce.BinaryEncoder(cols=['actor_1_name','director_name'])
In [42]:

encoder.fit_transform(X_binenc).shape
Out[42]:

(4104, 29)
In [43]:

X_binenc = encoder.fit_transform(X_binenc)
In [44]:

Xb_train, Xb_test, y_train, y_test = train_test_split(X_binenc,y)


In [45]:

X_train, X_test = (Xb_train[X.columns],Xb_test[X.columns])


In [46]:

model_binenc = Lasso()
model = Lasso()
In [47]:

model_binenc.fit(Xb_train,y_train)
model.fit(X_train,y_train)
/opt/conda/lib/python3.5/site-
packages/sklearn/linear_model/coordinate_descent.py:484:
ConvergenceWarning: Objective did not converge. You might want to
increase the number of iterations. Fitting data with very small alpha may
cause precision problems.
ConvergenceWarning)
Out[47]:

Lasso(alpha=1.0, copy_X=True, fit_intercept=True, max_iter=1000,


normalize=False, positive=False, precompute=False, random_state=None,
selection='cyclic', tol=0.0001, warm_start=False)
In [48]:

print(model_binenc.score(Xb_test,y_test))
print(model.score(X_test,y_test))
0.623169426585
0.624091664736
Aumentamos el rendimiento de nuestro algoritmo pero no de forma significativa.
Mantengamos entonces la dimensionalidad de nuestro espacio de features baja, y vamos a
buscar modelos más complejos.
Conocimiento experto
Una grán parte del diseño de las features pasa por un **conocimiento espécifico del dominio
en el que se esta trabajando**.
Por ejemplo para analizar una imagen nuestro cerebro no se concentra en los millones de
pixeles de una imagen, pero sólo en algunos relevantes como los de los contornos. Durante
un buen tiempo **los sistemas de visión de computadores encodeaban features que traducían
este conocimiento experto (contornos).**
Una de las únicas formas de obtener este conocimiento de forma sistemática es ir a bucear en
repositorios de papers de Machine Learning como Arxiv, y estudiar la investigación que se ha
hecho sobre el dominio específico.

Más datos de calidad


Nada le gana conseguir más datos que sean encodeables en features de calidad.
Píramide de Maslow del Machine Learning

Contamos con la base de datos de ganancias de las péliculas el primer fin de semana de
exhibición, así como la cantidad de cines en la que fue estrenada.
In [49]:

pd.read_csv('../vol/datasets/opening_df.csv').head()
Out[49]:
Puedes mejorar considerablemente nuestra predicción?

In [ ]:
import warnings
warnings.simplefilter("ignore")
In [1]:
%matplotlib inline
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

Métodos de evaluación
Por ahora hemos visto que:
 Se necesita separar de forma aleatoria en datos de entrenamiento y testeo
para poder evaluar performance del algoritmo
 Existen diversas métricas para evaluar rendimiento, y elegimos la nuestra
según las caracteristicas de nuestro problema
 Es útil apoyar la evaluación con visualizaciones de errores, como por
ejemplo scatterplots de residuales

Sin embargo nuestro método hasta ahora tiene una falla. Este depende de la forma en que
fueron elegidos nuestros datos de forma aleatoria:
 Podemos tener suerte y caer en un train set y test set que sea ideal para
nuestro modelo.
 Podemos tener pésima performance con esa separación de datos pero no
en otros.
Controlar la aleatoridad en train_test_split
train_test_split separa cada vez que lo llamamos los datos de forma diferente. Para poder
comparar modelos, hacer un código más limpio y compacto y para poder hacer nuestros
experimentos reproducibles utilizaremos el parametro random_state.
In [2]:
X = pd.read_csv('../vol/intermediate_results/X_opening.csv')
y = X['worldwide_gross']
X = X.drop('worldwide_gross',axis=1)
In [8]:
from sklearn.model_selection import train_test_split

X_train,X_test, y_train,y_test = train_test_split(X,y, random_state=1)


In [9]:
X2_train,X2_test, y2_train,y2_test = train_test_split(X,y,
random_state=1)
In [10]:
pd.DataFrame.equals(X_train,X2_train)
Out[10]:
True
Cross Validation

In [11]:
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import Lasso

scores = cross_val_score(Lasso(),X,y,cv=5,scoring='r2')
scores
/opt/conda/lib/python3.5/site-
packages/sklearn/linear_model/coordinate_descent.py:491:
ConvergenceWarning: Objective did not converge. You might want to
increase the number of iterations. Fitting data with very small alpha may
cause precision problems.
ConvergenceWarning)
/opt/conda/lib/python3.5/site-
packages/sklearn/linear_model/coordinate_descent.py:491:
ConvergenceWarning: Objective did not converge. You might want to
increase the number of iterations. Fitting data with very small alpha may
cause precision problems.
ConvergenceWarning)
Out[11]:
array([ 0.59316596, 0.68931527, 0.55383855, 0.18147236, 0.23040894])
In [12]:
scores.mean()
Out[12]:
0.44964021745791793
In [13]:
Lasso().fit(X_train,y_train).score(X_test,y_test)
/opt/conda/lib/python3.5/site-
packages/sklearn/linear_model/coordinate_descent.py:491:
ConvergenceWarning: Objective did not converge. You might want to
increase the number of iterations. Fitting data with very small alpha may
cause precision problems.
ConvergenceWarning)
Out[13]:
0.79261902949633645
Selección de modelos
Overfitting o underfitting?

Recuerden que para saber si estamos en overfitting o en underfitting necesitamos los scores
de entrenamiento y test.
In [16]:
!pip install --upgrade scikit-learn

Requirement already up-to-date: scikit-learn in


/opt/conda/lib/python3.5/site-packages
In [17]:
from sklearn.model_selection import cross_validate

results = cross_validate(Lasso(),X,y,return_train_score=True,cv=5)
results
/opt/conda/lib/python3.5/site-
packages/sklearn/linear_model/coordinate_descent.py:491:
ConvergenceWarning: Objective did not converge. You might want to
increase the number of iterations. Fitting data with very small alpha may
cause precision problems.
ConvergenceWarning)
/opt/conda/lib/python3.5/site-
packages/sklearn/linear_model/coordinate_descent.py:491:
ConvergenceWarning: Objective did not converge. You might want to
increase the number of iterations. Fitting data with very small alpha may
cause precision problems.
ConvergenceWarning)
Out[17]:
{'fit_time': array([ 0.00688601, 0.00739503, 0.01647115, 0.05436873,
0.05301976]),
'score_time': array([ 0.0004952 , 0.00049186, 0.00062156, 0.00069237,
0.00061393]),
'test_score': array([ 0.59316596, 0.68931527, 0.55383855, 0.18147236,
0.23040894]),
'train_score': array([ 0.68988012, 0.77004932, 0.76604995,
0.76123379, 0.75837599])}
In [18]:
test_scores = results['test_score']
train_scores = results['train_score']
print(np.mean(train_scores))
print(np.mean(test_scores))
0.749117836304
0.449640217458
Tenemos bias por lo que buscaremos modelos más complejos.
Validation Curves y Learning Curves
In [19]:
from sklearn.neighbors import KNeighborsRegressor

cross_validate(KNeighborsRegressor(), X, y, cv=5)
Out[19]:
{'fit_time': array([ 0.00543714, 0.00307131, 0.00355124, 0.00312901,
0.00317121]),
'score_time': array([ 0.0024519 , 0.00276566, 0.00358152, 0.00287461,
0.00244856]),
'test_score': array([ 0.3647382 , 0.59274527, 0.21545625, 0.15143495,
0.25635077]),
'train_score': array([ 0.73553883, 0.78647652, 0.78386739,
0.77876542, 0.77477287])}
In [20]:
cross_validate(KNeighborsRegressor(n_neighbors=10), X, y, cv=5)
Out[20]:
{'fit_time': array([ 0.00420117, 0.00292206, 0.00309992, 0.00377607,
0.00303674]),
'score_time': array([ 0.00300527, 0.0043323 , 0.00517344, 0.00384665,
0.00271416]),
'test_score': array([ 0.23553954, 0.61921355, 0.24881301, 0.1209604 ,
0.2466995 ]),
'train_score': array([ 0.67830521, 0.76365722, 0.76231726,
0.75701303, 0.75061953])}
In [22]:
n = np.arange(2,50,2)
n
Out[22]:
array([ 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32,
34,
36, 38, 40, 42, 44, 46, 48])
In [23]:
n.shape
Out[23]:
(24,)
In [39]:
from sklearn.model_selection import validation_curve

train_scores, test_scores = validation_curve(KNeighborsRegressor(),


X,
y,
param_name='n_neighbors',
param_range=n,
cv=5)
In [28]:
np.mean(train_scores,axis=1)
Out[28]:
array([ 0.86831591, 0.79120817, 0.7593398 , 0.7498298 , 0.74238245,
0.73284018, 0.72586058, 0.71779833, 0.71281982, 0.70976325,
0.70723469, 0.70502429, 0.70174649, 0.69741543, 0.69379214,
0.69163113, 0.68955146, 0.6862285 , 0.68321376, 0.68018032,
0.67885534, 0.67522056, 0.67135123, 0.66953759])
In [34]:
plt.plot(np.mean(train_scores,axis=1))
plt.plot(np.mean(test_scores,axis=1))
plt.xticks(np.arange(24),n);

In [36]:
from sklearn.model_selection import learning_curve

lc = learning_curve(KNeighborsRegressor(n_neighbors=6),X,y,cv=5)
samples, train, test = lc[0], lc[1], lc[2]
In [38]:
plt.plot(samples[1:],np.mean(train,axis=1)[1:])
plt.plot(samples[1:],np.mean(test,axis=1)[1:])
Out[38]:
[<matplotlib.lines.Line2D at 0x7f5caf524160>]

El modelo aún está aprendiendo, sin embargo no tenemos como obtener datos adicionales.
Como solucionar el overfitting y el underfitting?

Viarianza Alta:
 Conseguir más ejemplos
 Reducir cantidad de features
 Aumentar coeficiente de regularización

Bias Alto:
 Más features
 Modelo más complejo

Mal resultado general:


 Probar otro algoritmo/familia de modelos, quizás las hipotesis del modelo no
son cumplidad por tu dataset

In [ ]:
import warnings
warnings.simplefilter("ignore")
In [1]:
%matplotlib inline
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
Según distintos benchmarks (papers, kaggle.com) los **algoritmos de uso general** que
tienen más veces la mejor performance son: **Gradient Boosted Trees, Random Forest y
SVM**.

Decision Trees
In [5]:
from sklearn.tree import DecisionTreeRegressor

model = DecisionTreeRegressor(max_depth=2)
In [6]:
from sklearn.model_selection import train_test_split

X = pd.read_csv('../vol/intermediate_results/X_opening.csv')
y = X['worldwide_gross']
X = X.drop('worldwide_gross',axis=1)
In [7]:
X_train, X_test, y_train, y_test = train_test_split(X,y,random_state=1)
In [8]:
model.fit(X_train,y_train)
Out[8]:
DecisionTreeRegressor(criterion='mse', max_depth=2, max_features=None,
max_leaf_nodes=None, min_impurity_decrease=0.0,
min_impurity_split=None, min_samples_leaf=1,
min_samples_split=2, min_weight_fraction_leaf=0.0,
presort=False, random_state=None, splitter='best')
In [9]:
import graphviz
In [10]:
from sklearn.tree import export_graphviz

treedot = export_graphviz(model,
out_file=None,
feature_names=X.columns)
In [11]:
treedot
Out[11]:
'digraph Tree {\nnode [shape=box] ;\n0 [label="opening_gross <=
41613376.0\\nmse = 4.4919943637e+16\\nsamples = 1665\\nvalue =
141540319.054"] ;\n1 [label="opening_gross <= 22074048.0\\nmse =
1.33338221931e+16\\nsamples = 1506\\nvalue = 92999937.199"] ;\n0 -> 1
[labeldistance=2.5, labelangle=45, headlabel="True"] ;\n2 [label="mse =
4.9236662412e+15\\nsamples = 1257\\nvalue = 64781848.271"] ;\n1 -> 2 ;\n3
[label="mse = 3.147813102e+16\\nsamples = 249\\nvalue =
235450289.735"] ;\n1 -> 3 ;\n4 [label="opening_gross <= 70351576.0\\nmse
= 1.10398118716e+17\\nsamples = 159\\nvalue = 601300162.289"] ;\n0 -> 4
[labeldistance=2.5, labelangle=-45, headlabel="False"] ;\n5 [label="mse =
4.06753884592e+16\\nsamples = 92\\nvalue = 440868287.554"] ;\n4 -> 5 ;\n6
[label="mse = 1.22264857987e+17\\nsamples = 67\\nvalue =
821594676.851"] ;\n4 -> 6 ;\n}'
In [12]:
graphviz.Source(treedot)
Out[12]:

Virtudes de los arboles de decision:


 Metodo poderoso y probado
 Interpretable
 No necesita escalar los datos (clasificación), y menos preprocesamiento de
variables

Sin embargo en la practica existen modelos que obtienen mejor rendimiento. Como mejorar el
modelo de arboles de decisión?
Ensembles
Concepto General
Random Forest y Gradient Boosted Trees, forman parte de una familia de algoritmos que se
denominan ensembles.

Cómo funciona el algoritmo Random Forest?


Vamos a generar cientos de modelos de arboles de decisión que serán entrenados
sobre conjuntos de datos bootstrapeados del conjunto de datos original y donde para cada
etapa de separación el conjunto de features elegibles sera un subconjunto aleatorio del
conjunto original de features.
Cada uno de los arboles entrenados luego podrá votar por su predicción y promediaremos
estos votos.
Ensembles del pobre ("Poor man's ensembles")
 Entrenar diversos modelos a mano
 Promediar el resultado
 Owen Zhang, número 1 de Kaggle.com durante un largo tiempo, ocupaba
esta estrategia promediando diversos modelos XGBoost.
 from sklearn.ensemble import VotingClassifier sirve por
ejemplo para hacer un ensemble manual de clasificación

En general los ensembles del pobre funcionan ya que cada uno de los modelos que votarán
en conjunto son bastante fuertes.
Porqué RF es poderoso?
**Leo Breiman** creador del Random Forest demostró que un ensemble podía tener buen
poder de generalización sí:
1. Los submodelos tienen buen poder de predicción
2. Los submodelos están descorrelacionados
Así el algoritmo de Random Forest compromete un poco de poder de predicción de cada uno
de los decision trees que arma, pero la forma aleatoria de generarlos hace que
esten fuertemente descorrelacionados.
In [13]:
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import cross_validate

forest = RandomForestRegressor(200)
results = cross_validate(forest,X,y,cv=5,scoring='r2')
In [14]:
test_scores = results['test_score']
train_scores = results['train_score']
print(np.mean(train_scores))
print(np.mean(test_scores))
0.965239108957
0.514504965042
Mejor resultado que Lasso! Ya no tenemos Bias y tenemos un mejor score r2. Sin embargo
tenemos una diferencia importante entre score de entrenamiento y de test (overfit).
Gradient Boosted Trees
In [15]:
from sklearn.ensemble import GradientBoostingRegressor

ensemble = GradientBoostingRegressor()
results = cross_validate(ensemble,X,y,cv=5,scoring='r2')
In [16]:
test_scores = results['test_score']
train_scores = results['train_score']
print(np.mean(train_scores))
print(np.mean(test_scores))
0.915139214355
0.525193924287
Cómo optimizamos los parametros de este último modelo?
Optimización de hiperparametros
 Fijar un learning rate alto
 Fijar parametros de los arboles
 Fijados estos parametros, elegir el mejor numero de estimadores que
conforman el ensemble
 (Tarea) Con el learning rate dado y el numero de estimadores óptimo,
optimizar los parametros de los arboles
Grid Search
Por ahora dijimos que:
 train_test_split servia para evaluaciones rapidas, testeos y prototipaje
 cross_validate es un método más robusto para poder estimar el rendimiento
de tu algoritmo

Sin embargo una vez que hemos finalizado nuestra etapa de prototipaje y ya queremos
establecer un modelo definitivo deberiamos seguir el flujo siguiente.

In [17]:
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X,y,random_state=1)


In [18]:
from sklearn.model_selection import GridSearchCV

param_test1 = {'n_estimators': range(20,501,20)}


In [20]:
list(param_test1['n_estimators'])
Out[20]:
[20,
40,
60,
80,
100,
120,
140,
160,
180,
200,
220,
240,
260,
280,
300,
320,
340,
360,
380,
400,
420,
440,
460,
480,
500]
In [21]:
estimator = GradientBoostingRegressor(learning_rate=0.1,
min_samples_split=500,
min_samples_leaf=50,
max_depth=8,
max_features='sqrt',
subsample=0.8,
random_state=10)
In [22]:
gsearch1 = GridSearchCV(estimator,
param_grid = param_test1,
scoring='r2',
cv=5)
In [23]:
gsearch1.fit(X_train,y_train)
Out[23]:
GridSearchCV(cv=5, error_score='raise',
estimator=GradientBoostingRegressor(alpha=0.9,
criterion='friedman_mse', init=None,
learning_rate=0.1, loss='ls', max_depth=8,
max_features='sqrt', max_leaf_nodes=None,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=50, min_samples_split=500,
min_weight_fraction_leaf=0.0, n_estimators=100,
presort='auto', random_state=10, subsample=0.8, verbose=0,
warm_start=False),
fit_params=None, iid=True, n_jobs=1,
param_grid={'n_estimators': range(20, 501, 20)},
pre_dispatch='2*n_jobs', refit=True, return_train_score=True,
scoring='r2', verbose=0)
In [24]:
gsearch1.grid_scores_, gsearch1.best_params_, gsearch1.best_score_
/opt/conda/lib/python3.5/site-
packages/sklearn/model_selection/_search.py:747: DeprecationWarning: The
grid_scores_ attribute was deprecated in version 0.18 in favor of the
more elaborate cv_results_ attribute. The grid_scores_ attribute will not
be available from 0.20
DeprecationWarning)
Out[24]:
([mean: 0.65534, std: 0.05764, params: {'n_estimators': 20},
mean: 0.71947, std: 0.06256, params: {'n_estimators': 40},
mean: 0.73472, std: 0.06360, params: {'n_estimators': 60},
mean: 0.73893, std: 0.06236, params: {'n_estimators': 80},
mean: 0.74205, std: 0.06271, params: {'n_estimators': 100},
mean: 0.74593, std: 0.06236, params: {'n_estimators': 120},
mean: 0.74954, std: 0.06335, params: {'n_estimators': 140},
mean: 0.75082, std: 0.06305, params: {'n_estimators': 160},
mean: 0.75257, std: 0.06344, params: {'n_estimators': 180},
mean: 0.75349, std: 0.06447, params: {'n_estimators': 200},
mean: 0.75457, std: 0.06342, params: {'n_estimators': 220},
mean: 0.75531, std: 0.06489, params: {'n_estimators': 240},
mean: 0.75517, std: 0.06572, params: {'n_estimators': 260},
mean: 0.75389, std: 0.06495, params: {'n_estimators': 280},
mean: 0.75460, std: 0.06569, params: {'n_estimators': 300},
mean: 0.75250, std: 0.06545, params: {'n_estimators': 320},
mean: 0.75350, std: 0.06492, params: {'n_estimators': 340},
mean: 0.75354, std: 0.06623, params: {'n_estimators': 360},
mean: 0.75259, std: 0.06542, params: {'n_estimators': 380},
mean: 0.75254, std: 0.06469, params: {'n_estimators': 400},
mean: 0.75186, std: 0.06477, params: {'n_estimators': 420},
mean: 0.75205, std: 0.06508, params: {'n_estimators': 440},
mean: 0.75157, std: 0.06449, params: {'n_estimators': 460},
mean: 0.75051, std: 0.06352, params: {'n_estimators': 480},
mean: 0.75096, std: 0.06327, params: {'n_estimators': 500}],
{'n_estimators': 240},
0.7553059694284987)
In [26]:
final_results = cross_validate(gsearch1.best_estimator_,X_train,y_train)
In [27]:
test_scores = final_results['test_score']
train_scores = final_results['train_score']
print(np.mean(train_scores))
print(np.mean(test_scores))
0.81831693665
0.741387612516
In [28]:
estimator = GradientBoostingRegressor(learning_rate=0.1,
min_samples_split=500,
min_samples_leaf=50,
max_depth=8,
max_features='sqrt',
subsample=0.8,
random_state=10,
n_estimators=240)
In [29]:
estimator.fit(X_train,y_train)
Out[29]:
GradientBoostingRegressor(alpha=0.9, criterion='friedman_mse', init=None,
learning_rate=0.1, loss='ls', max_depth=8,
max_features='sqrt', max_leaf_nodes=None,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=50, min_samples_split=500,
min_weight_fraction_leaf=0.0, n_estimators=240,
presort='auto', random_state=10, subsample=0.8, verbose=0,
warm_start=False)
In [30]:
estimator.score(X_test,y_test)
Out[30]:
0.8092888852563106
Reflexiones de cierre
Recursos
 Reddit /machinelearning y /learnmachinelearning
 Analytics Vidhya y KD Nuggets
 Kaggle.com y "There is no Free Hunch" Blog
 Arxiv, papers
 Libros: "Pattern Recognition and Machine Learning" C.Bishop y "Elements of
Statistical Learning".
Próximos pasos
 Matemáticas
 Praxis: Feature Engineering, Model Selection y Tuning
 Deep Learning para NLP y Computer Vision
 Machine Learning Bayesiano

También podría gustarte