Curso de Machine Learning Aplicado Con Scikit
Curso de Machine Learning Aplicado Con Scikit
Curso de Machine Learning Aplicado Con Scikit
learn
Un poco de terminología de ML
El ciclo de trabajo del Machine Learning
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
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
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
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
/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:
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
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:
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])
/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):
<ipython-input-68-27d06730cdf2> in <lambda>(x)
----> 1 pd.Series(X.index).apply(lambda x: inv_map.loc[x])
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
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]);
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
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:
Como podemos ver no existe un separador óptimo. Debemos para resolver el problema
buscar un modelo aún más poderoso? No necesariamente.
sns.heatmap(X.corr())
Out[6]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f4ff97f7198>
La maldición de la dimensión
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?
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
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
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
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.
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 [ ]:
scaler = StandardScaler()
scaler.fit(X_train)
In [ ]:
scaler.mean_
In [ ]:
scaler.scale_
In [ ]:
X.values
In [ ]:
scaler.transform(X_train)
In [ ]:
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í.
In [ ]:
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 [ ]:
transformer = PolynomialFeatures(2)
transformer.fit_transform(A)
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
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]:
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]:
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]:
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.
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
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
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
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
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]:
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.
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