Introducción Al Curso de Machine Learning Aplicado Con Python
Introducción Al Curso de Machine Learning Aplicado Con Python
Introducción Al Curso de Machine Learning Aplicado Con Python
https://platzi.com/clases/1178-scikit/8822-introduccion-al-curso-de-machine-learning-aplica-6/
¿Cuál es la definición de éxito en una predicción? Establecer una métrica de rendimiento (calificación).
Ejemplo, evaluar la precisión de una predicción.
¿Con qué datos se contaría para hacer esa predicción? Establecer con claridad con que datos contamos y
cuales necesitamos.
¿La pregunta que se está tratando de resolver pertenece a alguna disciplina en particular?
Considerando nuestra intuición en la disciplina ¿Los datos nos permiten predecir el objetivo? Entre más
conozcamos la disciplina o el negocio (modelo del dominio) mejor resultado dará el modelo de ML que
diseñemos para resolver el problema (pregunta).
Problemas clásicos de Machine Learning: -Predecir métrica -Predecir etiqueta (clasificar) -Agrupar
elementos similares -Optimizar con ensayo error
https://platzi.com/clases/1178-scikit/8824-predecir-el-ingreso-de-peliculas-de-im-2/
https://www.youtube.com/watch?v=_OcLeySukXA&feature=youtu.be
CONTEXTO ejemplo:
Somos un ente gubernamental que quiere definir sus políticas de financiamiento de producciones
cinematográficas nacionales
1- Ayudar a la producción de películas de calidad que no logran ser autosustentables
2- Nos sería útil saber que películas tiene mas dificultad para recuperar en sus presupuestos. Por
3- consiguiente, queremos predecir una métrica: el ingreso mundial generado por una película.
ATERRIZA TU PROBLEMA DE APRENDIZAJE SUPERVISADO
Los ingresos de una película corresponden a valores continuos
Mi éxito será “que tan cerca estoy del valor real de ingreso generado por la película “
Me basare en bases de datos públicas de internet
El dominio de trabajo es la industria de cine, en particular de la distribución de películas
Si de forma general existen bastantes características que me pueden ayudar a saber que película
será exitosa como: calidad, actores, presupuesto ect--
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.
https://platzi.com/clases/1178-scikit/8825-terminologia-de-machine-learni-7/
Terminología
Datos tabulares = Datos en dos dimensiones.
Líneas = Ejemplos
Columna = Feature. Éstas son importantes porque nos van a ayudar a predecir cosas gracias a los modelos
que usemos de Machine Learning.
Cantidad de columnas = Dimensión de los datos
Output de un algoritmo de Machine Learning (ML) = Modelo
Variable objetivo = Target
Ejemplo
Linea = ejemplo (Película)
Columna = Feature (nos ayudan a precedir cosas gracias a los modelos de ML) (Características de cada
película)
**Cantidad de columnas **= dimensión de datos
Variable objetivo = target (Lo que se quiere predecir) (Ingreso de cada película)
Output de un algoritmo de ML = Modelo
En este material te comparto los notebooks de Jupyter utilizados por el profesor durante el curso, recuerda
que lo ideal es que tú mismo desarrolles estos ejercicios, pero este material te servirá como apoyo y punto de
comparación en caso de que te encuentres con alguna dificultad en el camino.
https://github.com/JuanPabloMF/machine-learning-platzi/tree/master
Espero que sigas disfrutando este curso y no olvides al final tomar el examen y obtener tu certificación.
¡Mucho éxito
5.1- Este repositorio contiene los notebooks del curso "Machine Learning Aplicado con Python" que dicté
en platzi.
El objetivo de este curso es entregar los skills prácticos necesarios para implementar algoritmos de ML en
un contexto profesional.
El curso incluye:
Introducción a Numpy, para manejo de algebra lineal.
Introducción a Pandas, para manejo de los datos en un formato de DataFrames (tablas).
Docker files para setup de ambientes limpios y poderosos de trabajo de Machine Learning.
Estudio completo del ciclo de ingeniería del Machine Learning.
o Preparación de datos: Cleaning, Imputation, Merging.
o Feature Engineering: One-hot encode, Scaling, Feature Design
o Entrenamiento de modelos: Sklearn API (train_test_split, fit, predict, score)
o Evaluación de modelos: sklearn.model_selection, Cross Validation, Grid Search.
Algoritmos de Machine Learning: Regresión Lineal, Regresión Lasso, KNN, Random Forest, Gradient
Boosting Trees.
El curso sigue un flujo de resolución real de un problema de predicción de ingreso de peliculas con la base de
datos de IMDB con 1000+ ejemplos de entrenamiento.
https://platzi.com/clases/1178-scikit/8828-iteraciones-y-la-navaja-de-occ-8/
Una vez conectado, el código que ingresaste se ejecutara, y veras que efectivamente los imports se harán sin
ningún problema por lo que ya tienes todo lo que necesitas para trabajar!
Un solo punto adicional que queda por aclarar es que como estas trabajando en la nube no tienes
directamente los archivos de la clase a mano para poder leerlos desde el notebook.
Para poder acceder los archivos del curso puedes hacer lo siguiente:
1. Encuentra el link hacia el archivo que quieres cargar en el repositorio de
github https://github.com/JuanPabloMF/datasets-platzi-course
2. Con el link del archivo csv puedes llamar la función de pandas read_csv de la siguiente manera:
import pandas as pd
pd.read_csv(url)
Ya puedes entrar de llenos al curso y empezar a implementar tus primeros modelos de machine
learning!
Otras opciones
Anaconda
Para instalar Anaconda debes:
Ir a https://www.anaconda.com/distribution/
Elige tu sistema operativo: Windows/Linux/macOS
Descarga el instalador gráfico para la arquitectura que corresponda a la CPU de tu computadora
(32 bits o 64 bits)
Cuando hayas descargado el instalador gráfico y lo hayas abierto se te solicitaran diversas confirmaciones,
puedes tomar las opciones por defecto.
Anaconda quedara luego de estos pasos instalado dentro de tus aplicaciones.
Abre Anaconda y en la home tendras Jupyter disponible. Abrelo con botón Launch.
El ambiente por defecto en el que Anaconda te hara trabajar se llama “base (root)” y ya contiene las
librerías esenciales de Pydata.
Crea un nuevo notebook de python 3 y estas listo para trabajar!
Docker
Te recomiendo usar Docker solo si ya tomaste alguno de los cursos de Platzi que te ensenan a usarlo, o si ya
tienes experiencia con esta herramienta.
1. Primero instala Docker en tu computador
Ve a https://www.docker.com/products/docker-desktop y haz click en descargar para tu OS.
Dale click a descargar. Esto descargara un archivo (en el caso de windows .exe) que es el instalador y pesa
914 MB.
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 #LIMPIA EL TIPO DE ARRAY
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) #la distancia entre numeros es el segundo # menos la entrada o sea 0
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')
9- ARRAYS EN NUMPY
https://platzi.com/clases/1178-scikit/8832-fundamentos-de-python-cientifico-2-num-0/
https://medium.com/@steve7an/how-to-test-jupyter-notebook-from-github-via-google-colab-7dc4b9b11a19
Funtion eye ()
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]) # DE UNA DIMENSION
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) # ESTO NO DICE QUE UNA ARRAYS ES IGUAL
Out[21]: False
In [23]:
# Reshaping
new_dims = (1,a1D.shape[0]) #TUPLA a1D.shape[0]) = (1,2,3) LONGITUD
a = a1D.reshape(new_dims)
In [25]:
np.array_equal(a,a2D)
Out[25]: True
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] # primer elemento son las líneas (2) y el Segundo elemento son las columnas (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] # acceder a los 5 primeros
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[:,:] #cuando quiero acceder a todos los elementos
Out[38]: array([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.]])
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)
RTA:
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.subtrac
-
t
np.multipl
*
y
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
RTA:
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
/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
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])
https://platzi.com/clases/1178-scikit/8835-cargar-los-dat-9/
5.7- PREPARACIÓN DE DATOS.IPYNB
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('../desktop/datasets/peliculas.csv',encoding='utf-8')
In [4]:
type(movies)
Out[4]:
pandas.core.frame.DataFrame
In [5]:
movies.head()
Out[5]:
d la c
m tit c as du con dir act act act im
u n o cast_t
ov le o pe ra ten ect or_ or_ or_ bu db
r g u plot_keywo otal_fa gr
ie_ _y l ct_ tio genres t_ra or_ 1_n 2_n 3_n dg _sc
at u n rds ceboo oss
tit ea o rat n. tin na am am am et or
io a tr k_likes
le r r io 1 g me e e e e
n ge y
C Action| avatar| Jam CC Joel 23 76
1 We
Av 20 o En U 17 Adventu future| es H Dav 70 05
1.7 7 PG- s
0 at 09 l gli S 8. re| marine| Ca Pou id 4834 00 7.9 05
8 8. 13 Stu
ar .0 o sh A 0 Fantasy native| mer nde Mo 00 84
0 di
r |Sci-Fi paraplegic on r ore 0.0 7.0
1Pir 20 C 2.3 1 En U 16 Action| PG- goddess| Gor Joh Orl Jac 48350 30 7.1 30
at 07 o 5 6 gli S 9. Adventu 13 marriage e nny and k 00 94
es .0 l 9. sh A 0 re| ceremony| Ver Dep o Dav 00 04
of o 0 Fantasy marriage bins p Blo enp 00 15
th r proposal| ki om ort 0.0 2.0
e pi...
Ca
rib
be
an
:
At
W
orl
d la c
m tit c as du con dir act act act im
u n o cast_t
ov le o pe ra ten ect or_ or_ or_ bu db
r g u plot_keywo otal_fa gr
ie_ _y l ct_ tio genres t_ra or_ 1_n 2_n 3_n dg _sc
at u n rds ceboo oss
tit ea o rat n. tin na am am am et or
io a tr k_likes
le r r io 1 g me e e e e
n ge y
d's
En
d
Ste
C Sa Chr Ror 24 20
1 Action| bomb| pha
Sp 20 o En 14 m isto y 50 00
2.3 4 U Adventu PG- espionage| nie
2 ect 15 l gli 8. Me ph Kin 11700 00 6.8 74
5 8. K re| 13 sequel|spy| Sig
re .0 o sh 0 nde Wa nea 00 17
0 Thriller terrorist ma
r s ltz r 0.0 5.0
n
Th
e Jose
Chr
Da C deception| Chr ph 25 44
1 isto To
rk 20 o En U 16 imprisonme isti Gor 00 81
2.3 6 Action| PG- phe m 10675
3 Kn 12 l gli S 4. nt| an don 00 8.5 30
5 4. Thriller 13 r Har 9
ig .0 o sh A 0 lawlessness Bal - 00 64
0 Nol dy
ht r |police offi... e Lev 0.0 2.0
an
Ris itt
es
St
ar
W
ar
s:
Ep
iso
de
VII Dou Do
N N N N N Rob
- Na Na Docume Na g ug Na Na Na
4 a a a a a NaN Wa 143 7.1
Th N N ntary N Wal Wa N N N
N N N N N lker
e ker lker
Fo
rc
e
A
wa
ke
ns
...
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
https://platzi.com/clases/1178-scikit/8836-inspeccion-de-los-tipos-de-datos/
Inspección de los tipos de datos
Datos importantes:
La inspección de los datos se da para tener conocimiento de la salud de los datos que tenemos,
saber si vienen limpios o no, y también porque se quiere tener un entendimiento cuantitativo de ellos.
Parte de esto es mirar gráficos estadísticos y entender diferentes propiedades numéricas de las
columnas.
A diferencia de Numpy, Pandas no solo permite cargar datos numéricos, sino también datos de
texto.
El método info nos va a mostrar la cantidad completa de columnas con la cantidad de elementos no
nulos que hay en esas columnas, y por último muestra el tipo de cada columna.
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]:
title_yea aspect_r duration cast_total_faceboo imdb_sc
duration budget gross
r atio .1 k_likes ore
cou 4935.000 4714.000 5028.000 5028.000 4.551000e 5043.000 4.159000e
5043.000000
nt 000 000 000 000 +03 000 +03
me 2002.470 107.2010 107.2010 3.975262e 4.846841e
2.220403 9699.063851 6.442138
an 517 74 74 +07 +07
12.47459 25.19744 25.19744 2.061149e 6.845299e
std 1.385113 18163.799124 1.125116
9 1 1 +08 +07
1916.000 2.180000e 1.620000e
min 1.180000 7.000000 7.000000 0.000000 1.600000
000 +02 +02
25 1999.000 93.00000 93.00000 6.000000e 5.340988e
1.850000 1411.000000 5.800000
% 000 0 0 +06 +06
50 2005.000 103.0000 103.0000 2.000000e 2.551750e
2.350000 3090.000000 6.600000
% 000 00 00 +07 +07
75 2011.000 118.0000 118.0000 4.500000e 6.230944e
2.350000 13756.500000 7.200000
% 000 00 00 +07 +07
ma 2016.000 16.00000 511.0000 511.0000 1.221550e 7.605058e
656730.000000 9.500000
x 000 0 00 00 +10 +08
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]:
d c
m tit c as du con dir act act act cast_t im
u la o
ov le o pe ra ten ect or_ or_ or_ otal_f bu db gr
r ng u plot_key
ie_ _y l ct_ tio genres t_ra or_ 1_n 2_n 3_n acebo dg _sc os
at ua n words
tit ea o rat n. tin na am am am ok_lik et or s
io ge tr
le r r io 1 g me e e e es e
n y
Pri
anime| Jad
nc
C cult Hay a 2.4 22
2 ess 1 Ja Ja Min Bill
19 o 13 Adventure| film| ao Pin 00 98
3 M 1.8 3 pa p PG- nie y
97 l 4. Animation forest| Miy ket 2710 00 8.4 19
2 on 5 4. ne a 13 Dri Cru
.0 o 0 |Fantasy princess aza t 0e+ 1.
3 on 0 se n ver dup
r |studio ki Smi 09 0
ok
ghibli th
e
2 St 20 C 1.8 1 Ja Ja 10 Action| PG- 19th Kat Wil Rob Ros 991 2.1 6.9 41
3 ea 04 o 5 0 pa p 3. Adventure| 13 century| suhi lia in alin 27 03
3 m .0 l 3. ne a 0 Animation ball| ro m Atk d 52 88
4 bo o 0 se n |Family| boy| Ôto Ho in Ayr 0e+ .0
y r Sci-Fi| inventor mo otki Do es 09
Thriller |steam ns wn
d c
m tit c as du con dir act act act cast_t im
u la o
ov le o pe ra ten ect or_ or_ or_ otal_f bu db gr
r ng u plot_key
ie_ _y l ct_ tio genres t_ra or_ 1_n 2_n 3_n acebo dg _sc os
at ua n words
tit ea o rat n. tin na am am am ok_lik et or s
io ge tr
le r r io 1 g me e e e es e
n y
es
S
o daughte
C Joo Ka 1.2 22
2 Th 1 ut Comedy| r|han Ah-
20 o Ko 11 n- Do ng- 21 01
9 e 1.8 1 h Drama| river| sun
06 l re 0. R ho ona ho 1173 55 7.0 41
8 Ho 5 0. K Horror| monster g
.0 o an 0 Bon Bae Son 0e+ 2.
8 st 0 or Sci-Fi |river| Ko
r g g 10 0
e seoul
a
H
C H bus| Ma Pét 2.5
3 1 u Laj Bál 19
Fa 20 o un 13 Drama| death| rcel er 00
0 2.3 3 n os int 58
tel 05 l ga 4. Romance| R gay slur| l Fan 11 00 7.1
0 5 4. g Kolt Pén 88
ess .0 o ri 0 War hatred| Na csik 0e+
5 0 a ai tek .0
r an jewish gy ai 09
ry
based on
C manga| Kat Tak 1.1
3 1 Ja Ja Mit Tes 43
19 o 12 Action| biker suhi esh 00
4 Ak 1.8 2 pa p suo shô 91
88 l 4. Animation R gang| ro i 28 00 8.1
2 ira 5 4. ne a Iwa Gen 62
.0 o 0 |Sci-Fi gifted Ôto Kus 0e+
3 0 se n ta da .0
r child| mo ao 09
post th...
S cake|
La
o christia Cha Hye
dy C 4.2
3 1 ut n| n- Min Yeo - 21
Ve 20 o Ko 11 00
8 2.3 1 h Crime| lesbian wo -sik ng- jeo 16
ng 05 l re 2. R 907 00 7.7
5 5 2. K Drama sex|oral ok Cho ae ng 67
ea .0 o an 0 0e+
9 0 or sex| Par i Lee Ka .0
nc r 09
e pregnan k ng
e
a t s...
13- INSPECCIÓN CUANTITATIVA Y DE SALUD DE LOS DATOS
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
Out[41]:
5043 rows × 8 columns
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)
Out[48]:
movi producti worldwi title aspec dur dura bu imdb gr openin scr
cast_total_fa
e_titl on_budge de_gros _yea t_rati atio tion. dg _scor os g_gros een
cebook_likes
e t s r o n 1 et e s s s
Fa
33 67 216
ls NaN NaN NaN 27 274 13 13 NaN NaN 2106
5 1 4
e
Tr 4385. 435 437 40 4385. 37 222
4385.0 4385.0 4111 4372 4385.0 2279
ue 0 8 2 50 0 14 1
In [49]:
(movies_v2 != 0).apply(pd.Series.value_counts)
Out[49]:
movi producti worldwi title aspec dur dura bu imdb gr openin scr
cast_total_fa
e_titl on_budg de_gros _yea t_rati atio tion. dg _scor os g_gros een
cebook_likes
e et s r o n 1 et e s s s
Fa
Na Na Na
ls NaN NaN 281 NaN NaN NaN NaN 27 NaN NaN
N N N
e
43 43
Tr 4385. 438 4385. 438 4385. 4385. 438
4385.0 4104 4358 85. 85. 4385.0
ue 0 5.0 0 5.0 0 0 5.0
0 0
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()
Out[58]:
production worldwid title_ aspect_ durati cast_total_face imdb_ opening scre
budget
_budget e_gross year ratio on.1 book_likes score _gross ens
27839189 2009. 237000 7702548 345
0 425000000 1.78 178.0 4834 7.9
82 0 000.0 1.0 2.0
20586622
1 306000000 NaN NaN NaN 143 NaN 7.1 NaN NaN
25
96342042 2007. 300000 1398021 436
2 300000000 2.35 169.0 48350 7.1
5 0 000.0 90.0 2.0
87962092 2015. 245000 7040314 392
3 300000000 2.35 148.0 11700 6.8
3 0 000.0 8.0 9.0
10844390 2012. 250000 1608872 440
4 275000000 2.35 164.0 106759 8.5
99 0 000.0 95.0 4.0
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()
Out[63]:
production worldwid title_ aspect_ durati cast_total_face imdb_ opening scre
budget
_budget e_gross year ratio on.1 book_likes score _gross ens
425000000. 2.783919e 2009. 237000 7702548 345
0 1.78 178.0 4834.0 7.9
0 +09 0 000.0 1.0 2.0
300000000. 9.634204e 2007. 300000 1398021 436
2 2.35 169.0 48350.0 7.1
0 +08 0 000.0 90.0 2.0
production worldwid title_ aspect_ durati cast_total_face imdb_ opening scre
budget
_budget e_gross year ratio on.1 book_likes score _gross ens
300000000. 8.796209e 2015. 245000 7040314 392
3 2.35 148.0 11700.0 6.8
0 +08 0 000.0 8.0 9.0
275000000. 1.084439e 2012. 250000 1608872 440
4 2.35 164.0 106759.0 8.5
0 +09 0 000.0 95.0 4.0
275000000. 2.600021e 2013. 215000 2921084 390
5 2.35 150.0 45757.0 6.5
0 +08 0 000.0 9.0 4.0
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])
<ipython-input-68-27d06730cdf2> in <lambda>(x)
----> 1 pd.Series(X.index).apply(lambda x: inv_map.loc[x])
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]);
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:
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.
sns.heatmap(X.corr())
Out[6]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f4ff97f7198>
La maldición de la dimensión
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?
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.
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>
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
5.11- CREACIÓN Y TRANSFORMACIÓN DE FEATURES.IPYNB
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)
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]:
gener
pais
o
hombr
0 Chile
e
1 Colombia mujer
hombr
2 Colombia
e
Venezuel
3 mujer
a
In [30]:
pd.get_dummies(d)
Out[30]:
pais_Chil pais_Colombi pais_Venezuel genero_hombr genero_muje
e a a e r
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('Unnamed: 0')
In [36]:
categoricals.head(2)
Out[36]:
actor_1_nam director_nam
e e
Unnamed:
0
James
0 CCH Pounder
Cameron
1 Doug Walker Doug 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]:
production_ title_yea aspect_r duratio cast_total_faceb imdb_s actor_1_ director_
budget
budget r atio n.1 ook_likes core name name
425000000. 2.00900 1.78000 1.78000 2.37000 CCH James
0 4834.0 7.9
0 0e+03 0e+00 0e+02 0e+08 Pounder Cameron
306000000. 5.91165 5.91165 5.91165 5.91165 Doug Doug
1 143.0 7.1
0 6e+08 6e+08 6e+08 6e+08 Walker Walker
300000000. 2.00700 2.35000 1.69000 3.00000 Johnny Gore
2 48350.0 7.1
0 0e+03 0e+00 0e+02 0e+08 Depp Verbinski
300000000. 2.01500 2.35000 1.48000 2.45000 Christop Sam
3 11700.0 6.8
0 0e+03 0e+00 0e+02 0e+08 h Waltz Mendes
275000000. 2.01200 2.35000 1.64000 2.50000 Tom Christoph
4 106759.0 8.5
0 0e+03 0e+00 0e+02 0e+08 Hardy er Nolan
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]:
Unnamed: opening_gros screen
movie_title
0 s s
0 0 10 Days in a Madhouse 2451.0 10.0
10 Things I Hate About
1 1 8330681.0 2271.0
You
2 2 102 Dalmatians 19883351.0 2704.0
Unnamed: opening_gros screen
movie_title
0 s s
3 3 12 Rounds 5329240.0 2331.0
4 4 12 Years a Slave 923715.0 19.0
Puedes mejorar considerablemente nuestra predicción?
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
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>]
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]:
Cada uno de los arboles entrenados luego podrá votar por su predicción y promediaremos estos votos.
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.
<img src="../vol/img/grid_search_crossval.png" width=700>
In [17]:
from sklearn.model_selection import train_test_split