5. Introducció al Machine Learning amb Scikit-Learn
Introducció al Machine Learning amb sklearn¶
Començarem amb una visió general i molt bàsica de com funcionen els models d'aprenentatge automàtic i com s'utilitzen.
Exemple d'arbre de decisió¶
El teu cosí ha guanyat milions de dòlars especulant amb béns arrels. S'ha oferit per convertir-se en soci comercial amb tu pel teu interès per la ciència de dades. Ell proporcionarà els diners i tu oferiràs models que prediuen quant valen les diferents cases.
Li preguntes al teu cosí com ha predit els valors immobiliaris en el passat, i diu que és només una intuïció. Però més preguntes revelen que ha identificat patrons de preus de cases que ha vist en el passat, i els utilitza per fer prediccions per a les cases noves que està considerant.
L'aprenentatge automàtic funciona de la mateixa manera. Començarem amb un model anomenat arbre de decisió (decision tree). Hi ha models més potents que donen prediccions més precises, però els arbres de decisió són fàcils d'entendre i són l'element bàsic d'alguns dels millors models en ciència de dades.
Per simplificar, començarem amb l'arbre de decisions el més senzill possible.

Divideix les cases només en dues categories, segons tinguen dues o més habitacions. El preu previst per a qualsevol casa en consideració és el preu mitjà històric de les cases de la mateixa categoria.
Utilitzem les dades per decidir com dividir les cases en dos grups, i després de nou per determinar el preu previst a cada grup. Aquest pas de captura de patrons a partir de dades s'anomena ajustament o entrenament del model. Les dades utilitzades per ajustar el model s'anomenen dades d'entrenament.
Els detalls de com s'ajusta el model (p. ex., com dividir les dades) són prou complexos i els guardarem per a més endavant. Un cop s'haja ajustat el model, podem aplicar-lo a dades noves per predir els preus d'habitatges addicionals.

L'arbre de decisions de l'esquerra (Arbre de decisions 1) probablement té més sentit, perquè recull la realitat que les cases amb més habitacions solen vendre's a preus més alts que les cases amb menys habitacions. El major inconvenient d'aquest model és que no recull la majoria dels factors que afecten el preu de l'habitatge, com ara el nombre de banys, la mida de l'habitatge, la ubicació, etc.
Podeu capturar més factors utilitzant un arbre que tingui més divisions. Aquests s'anomenen arbres més profunds. Un arbre de decisions que també considera la mida total del solar de cada casa podria semblar així:

Es prediu el preu de qualsevol casa rastrejant l'arbre de decisió, sempre escollint el camí corresponent a les característiques d'aquesta casa. El preu previst per a la casa és a la part inferior de l'arbre. El punt de la part inferior on fem una predicció s'anomena fulla.
Les divisions i els valors de les fulles estaran determinats per les dades, així que és hora que comprovem les dades amb les quals treballareu.
Exploració bàsica de les dades¶
El primer pas en qualsevol projecte d'aprenentatge automàtic és familiaritzar-se amb les dades. Per a això farem servir la biblioteca Pandas, estudiada en apartats anteriors.
Continuant amb l'exemple, veurem dades sobre els preus de les cases a Melbourne, Austràlia. Carreguem i explorem les dades:
import pandas as pd
melbourne_file_path = 'data/sklearn/melb_data.csv'
melbourne_data = pd.read_csv(melbourne_file_path)
melbourne_data.describe()
| Rooms | Price | Distance | Postcode | Bedroom2 | Bathroom | Car | Landsize | BuildingArea | YearBuilt | Lattitude | Longtitude | Propertycount | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| count | 13580.000000 | 1.358000e+04 | 13580.000000 | 13580.000000 | 13580.000000 | 13580.000000 | 13518.000000 | 13580.000000 | 7130.000000 | 8205.000000 | 13580.000000 | 13580.000000 | 13580.000000 |
| mean | 2.937997 | 1.075684e+06 | 10.137776 | 3105.301915 | 2.914728 | 1.534242 | 1.610075 | 558.416127 | 151.967650 | 1964.684217 | -37.809203 | 144.995216 | 7454.417378 |
| std | 0.955748 | 6.393107e+05 | 5.868725 | 90.676964 | 0.965921 | 0.691712 | 0.962634 | 3990.669241 | 541.014538 | 37.273762 | 0.079260 | 0.103916 | 4378.581772 |
| min | 1.000000 | 8.500000e+04 | 0.000000 | 3000.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 1196.000000 | -38.182550 | 144.431810 | 249.000000 |
| 25% | 2.000000 | 6.500000e+05 | 6.100000 | 3044.000000 | 2.000000 | 1.000000 | 1.000000 | 177.000000 | 93.000000 | 1940.000000 | -37.856822 | 144.929600 | 4380.000000 |
| 50% | 3.000000 | 9.030000e+05 | 9.200000 | 3084.000000 | 3.000000 | 1.000000 | 2.000000 | 440.000000 | 126.000000 | 1970.000000 | -37.802355 | 145.000100 | 6555.000000 |
| 75% | 3.000000 | 1.330000e+06 | 13.000000 | 3148.000000 | 3.000000 | 2.000000 | 2.000000 | 651.000000 | 174.000000 | 1999.000000 | -37.756400 | 145.058305 | 10331.000000 |
| max | 10.000000 | 9.000000e+06 | 48.100000 | 3977.000000 | 20.000000 | 8.000000 | 10.000000 | 433014.000000 | 44515.000000 | 2018.000000 | -37.408530 | 145.526350 | 21650.000000 |
Els resultats mostren 8 números per a cada columna del vostre conjunt de dades original. El primer número, el recompte, mostra quantes files tenen valors que no falten.
Els valors que falten sorgeixen per moltes raons. Per exemple, la mida de la segona habitació no es recopilaria quan s'estudia una casa d'una habitació. Tornarem al tema de les dades que falten.
El segon valor és la mitjana, que és la mitjana. Sota això, std és la desviació estàndard, que mesura la dispersió en la distribució numèrica dels valors.
Per interpretar els valors mínim, 25%, 50%, 75% i màxim, imagineu ordenar cada columna del valor més baix al més alt. El primer valor (més petit) és el min. Si passeu un quart de camí a través de la llista, trobareu un nombre que és més gran que el 25% dels valors i inferior al 75% dels valors. Aquest és el valor del 25% (pronunciat "percentil 25"). Els percentils 50 i 75 es defineixen de manera anàloga i el màxim és el nombre més gran.
Selecció de dades per al model¶
El vostre conjunt de dades té massa variables, i fins i tot per imprimir-les bé. Com pots reduir aquesta quantitat aclaparadora de dades a alguna cosa que puguis entendre?
Començarem escollint algunes variables utilitzant la nostra intuïció, encara que existeixen tècniques estadístiques per prioritzar automàticament les variables, com per exemple, eliminar les que són molt dependent entre elles.
Per triar variables/columnes, haurem de veure una llista de totes les columnes del conjunt de dades:
melbourne_data.columns
Index(['Suburb', 'Address', 'Rooms', 'Type', 'Price', 'Method', 'SellerG',
'Date', 'Distance', 'Postcode', 'Bedroom2', 'Bathroom', 'Car',
'Landsize', 'BuildingArea', 'YearBuilt', 'CouncilArea', 'Lattitude',
'Longtitude', 'Regionname', 'Propertycount'],
dtype='object')
Observem també si tenim tots els valors disponibles:
melbourne_data.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 13580 entries, 0 to 13579 Data columns (total 21 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Suburb 13580 non-null object 1 Address 13580 non-null object 2 Rooms 13580 non-null int64 3 Type 13580 non-null object 4 Price 13580 non-null float64 5 Method 13580 non-null object 6 SellerG 13580 non-null object 7 Date 13580 non-null object 8 Distance 13580 non-null float64 9 Postcode 13580 non-null float64 10 Bedroom2 13580 non-null float64 11 Bathroom 13580 non-null float64 12 Car 13518 non-null float64 13 Landsize 13580 non-null float64 14 BuildingArea 7130 non-null float64 15 YearBuilt 8205 non-null float64 16 CouncilArea 12211 non-null object 17 Lattitude 13580 non-null float64 18 Longtitude 13580 non-null float64 19 Regionname 13580 non-null object 20 Propertycount 13580 non-null float64 dtypes: float64(12), int64(1), object(8) memory usage: 2.2+ MB
Per simplicitat, anem a eliminar les dades de les què tenim els valors no disponibles:
melbourne_data = melbourne_data.dropna(axis=0)
melbourne_data.info()
<class 'pandas.core.frame.DataFrame'> Index: 6196 entries, 1 to 12212 Data columns (total 21 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Suburb 6196 non-null object 1 Address 6196 non-null object 2 Rooms 6196 non-null int64 3 Type 6196 non-null object 4 Price 6196 non-null float64 5 Method 6196 non-null object 6 SellerG 6196 non-null object 7 Date 6196 non-null object 8 Distance 6196 non-null float64 9 Postcode 6196 non-null float64 10 Bedroom2 6196 non-null float64 11 Bathroom 6196 non-null float64 12 Car 6196 non-null float64 13 Landsize 6196 non-null float64 14 BuildingArea 6196 non-null float64 15 YearBuilt 6196 non-null float64 16 CouncilArea 6196 non-null object 17 Lattitude 6196 non-null float64 18 Longtitude 6196 non-null float64 19 Regionname 6196 non-null object 20 Propertycount 6196 non-null float64 dtypes: float64(12), int64(1), object(8) memory usage: 1.0+ MB
Hem passat de tindre informació de 13580 a tindre solament 6196. Reiterem que en un cas real, utilitzariem altres tècniques menys agressives per preparar les dades.
Selecció de l'objectiu (target)¶
Utilitzarem la notació de punts per seleccionar la columna que volem predir, en este cas, el preu de l'habitatge, que s'anomena objectiu de predicció o target. Per convenció, l'objectiu de predicció s'anomena y. Per tant, el codi que necessitem per seleccionar i guarder els preus de l'habitatge a les dades de Melbourne és:
y = melbourne_data.Price
Escollint característiques (Features)¶
Les columnes que s'introdueixen al nostre model (i posteriorment s'utilitzen per fer prediccions) s'anomenen característiques. En el nostre cas, aquestes serien les columnes utilitzades per determinar el preu de l'habitatge. De vegades, utilitzareu totes les columnes excepte l'objectiu com a característiques. Altres vegades convindrà reduir el número de característiques per millorar l'eficiència del model.
De moment, construirem un model amb només unes quantes característiques. Més endavant veurem com repetir i comparar models construïts amb diferents característiques.
Seleccionem diverses característiques utilitzant pandas. Per convenció, el conjunt de dades d'entrenament s'anomena X.
melbourne_features = ['Rooms', 'Bathroom', 'Landsize', 'Lattitude', 'Longtitude']
X = melbourne_data[melbourne_features]
Revisem ràpidament les dades que farem servir per predir els preus de l'habitatge.
X.describe()
| Rooms | Bathroom | Landsize | Lattitude | Longtitude | |
|---|---|---|---|---|---|
| count | 6196.000000 | 6196.000000 | 6196.000000 | 6196.000000 | 6196.000000 |
| mean | 2.931407 | 1.576340 | 471.006940 | -37.807904 | 144.990201 |
| std | 0.971079 | 0.711362 | 897.449881 | 0.075850 | 0.099165 |
| min | 1.000000 | 1.000000 | 0.000000 | -38.164920 | 144.542370 |
| 25% | 2.000000 | 1.000000 | 152.000000 | -37.855438 | 144.926198 |
| 50% | 3.000000 | 1.000000 | 373.000000 | -37.802250 | 144.995800 |
| 75% | 4.000000 | 2.000000 | 628.000000 | -37.758200 | 145.052700 |
| max | 8.000000 | 8.000000 | 37000.000000 | -37.457090 | 145.526350 |
X.head()
| Rooms | Bathroom | Landsize | Lattitude | Longtitude | |
|---|---|---|---|---|---|
| 1 | 2 | 1.0 | 156.0 | -37.8079 | 144.9934 |
| 2 | 3 | 2.0 | 134.0 | -37.8093 | 144.9944 |
| 4 | 4 | 1.0 | 120.0 | -37.8072 | 144.9941 |
| 6 | 3 | 2.0 | 245.0 | -37.8024 | 144.9993 |
| 7 | 2 | 1.0 | 256.0 | -37.8060 | 144.9954 |
Comprovar visualment les nostres dades amb aquestes ordres és una part important de la feina d'un científic de dades. Moltes vegades trobareu sorpreses al conjunt de dades que mereixen una inspecció més detallada.
Construeix el teu model¶
Utilitzareu la biblioteca scikit-learn per crear els vostres models. És la llibreria més utilitzada per a tasques de machine learning que proporciona ferramentes per a la classificació, regressió, clustering, reducció de dimensionalitat,..
Els passos per construir i utilitzar un model són:
- Definició: quin tipus de model serà? Un arbre de decisió? Algun altre tipus de model? També s'especifiquen altres paràmetres del tipus de model.
- Entrenament: captura patrons a partir de les dades proporcionades. Aquest és el cor del modelatge.
- Prediccións: pas que utilitza el model per predir el valor de l'objectiu utilitzant noves dades.
- Avaluació: determina la precisió de les prediccions del model.
Aquí teniu un exemple de definició d'un model d'arbre de decisions amb scikit-learn i d'ajustament amb les característiques i la variable objectiu.
from sklearn.tree import DecisionTreeRegressor
import warnings
warnings.filterwarnings('ignore')
# Define model. Specify a number for random_state to ensure same results each run
melbourne_model = DecisionTreeRegressor(random_state=1)
# Fit model
melbourne_model.fit(X, y)
DecisionTreeRegressor(random_state=1)In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
DecisionTreeRegressor(random_state=1)
Molts models d'aprenentatge automàtic permeten una certa aleatorietat en l'entrenament del model. Especificar un número per a random_state garanteix que obtingueu els mateixos resultats a cada execució.
Ara tenim un model ajustat que podem utilitzar per fer prediccions.
A la pràctica, voldrem fer prediccions de les cases noves que ixiran al mercat en lloc de les cases per les quals ja tenim preus. Però farem prediccions per a les primeres files de les dades d'entrenament per veure com funciona la funció de predicció.
print("Predint el valor dels primers 5 habitatges:")
print(melbourne_data.head().Price)
print("Les prediccions són: ")
print(melbourne_model.predict(X.head()))
Predint el valor dels primers 5 habitatges: 1 1035000.0 2 1465000.0 4 1600000.0 6 1876000.0 7 1636000.0 Name: Price, dtype: float64 Les prediccions són: [1035000. 1465000. 1600000. 1876000. 1636000.]
Validació del model¶
Una vegada contruït un model, necessitem determinar si eixe model és vàlid per a fer prediccions amb noves dades que li introduim. En la majoria dels casos, la mètrica rellevant de la qualitat del model és la precisió predictiva (accuracy). Esta mesura ens determina com de exactes seran les prediccions del model.
Compte!!
És un gran error fer prediccions amb les dades d'entrenament i comparar aquestes prediccions amb els valors objectiu de les dades d'entrenament. Pensem com podriem mesurar la qualitat d'un model.
Primer hauriem d'entrenar el model i fer prediccions amb ell. Després comparariem els valors predits i reals de les cases, per exemple de 10.000 cases. És probable que trobem una barreja de bones i males prediccions, però, comparar una llista de 10.000 valors predits i reals seria poc productiu. Hem d'utilitzar algun valor o mètrica que ens indique amb un sol valor com de fiable és el nostre model.
Hi ha moltes mètriques per determinar la qualitat del model, cadascuna d'elles ens aporta informació valiosa. Però començarem amb una anomenada Error absolut mitjà (també anomenat MAE).
L'error de predicció per a cada casa és:
error = valor real - valor predit
Per tant, si una casa costava 150.000 dòlars i vam predir que costaria 100.000 dòlars, l'error és de 50.000 dòlars.
Amb la mètrica MAE, prenem el valor absolut de cada error, per convertir cada error en un nombre positiu. A continuació, calculem la mitjana d'aquests errors absoluts per obtindre el seu valor i ja tenim una mesura de la qualitat del model.
Per calcular aquest error amb sklearn ho podem fer de la següent forma:
from sklearn.metrics import mean_absolute_error
predicted_home_prices = melbourne_model.predict(X)
mean_absolute_error(y, predicted_home_prices)
1115.7467183128902
Açò indica que una predicció se'n va del seu valor real una mitjana de 1115 dòlars. No està gens malament!!
El problema de les mètriques "In-Sample"¶
La mesura que acabem de calcular es pot anomenar una puntuació "In-Sample" (dades que estan en la mostra), ja que hem utilitzat la "mostra" de cases tant per construir el model com per avaluar-lo. Això és un error, com ja haviem comentat.
Imagineu que, en el mercat immobiliari, el color de la porta no està relacionat amb el preu de l'habitatge.
No obstant, a la mostra de dades que utilitzàrem per construir el model, totes les cases amb portes verdes eren molt cares. La feina del model és trobar patrons que prediguen els preus dels habitatges, de manera que veurà aquest patró, i sempre predirà preus alts per a habitatges amb portes verdes.
Com que aquest patró es va deduir de les dades d'entrenament, el model serà molt precís si utilitzem les dades d'entrenament per fer prediccions.
Però si aquesta pressició no es manté quan introduim dades noves al model, el model no seria útil en la realitat.
Compte!!
Com que el valor pràctic dels models prové de fer prediccions sobre dades noves, hem de mesurar el rendiment del model amb dades que no s'han utilitzat per entrenar el model.
La manera més senzilla de fer-ho és dividir les dades de les què disposem en dos blocs, un bloc per a entrenament (dades d'entrenament) i un bloc per a validació (dades de validació).
La biblioteca sklearn té una funció train_test_split per dividir les dades en dos blocs. Utilitzarem algunes d'aquestes dades com a dades d'entrenament per adaptar-se al model i les altres dades les farem servir com a dades de validació per calcular l'error_absolut_mitjana.
from sklearn.model_selection import train_test_split
train_X, val_X, train_y, val_y = train_test_split(X, y, random_state = 0)
melbourne_model = DecisionTreeRegressor()
melbourne_model.fit(train_X, train_y)
val_predictions = melbourne_model.predict(val_X)
print(mean_absolute_error(val_y, val_predictions))
278215.26597805036
Com podeu observar l'error absolut mitjà per a les dades "In-Sample" va ser d'uns 1000 dòlars mentre que per a dades fora de la mostra és de més de 250.000 dòlars.
Aquesta és la diferència entre un model que és quasi exacte i un que no es pot utilitzar per a la majoria de propòsits pràctics.
Però aquest valor per si sol, tampoc ens dóna una visió real de si el model és bo o roïn, ja que l'error és gran o menut depenent del preu dels habitatges. El valor mitjà de l'habitatge a les dades de validació és d'1,1 milions de dòlars, per tant, l'error de les dades noves és aproximadament una quarta part del valor mitjà de l'habitatge, és a dir sobre un 25%.
Hi ha moltes maneres de millorar aquest model, com ara experimentar per trobar millors característiques o canviar l'algorisme del model.
Altres mètriques segons el model¶
A banda de l'error quadràtic mitjà, hi ha més mètriques que es poden utilitzar per validar o descartar el model. No entrarem en detall, ja les veureu més en profunditat en Models de IA. Les principals, segons el tipus de problema (classificació, regressió, agrupament, etc.) són les segïuents:
Classificació:
- Precisió (Accuracy): prediccions correctes respecte al total de prediccions.
- Recall (Sensibilitat o True Positive Rate): mesura la proporció de True positives (mostres positives que s'han predit correctament) respecte al total de positives reals. És útil quan és crucial identificar tots els casos positius, per exemple, diagnòstics d'enfermetats greus.
- Precisió (Precision): proporció de True positives respecte al total de prediccions positives. És important quan és important minimitzar els falsos positius, per exemple, diagnòstics d'enfermetats greus.
- F1 Score: L'F1 Score és una mitjana de precisió i recall. Proporciona un equilibri entre aquestes dues mètriques i és útil quan hi ha un desequilibri entre les classes (True positives, True negatives, False positives, False negative).
- Matriu de Confusió: Una taula que mostra les relacions entre les prediccions del model i les classes reals (True positives, True negatives, False positives, False negative).
Regressió:
- Error Quadràtic Mitjà (Mean Squared Error - MSE): Mesura la mitjana dels quadrats de les diferències entre les prediccions del model i els valors reals.
- Error Absolut Mitjà (Mean Absolute Error - MAE): Mesura la mitjana de les diferències absolutes entre les prediccions i els valors reals.
- Coeficient de Determinació (R-squared): Proporciona una mesura de com de bé s'ajusta el model a les punts de dades. El valor pot oscil·lar entre 0 i 1.
Agrupament:
- Índex de Silueta: Mesura la similitud dels objectes en el mateix clúster (cohesió) i la diferència entre els clústers (separació).
- Homogeneïtat, Completitud i V-Measure: Són mètriques que es poden utilitzar per avaluar la qualitat d'un agrupament.
- Índex d'Adjusted Rand (ARI): Mesura la similitud entre dues agrupacions, ajustada al fet que els agrupaments aleatoris podrien obtenir un valor alt.
Subajust i sobreajust del model (underfitting i overfitting)¶
Ara que coneixem una manera fiable de mesurar la precisió del model, podem experimentar amb models alternatius i veure quins ofereixen les millors prediccions. Però quines alternatives tenim per als models?
Podem veure a la documentació de scikit-learn que el model d'arbre de decisions té moltes opcions (més de les que necessitarem). Les opcions més importants determinen la profunditat de l'arbre. Recordem que la profunditat d'un arbre és una mesura de quantes divisions fa abans d'arribar a una predicció.
A la pràctica, no és estrany que un arbre tinga 10 divisions entre el nivell superior (totes les cases) i una fulla. A mesura que l'arbre s'enfonsa, el conjunt de dades es ramifica en rames amb menys cases. Si un arbre només tenia 1 divisió, divideix les dades en 2 grups. Si cada grup es torna a dividir, obtindríem 4 grups de cases. Dividir cadascun d'ells de nou crearia 8 grups. Si seguim duplicant el nombre de grups afegint més divisions a cada nivell. Quan arribem al nivell 10, tindriem 2^10 = 1024 fulles.
Quan dividim les cases entre moltes fulles, també tenim menys cases a cada fulla. Les fulles amb molt poques cases faran prediccions molt pròximes als valors reals d'aquestes cases (amb les dades d'entrenament), però poden fer prediccions molt poc fiables per a dades noves (perquè cada predicció es basa només en unes poques cases).
Es tracta d'un fenomen anomenat sobreajust o overfitting, on un model coincideix amb les dades d'entrenament quasi perfectament, però funciona malament en la validació i altres dades noves. D'altra banda, si fem que el nostre arbre siga molt poc profund, no divideix les cases en grups molt diferenciats.
En un extrem, si un arbre divideix les cases en només 2 o 4 grups, cada grup encara té una gran varietat de cases. Les prediccions resultants poden estar lluny per a la majoria de cases, fins i tot per a les dades d'entrenament (i també serà roïn en la validació pel mateix motiu). Quan un model no aconsegueix capturar distincions i patrons importants a les dades, de manera que funciona mal fins i tot en les dades d'entrenament, això s'anomena subajust o underfitting.
Com que ens importa la precisió de les dades noves, que estimem a partir de les nostres dades de validació, volem trobar el punt òptim entre l'ajustament insuficient i el sobreajust. Visualment, volem el punt baix de la corba de validació (roja) a la figura següent:

Tots els algorismes de ML tenen formes de controlar el overfitting i el underfitting.