5. Modelado de datos#

5.1. Introducción#

Ya hemos visto algunas técnicas cualitativas. Veamos brevemente un resumen de las técnicas cuantitativas que podemos utilizar para entender los datos:


Tomado de: Choosing a good chart.

Si bien, las técnicas revisadas nos dan un importante entendimiento de los datos, no son suficientes para poder realizar un análisis más profundo. Para ello, es necesario realizar un proceso de modelado. El modelado de datos es un proceso de análisis de datos que busca descubrir patrones y relaciones entre variables. El modelado de datos es una parte fundamental del análisis de datos y es la base para la construcción de modelos de aprendizaje automático (machine learning).

Primero, entendamos en que campo del conocimiento se encuentra el modelado de datos. El modelado de datos es un proceso que se encuentra en el campo de la estadística. La estadística es una rama de las matemáticas que se encarga de recolectar, organizar, analizar e interpretar datos. Sin embargo, en épocas más recientes se ha desarrollado un campo de conocimiento que se encarga de realizar análisis de datos a gran escala. Este campo de conocimiento es el análisis de datos (data analytics). El cual es un proceso que se encarga de recolectar, organizar, analizar e interpretar datos a gran escala. El análisis de datos es un proceso que se encuentra en el campo de la ciencia de datos (data science). La ciencia de datos es un campo de conocimiento que se encarga de recolectar, organizar, analizar e interpretar datos a gran escala utilizando técnicas de estadística, matemáticas, programación y visualización de datos.


Tomado de: Medium.

¿Qué es un modelo?

Un modelo es una forma de representar la realidad. También se suele decir que un modelo es una abstracción de la realidad, una representación simplificada de la realidad o una representación de la realidad que nos permite entenderla mejor y predecir lo que pasará.


Algunos ejemplos de modelos.#

Uno de los modelos más simples que podemos encontrar es el del tiro parabólico:


Si ponemos algunas de estas variables en un modelo matemático, obtenemos la siguiente ecuación:

\[y = ax^2 + bx + c\]
  • Donde \(y\) es la altura, \(x\) es la distancia y \(a\), \(b\) y \(c\) son constantes.

  • En éste caso, tanto \(x\) como \(y\) se les conoce como variables y \(a\), \(b\) y \(c\) como parámetros.

  • Éste tipo de modelos se los conoce como modelos matemáticos.

Por otro lado, tenemos modelos estocásticos o estadísticos. Un clásico ejemplo es el modelo de regresión lineal.

Datos: https://www.kaggle.com/competitions/house-prices-advanced-regression-techniques/data
(Por ahora no nos preocupemos por el código)

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

from scipy import stats
from sklearn.preprocessing import LabelEncoder

sns.set()
# leer datos
df = pd.read_csv('https://raw.githubusercontent.com/alejo-acosta/pmdb-material/master/data/house-train.csv')

# variables categóricas y numéricas
cat_vars = [i for i in df.columns if i not in df._get_numeric_data().columns]
num_vars = [i for i in df.columns if i not in cat_vars]

# eliminar outliers
lista_variables_outliers = ['SalePrice', 'OverallQual', 'GrLivArea', 'GarageCars', 'GarageArea', 'TotalBsmtSF',]
df = df[(np.abs(stats.zscore(df[lista_variables_outliers])) < 3).all(axis=1)]
df.shape
(1420, 81)
df.corr(numeric_only=True)
Id MSSubClass LotFrontage LotArea OverallQual OverallCond YearBuilt YearRemodAdd MasVnrArea BsmtFinSF1 ... WoodDeckSF OpenPorchSF EnclosedPorch 3SsnPorch ScreenPorch PoolArea MiscVal MoSold YrSold SalePrice
Id 1.000000 0.009621 -0.021551 -0.038818 -0.029113 0.012741 -0.017785 -0.020428 -0.060695 -0.017975 ... -0.040320 -0.006093 0.013044 -0.047429 0.008419 0.058125 -0.007117 0.026235 0.001594 -0.028339
MSSubClass 0.009621 1.000000 -0.416096 -0.149659 0.047990 -0.070054 0.042037 0.045069 0.039232 -0.067868 ... -0.014463 -0.002367 -0.013658 -0.044716 -0.028726 0.003860 -0.007569 -0.011168 -0.016375 -0.083061
LotFrontage -0.021551 -0.416096 1.000000 0.388814 0.200827 -0.047492 0.114217 0.068135 0.145392 0.119650 ... 0.073115 0.107991 -0.009496 0.080022 0.045194 0.019435 0.003201 0.030580 0.012295 0.359398
LotArea -0.038818 -0.149659 0.388814 1.000000 0.068681 0.001046 0.002335 -0.003509 0.052459 0.159139 ... 0.152759 0.057198 -0.021991 0.023672 0.031435 0.021404 0.040562 0.012069 -0.011880 0.258683
OverallQual -0.029113 0.047990 0.200827 0.068681 1.000000 -0.109772 0.580568 0.540272 0.352730 0.172550 ... 0.220549 0.279620 -0.126313 0.038104 0.052519 0.006848 -0.027982 0.078137 -0.023864 0.799280
OverallCond 0.012741 -0.070054 -0.047492 0.001046 -0.109772 1.000000 -0.374825 0.072095 -0.130476 -0.023991 ... -0.002377 -0.033548 0.082156 0.024903 0.042494 0.023986 0.070653 -0.010055 0.049796 -0.087776
YearBuilt -0.017785 0.042037 0.114217 0.002335 0.580568 -0.374825 1.000000 0.592912 0.299861 0.229749 ... 0.219863 0.178678 -0.397671 0.033396 -0.044684 0.003906 -0.033263 0.010397 -0.020457 0.573975
YearRemodAdd -0.020428 0.045069 0.068135 -0.003509 0.540272 0.072095 0.592912 1.000000 0.150106 0.101205 ... 0.199823 0.213640 -0.200636 0.047964 -0.045501 -0.012309 -0.007571 0.022569 0.036678 0.536000
MasVnrArea -0.060695 0.039232 0.145392 0.052459 0.352730 -0.130476 0.299861 0.150106 1.000000 0.209497 ... 0.129064 0.101776 -0.105213 0.027028 0.073498 -0.009980 -0.028369 0.008098 -0.011092 0.411393
BsmtFinSF1 -0.017975 -0.067868 0.119650 0.159139 0.172550 -0.023991 0.229749 0.101205 0.209497 1.000000 ... 0.188428 0.055745 -0.117118 0.034551 0.077734 0.004319 0.008649 0.007750 0.014777 0.361936
BsmtFinSF2 -0.002119 -0.064314 0.054036 0.119265 -0.062201 0.041951 -0.051028 -0.068865 -0.070000 -0.055476 ... 0.079780 0.010126 0.032677 -0.030548 0.087752 0.048532 0.004949 -0.017885 0.029258 -0.004782
BsmtUnfSF -0.004376 -0.140139 0.132860 -0.006170 0.298336 -0.150174 0.147230 0.172410 0.088732 -0.556108 ... -0.018743 0.120542 -0.001686 0.023617 -0.020835 -0.023278 -0.023710 0.035132 -0.046325 0.203526
TotalBsmtSF -0.025231 -0.257936 0.298392 0.215313 0.495435 -0.176979 0.392141 0.274034 0.296382 0.432061 ... 0.216169 0.199957 -0.114643 0.050981 0.097589 -0.001018 -0.015211 0.040307 -0.023750 0.617726
1stFlrSF 0.002358 -0.270611 0.391584 0.261491 0.412187 -0.152869 0.268802 0.211890 0.268363 0.354437 ... 0.207521 0.157426 -0.076616 0.070864 0.099181 0.033485 -0.017420 0.060635 -0.016423 0.582620
2ndFlrSF 0.008105 0.312220 0.036506 0.014764 0.266113 0.013541 0.013189 0.124694 0.131514 -0.202605 ... 0.068724 0.205234 0.063990 -0.022363 0.026488 0.017861 0.020223 0.044142 -0.020806 0.278211
LowQualFinSF -0.028965 0.019915 0.013293 -0.013412 -0.067973 -0.002074 -0.159068 -0.078560 -0.066142 -0.071264 ... -0.009141 -0.011815 0.021783 -0.002475 -0.030601 -0.005983 -0.002403 -0.007274 -0.006814 -0.073286
GrLivArea 0.006457 0.082398 0.334468 0.211128 0.551004 -0.104043 0.201318 0.267980 0.317642 0.076961 ... 0.219971 0.306794 0.002492 0.033151 0.096793 0.041273 0.005066 0.085897 -0.032220 0.691209
BsmtFullBath -0.001711 0.008962 0.067987 0.140862 0.090223 -0.038879 0.175190 0.110922 0.068172 0.656567 ... 0.166353 0.050259 -0.058286 0.001497 0.028851 0.028969 -0.021615 -0.019680 0.066400 0.236344
BsmtHalfBath -0.017148 -0.004664 -0.021548 0.047681 -0.045921 0.122609 -0.033810 -0.010625 0.025148 0.074985 ... 0.041759 -0.020402 -0.033970 0.035424 0.036250 -0.012719 -0.007345 0.041146 -0.042068 -0.026790
FullBath 0.006626 0.140909 0.170096 0.101439 0.524377 -0.218522 0.475003 0.427316 0.228160 0.012828 ... 0.161755 0.252857 -0.127915 0.040883 -0.019599 0.016623 -0.011155 0.061471 -0.018573 0.546787
HalfBath 0.000273 0.185976 0.035798 -0.002604 0.259677 -0.060213 0.238869 0.175231 0.184638 -0.024091 ... 0.097891 0.185443 -0.088322 -0.003450 0.068306 0.009909 0.003110 -0.007947 -0.008693 0.281715
BedroomAbvGr 0.038200 -0.048734 0.280617 0.114899 0.080345 -0.006355 -0.068586 -0.055707 0.100239 -0.125564 ... 0.032887 0.094782 0.034854 -0.024037 0.038099 0.056840 0.009966 0.053140 -0.034735 0.158195
KitchenAbvGr 0.003275 0.276212 0.003380 -0.013736 -0.189654 -0.095969 -0.171663 -0.150560 -0.029590 -0.080001 ... -0.086811 -0.072016 0.040097 -0.025103 -0.051614 -0.011210 0.062736 0.029288 0.034102 -0.148215
TotRmsAbvGrd 0.031595 0.035387 0.328658 0.152459 0.368019 -0.074965 0.079134 0.157212 0.220394 -0.048975 ... 0.139871 0.204335 0.008516 -0.001100 0.037482 0.039611 0.031503 0.054779 -0.038087 0.479828
Fireplaces -0.022740 -0.042442 0.227041 0.254272 0.364492 -0.028427 0.136065 0.089521 0.214064 0.218873 ... 0.187765 0.154158 -0.022783 0.014772 0.183224 0.050838 0.004596 0.060390 -0.025094 0.461168
GarageYrBlt -0.000074 0.095978 0.051941 -0.043868 0.546837 -0.329106 0.832099 0.639424 0.228677 0.129871 ... 0.216942 0.213881 -0.291563 0.026456 -0.084927 -0.010657 -0.031689 0.008548 -0.005883 0.516885
GarageCars 0.015540 -0.035639 0.272450 0.129896 0.582251 -0.196437 0.540309 0.407866 0.331647 0.194047 ... 0.203547 0.198684 -0.154294 0.041379 0.042242 0.001903 -0.043091 0.043633 -0.041658 0.652158
GarageArea 0.012252 -0.097686 0.296419 0.138271 0.541277 -0.158334 0.488148 0.360740 0.328004 0.241241 ... 0.205364 0.216287 -0.130040 0.043492 0.046672 -0.001890 -0.028263 0.041233 -0.030865 0.639583
WoodDeckSF -0.040320 -0.014463 0.073115 0.152759 0.220549 -0.002377 0.219863 0.199823 0.129064 0.188428 ... 1.000000 0.043225 -0.127230 -0.031436 -0.075754 0.084728 -0.007540 0.028682 0.020772 0.324090
OpenPorchSF -0.006093 -0.002367 0.107991 0.057198 0.279620 -0.033548 0.178678 0.213640 0.101776 0.055745 ... 0.043225 1.000000 -0.090668 -0.003648 0.062485 0.039329 -0.017168 0.081898 -0.053504 0.325225
EnclosedPorch 0.013044 -0.013658 -0.009496 -0.021991 -0.126313 0.082156 -0.397671 -0.200636 -0.105213 -0.117118 ... -0.127230 -0.090668 1.000000 -0.038650 -0.083756 -0.019341 0.019319 -0.024462 0.000857 -0.148736
3SsnPorch -0.047429 -0.044716 0.080022 0.023672 0.038104 0.024903 0.033396 0.047964 0.027028 0.034551 ... -0.031436 -0.003648 -0.038650 1.000000 -0.031800 -0.006217 0.000159 0.028936 0.018794 0.064986
ScreenPorch 0.008419 -0.028726 0.045194 0.031435 0.052519 0.042494 -0.044684 -0.045501 0.073498 0.077734 ... -0.075754 0.062485 -0.083756 -0.031800 1.000000 0.074155 0.033554 0.029660 0.009544 0.098910
PoolArea 0.058125 0.003860 0.019435 0.021404 0.006848 0.023986 0.003906 -0.012309 -0.009980 0.004319 ... 0.084728 0.039329 -0.019341 -0.006217 0.074155 1.000000 0.039211 -0.012007 -0.053643 0.036755
MiscVal -0.007117 -0.007569 0.003201 0.040562 -0.027982 0.070653 -0.033263 -0.007571 -0.028369 0.008649 ... -0.007540 -0.017168 0.019319 0.000159 0.033554 0.039211 1.000000 -0.007846 0.004789 -0.016619
MoSold 0.026235 -0.011168 0.030580 0.012069 0.078137 -0.010055 0.010397 0.022569 0.008098 0.007750 ... 0.028682 0.081898 -0.024462 0.028936 0.029660 -0.012007 -0.007846 1.000000 -0.149396 0.082498
YrSold 0.001594 -0.016375 0.012295 -0.011880 -0.023864 0.049796 -0.020457 0.036678 -0.011092 0.014777 ... 0.020772 -0.053504 0.000857 0.018794 0.009544 -0.053643 0.004789 -0.149396 1.000000 -0.029777
SalePrice -0.028339 -0.083061 0.359398 0.258683 0.799280 -0.087776 0.573975 0.536000 0.411393 0.361936 ... 0.324090 0.325225 -0.148736 0.064986 0.098910 0.036755 -0.016619 0.082498 -0.029777 1.000000

38 rows × 38 columns

corr = df[num_vars].corr()[['SalePrice']].sort_values(by='SalePrice', ascending=False)
corr = corr.style.background_gradient(cmap='coolwarm')
corr
  SalePrice
SalePrice 1.000000
OverallQual 0.799280
GrLivArea 0.691209
GarageCars 0.652158
GarageArea 0.639583
TotalBsmtSF 0.617726
1stFlrSF 0.582620
YearBuilt 0.573975
FullBath 0.546787
YearRemodAdd 0.536000
GarageYrBlt 0.516885
TotRmsAbvGrd 0.479828
Fireplaces 0.461168
MasVnrArea 0.411393
BsmtFinSF1 0.361936
LotFrontage 0.359398
OpenPorchSF 0.325225
WoodDeckSF 0.324090
HalfBath 0.281715
2ndFlrSF 0.278211
LotArea 0.258683
BsmtFullBath 0.236344
BsmtUnfSF 0.203526
BedroomAbvGr 0.158195
ScreenPorch 0.098910
MoSold 0.082498
3SsnPorch 0.064986
PoolArea 0.036755
BsmtFinSF2 -0.004782
MiscVal -0.016619
BsmtHalfBath -0.026790
Id -0.028339
YrSold -0.029777
LowQualFinSF -0.073286
MSSubClass -0.083061
OverallCond -0.087776
KitchenAbvGr -0.148215
EnclosedPorch -0.148736
sns.regplot(x='GrLivArea', y='SalePrice', data=df, scatter_kws={'alpha':0.7, 'edgecolor':'none'}, marker='.', line_kws={'color':'darkorange'})
plt.show()
_images/99452316da45de53f2e860cc23e16a80e58090ca38f3267f62ecb6560aef5e40.png

No podemos predecir con exactitud el valor de \(y\) a partir de \(x\), pero podemos predecir un intervalo de valores en los que se encontrará \(y\) con cierta probabilidad. Por ejemplo, podemos decir que con un 95% de probabilidad, dado un valor determinado de \(x=1000\), \(y\) se encontrará entre \(75000 y \)125000.

El gráfico es una representación cualitativa del modelo, pero el modelo en sí tomaría la forma de la siguiente ecuación:

\[y = ax + b\]

Donde \(y\) es el precio de la vivienda en dólares, \(x\) es el área de construcción en pies cuadrados y \(a\) y \(b\) son las constantes o parámetros del modelo.

Pregunta: ¿Cómo se puede interpretar el parámetro a? ¿Cómo se puede interpretar el parámetro b?

Revisar: https://www.geogebra.org/calculator/pz34cwqh

5.2. Modelos de regresión básicos#

sns.regplot(x='GrLivArea', y='SalePrice', data=df, scatter_kws={'alpha':0.7, 'edgecolor':'none'}, marker='.', line_kws={'color':'darkorange'})
plt.xlim(0, 3000)
plt.show()
_images/f84dceed34b47cb83d61e2f1ae8ba66c814b16a68f0bc4b23c82b10986f9ff7c.png
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split

y = df['SalePrice']
X = df[['GrLivArea']]

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

lr = LinearRegression()

lr.fit(X_train, y_train)

print('Intercept: ', lr.intercept_)
print('Coef: ', lr.coef_)
Intercept:  25506.75033248376
Coef:  [101.46531224]

\(Precio = 100 [\frac{USD}{Área}] * Metros\_cuadrados [Área] + 27000[USD]\)

Pregunta: ¿En promedio, cuánto costaría una vivienda de 2000 metros cuadrados?

La más simple:

\[y = ax + b\]

La regresión lineal, no necesariamente tiene que tener una sola variable independiente. Puede tener más de una variable independiente. Por ejemplo, podemos tener un modelo de regresión lineal con dos variables independientes:

\[y = ax_1 + bx_2 + c\]

Además, las variables independiente pueden tener ciertas transformaciones. Por ejemplo, podemos tener un modelo de regresión lineal con una variable independiente que es el cuadrado de otra variable independiente:

\[y = ax_1^2 + bx_1 + cx_2 + d\]


Tomado de: Tax Foundation.

¿Qué ecuación matemática podría representar el gráfico anterior?

(1) $\(y = ax^2 + bx + c\)\( (2) \)\(y = bx + c\)$

def plot_order(order=1, fit_reg=False, extended=False):
    x = np.linspace(0, 20, 19)
    def func(x):
        return x*np.sin(x)+x
    y = func(x)
    import warnings
    params = {'scatter_kws':{'alpha':1, 'edgecolor':'none'}, 
              'marker':'o', 'line_kws':{'color':'darkorange'}, 
              'ci':0, 'x':x, 'y':y}
    warnings.filterwarnings('ignore')
    fit = np.polyfit(x, y, order)
    fit_fn = np.poly1d(fit)
    if extended: xline = np.linspace(-5,25,100)
    else:        xline = np.linspace(0,20,100)
    fig = plt.figure(figsize=(8, 5))
    if fit_reg:
        plt.plot(x, y, 'bo', xline, fit_fn(xline), '--r')
    sns.regplot(order=order, **params, fit_reg=False)
    plt.axvspan(-1, 21, color='grey', alpha=0.2)
    plt.xlim(-5, 25)
    plt.ylim(-10, 50)
    plt.show()
from ipywidgets import interact
interact(plot_order, order=(1, 20, 1))
plt.show()

Overfitting: es un problema que se presenta cuando el modelo se ajusta demasiado a los datos de entrenamiento. En otras palabras, el modelo se ajusta demasiado a los datos que tiene disponible y no generaliza bien a nuevos datos.

Revisar: https://www.youtube.com/watch?v=EuBBz3bI-aA

5.2.1. Ejemplo regresión lineal#

corr
  SalePrice
SalePrice 1.000000
OverallQual 0.799280
GrLivArea 0.691209
GarageCars 0.652158
GarageArea 0.639583
TotalBsmtSF 0.617726
1stFlrSF 0.582620
YearBuilt 0.573975
FullBath 0.546787
YearRemodAdd 0.536000
GarageYrBlt 0.516885
TotRmsAbvGrd 0.479828
Fireplaces 0.461168
MasVnrArea 0.411393
BsmtFinSF1 0.361936
LotFrontage 0.359398
OpenPorchSF 0.325225
WoodDeckSF 0.324090
HalfBath 0.281715
2ndFlrSF 0.278211
LotArea 0.258683
BsmtFullBath 0.236344
BsmtUnfSF 0.203526
BedroomAbvGr 0.158195
ScreenPorch 0.098910
MoSold 0.082498
3SsnPorch 0.064986
PoolArea 0.036755
BsmtFinSF2 -0.004782
MiscVal -0.016619
BsmtHalfBath -0.026790
Id -0.028339
YrSold -0.029777
LowQualFinSF -0.073286
MSSubClass -0.083061
OverallCond -0.087776
KitchenAbvGr -0.148215
EnclosedPorch -0.148736
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split

y = df['SalePrice']
X = df[['GrLivArea']]

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

El modelo teórico sería de la siguiente forma:

\[y = ax_1 + bx_2 + c\]

Lo que buscamos son los parámetros \(a\), \(b\) y \(c\). Donde \(a\) es el coeficiente de la variable \(x_1\), \(b\) es el coeficiente de la variable \(x_2\) y \(c\) es el intercepto.

Para ello, utilizaremos el método de mínimos cuadrados. El método de mínimos cuadrados es un método que busca minimizar la suma de los errores al cuadrado. En otras palabras, busca minimizar la suma de las diferencias entre los valores reales y los valores predichos al cuadrado.

modelo_rl = LinearRegression()
modelo_rl.fit(X_train, y_train)
LinearRegression()
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.

Podemos obtener un score de nuestro modelo, que indica que tan bien se ajusta a un set de datos. En éste caso siempre se debe obtener el score frente a los datos de prueba (test data).

modelo_rl.score(X_test, y_test)
0.46011963176263837

Para obtener el intercepto y los coeficientes del modelo:

modelo_rl.intercept_
25506.75033248376
modelo_rl.coef_
array([101.46531224])

Podemos hacer predicciones del modelo utilizando el método predict para comparar el valor predicho con el valor real.

pred = modelo_rl.predict(X_test)
y_test_df = pd.DataFrame(y_test)
y_test_df['pred'] = pred

y_test_df
SalePrice pred
51 114500 144829.957532
295 142500 127276.458514
700 312500 208144.312373
1033 230000 193330.376785
377 340000 275720.210328
... ... ...
1328 256000 308797.902120
360 156000 118043.115100
1337 52500 95822.211718
1450 136000 207332.589875
566 325000 279575.892193

284 rows × 2 columns

También podemos ingresar valores de cada variable independiente para obtener un valor predicho.

modelo_rl.predict([[2000]])
array([228437.374822])

5.2.2. Variables categóricas#

Es una variable que puede tomar un número limitado de valores. Por ejemplo, el género de una persona puede ser masculino o femenino. Otra variable categórica puede ser el color de un auto, el cual puede ser rojo, azul o verde.

Las variables categóricas se pueden dividir en dos tipos: ordinales y nominales.

  • Las variables categóricas ordinales son aquellas que tienen un orden. Por ejemplo, el nivel de educación de una persona puede ser primaria, secundaria, universitaria o posgrado. En éste caso, el nivel de educación tiene un orden, ya que una persona con educación universitaria tiene más educación que una persona con educación secundaria.

  • Las variables categóricas nominales son aquellas que no tienen un orden. Por ejemplo, el color de un auto puede ser rojo, azul o verde. En éste caso, el color de un auto no tiene un orden, ya que no podemos decir que el color rojo es mayor o menor que el color azul.

Hay dos formas de representar las variables categóricas:

  • La primera forma es utilizando números. Por ejemplo, podemos representar el género de una persona con 0 para masculino y 1 para femenino. O podemos representar el color de un auto con 0 para rojo, 1 para azul y 2 para verde.

  • La segunda forma es utilizando variables dummies. Una variable dummy es una variable que toma el valor de 0 o 1. Por ejemplo, podemos representar el género de una persona con dos variables dummies: una variable dummy para masculino y otra variable dummy para femenino. En éste caso, la variable dummy para masculino toma el valor de 1 cuando el género de la persona es masculino y 0 cuando el género de la persona es femenino. Por otro lado, la variable dummy para femenino toma el valor de 1 cuando el género de la persona es femenino y 0 cuando el género de la persona es masculino. De ésta forma, podemos representar el género de una persona con dos variables dummies: una variable dummy para masculino y otra variable dummy para femenino.

df['OverallQual'].value_counts().sort_index()
2       3
3      19
4     115
5     397
6     373
7     317
8     156
9      36
10      4
Name: OverallQual, dtype: int64
df
Id MSSubClass MSZoning LotFrontage LotArea Street Alley LotShape LandContour Utilities ... PoolArea PoolQC Fence MiscFeature MiscVal MoSold YrSold SaleType SaleCondition SalePrice
0 1 60 RL 65.0 8450 Pave NaN Reg Lvl AllPub ... 0 NaN NaN NaN 0 2 2008 WD Normal 208500
1 2 20 RL 80.0 9600 Pave NaN Reg Lvl AllPub ... 0 NaN NaN NaN 0 5 2007 WD Normal 181500
2 3 60 RL 68.0 11250 Pave NaN IR1 Lvl AllPub ... 0 NaN NaN NaN 0 9 2008 WD Normal 223500
3 4 70 RL 60.0 9550 Pave NaN IR1 Lvl AllPub ... 0 NaN NaN NaN 0 2 2006 WD Abnorml 140000
4 5 60 RL 84.0 14260 Pave NaN IR1 Lvl AllPub ... 0 NaN NaN NaN 0 12 2008 WD Normal 250000
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1455 1456 60 RL 62.0 7917 Pave NaN Reg Lvl AllPub ... 0 NaN NaN NaN 0 8 2007 WD Normal 175000
1456 1457 20 RL 85.0 13175 Pave NaN Reg Lvl AllPub ... 0 NaN MnPrv NaN 0 2 2010 WD Normal 210000
1457 1458 70 RL 66.0 9042 Pave NaN Reg Lvl AllPub ... 0 NaN GdPrv Shed 2500 5 2010 WD Normal 266500
1458 1459 20 RL 68.0 9717 Pave NaN Reg Lvl AllPub ... 0 NaN NaN NaN 0 4 2010 WD Normal 142125
1459 1460 20 RL 75.0 9937 Pave NaN Reg Lvl AllPub ... 0 NaN NaN NaN 0 6 2008 WD Normal 147500

1420 rows × 81 columns

df2 = pd.get_dummies(df, columns=['OverallQual'], drop_first=True )
df2
Id MSSubClass MSZoning LotFrontage LotArea Street Alley LotShape LandContour Utilities ... SaleCondition SalePrice OverallQual_3 OverallQual_4 OverallQual_5 OverallQual_6 OverallQual_7 OverallQual_8 OverallQual_9 OverallQual_10
0 1 60 RL 65.0 8450 Pave NaN Reg Lvl AllPub ... Normal 208500 0 0 0 0 1 0 0 0
1 2 20 RL 80.0 9600 Pave NaN Reg Lvl AllPub ... Normal 181500 0 0 0 1 0 0 0 0
2 3 60 RL 68.0 11250 Pave NaN IR1 Lvl AllPub ... Normal 223500 0 0 0 0 1 0 0 0
3 4 70 RL 60.0 9550 Pave NaN IR1 Lvl AllPub ... Abnorml 140000 0 0 0 0 1 0 0 0
4 5 60 RL 84.0 14260 Pave NaN IR1 Lvl AllPub ... Normal 250000 0 0 0 0 0 1 0 0
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1455 1456 60 RL 62.0 7917 Pave NaN Reg Lvl AllPub ... Normal 175000 0 0 0 1 0 0 0 0
1456 1457 20 RL 85.0 13175 Pave NaN Reg Lvl AllPub ... Normal 210000 0 0 0 1 0 0 0 0
1457 1458 70 RL 66.0 9042 Pave NaN Reg Lvl AllPub ... Normal 266500 0 0 0 0 1 0 0 0
1458 1459 20 RL 68.0 9717 Pave NaN Reg Lvl AllPub ... Normal 142125 0 0 1 0 0 0 0 0
1459 1460 20 RL 75.0 9937 Pave NaN Reg Lvl AllPub ... Normal 147500 0 0 1 0 0 0 0 0

1420 rows × 88 columns

y = df2['SalePrice']

X = df2[['OverallQual_3', 'OverallQual_4', 'OverallQual_5', 'OverallQual_6', 'OverallQual_7', 'OverallQual_8', 'OverallQual_9', 'OverallQual_10']]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

modelo2 = LinearRegression()
modelo2.fit(X_train, y_train)
LinearRegression()
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.
X.columns
Index(['OverallQual_3', 'OverallQual_4', 'OverallQual_5', 'OverallQual_6',
       'OverallQual_7', 'OverallQual_8', 'OverallQual_9', 'OverallQual_10'],
      dtype='object')
modelo2.intercept_
51770.333333332936
plt.bar(X.columns, modelo2.coef_+modelo2.intercept_)
plt.xticks(rotation=90)
plt.show()
_images/185dbeaa508cb29e8c16dfe5f2aae3ca53784e60affe61a7ecb4ce9562c071f3.png

5.3. Los distintos tipos de modelos#

Existe una infinidad de modelos. Sin embargo, podemos clasificarlos en tres grandes grupos de acuerdo al siguiente diagrama:


Tomado de: Abdul Rahid.

En general, un proyecto en ciencia de datos sigue el siguiente flujo:

  1. Definir el problema y mirar el panorama general.

  2. Obtener los datos.

  3. Explorar los datos para obtener información general y estadística descriptiva.

  4. Preparación y limpieza de los datos.
    4.1. Separación de los datos en entrenamiento y prueba (cross-validation).

  5. Exploración y selección de modelos.

  6. Afinar los modelos (hiperparámetros).

  7. Interpretación del modelo.

  8. Presentación de la solución.

  9. Desplegar, monitorear y mantener el sistema.

5.4. Aprendizaje supervisado#

Los modelos de aprendizaje supervisado son aquellos que utilizan datos etiquetados para entrenar el modelo. En otras palabras, el modelo aprende a partir de casos en los cuales tenemos las variables independientes (x) y también tenemos las variables (y). Por ejemplo, si queremos entrenar un modelo para que reconozca imágenes de perros, necesitamos tener un set de datos de imágenes de perros etiquetadas como perros y otro set de datos de imágenes de gatos etiquetadas como gatos. De ésta forma, el modelo aprende a reconocer las imágenes de perros y gatos.

Es similar a tener un profesor que nos dice si lo que estamos haciendo está bien o mal. Por ejemplo, si estamos aprendiendo a sumar, el profesor nos dice si la suma que hicimos está bien o mal. De ésta forma, aprendemos a sumar.

¿Qué tipo de modelos de aprendizaje supervisado conocen?


Tomado de: Analyst Prep.

5.4.1. Modelos de regresión#

Un modelo de regresión es un modelo que busca predecir un valor numérico (variable continua). Por ejemplo, el precio de una vivienda, el precio de una acción, la cantidad de ventas de un producto, etc.

5.4.2. Modelos de clasificación#

Un modelo de clasificación es un modelo que busca predecir una clase (variable categórica). Por ejemplo, si una imagen es un perro o un gato, si un correo electrónico es spam o no, si un tumor es benigno o maligno, si una hogar es pobre o no, etc.

5.4.3. Árboles de decisión y bosques aleatorios#

Un árbol de decisión es un modelo de aprendizaje supervisado que utiliza un árbol para predecir una clase (variable categórica) o un valor numérico (variable continua). Un árbol de decisión es un modelo que se puede utilizar tanto para clasificación como para regresión.


Tomado de: Wikipedia.

df3 = df.copy()

encoders = {}
for col in cat_vars:
    le = LabelEncoder()
    encoders[col] = le
    df3[col] = le.fit_transform(df[col])
    
# decition tree classifier on OverallQual
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split

perdidos = df3.isna().sum()
y = df3['OverallQual']
x = df3[[i for i in df3.columns if i not in ['OverallQual', 'SalePrice'] and perdidos[i] == 0]]
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=42)
dt = DecisionTreeClassifier()
dt.fit(X_train, y_train)
DecisionTreeClassifier()
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.
# plot tree
from sklearn.tree import plot_tree

fig = plt.figure(figsize=(40, 15), dpi=150)
plot_tree(dt, feature_names=x.columns, class_names=['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'], filled=True, fontsize=7)
plt.show()
_images/99abfe7ddc0c06c70789084d55da9d30707208d2f11926bd6d540a1cc6be69cf.png
# Matríz de confusión
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay, accuracy_score

y_pred = dt.predict(X_test)
cmatrix_tc = confusion_matrix(y_test, y_pred)
cmatrix_tc
array([[ 0,  0,  1,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  2,  0,  0,  0,  0,  0],
       [ 0,  0, 12, 15,  2,  1,  0,  0,  0],
       [ 0,  1, 11, 37, 25,  1,  1,  0,  0],
       [ 0,  0,  6, 14, 47, 11,  1,  0,  0],
       [ 0,  0,  2,  5, 11, 31, 15,  1,  0],
       [ 0,  0,  0,  1,  2,  5, 16,  2,  0],
       [ 0,  0,  0,  0,  0,  1,  1,  2,  0],
       [ 0,  0,  0,  0,  0,  0,  0,  1,  0]])
lista_acc = []
for i in range(2,150):
    dt = DecisionTreeClassifier(max_depth=i)
    dt.fit(X_train, y_train)
    y_pred = dt.predict(X_test)
    acc = accuracy_score(y_test, y_pred)
    lista_acc.append(acc)
plt.plot(range(2,150), lista_acc)
[<matplotlib.lines.Line2D at 0x7f0c1c6455a0>]
_images/0fa0615f5fd299748a8a6312ced7bfe9887c0b969aa21261b457e502d21502ce.png
# Mostrar la matríz de confusión
cmap = sns.diverging_palette(200, 100, as_cmap=True)
sns.heatmap(cmatrix_tc, annot=True, cmap=cmap, fmt='d', cbar=False)
plt.xlabel('Predicted')
plt.ylabel('True')

# Calcular la exactitud (accuracy)
from sklearn.metrics import accuracy_score
acc = accuracy_score(y_test, y_pred)
print('Exactitud: ', f'{acc:.2%}')
Exactitud:  48.94%
_images/5fabead90ad32d82350c9614866a1e54866b3e1669c0ee1873672f40d6c7f29f.png
# Same but with a random forest
from sklearn.ensemble import RandomForestClassifier

rf = RandomForestClassifier(max_depth=3)
rf.fit(X_train, y_train)
y_pred = rf.predict(X_test)
cmatrix_rf = confusion_matrix(y_test, y_pred)

# Mostrar la matríz de confusión
sns.heatmap(cmatrix_rf, annot=True, cmap=cmap, fmt='d', cbar=False)
plt.xlabel('Predicted')
plt.ylabel('True')
Text(46.25, 0.5, 'True')
_images/b8988c923bbfbce462ad227f94209132767f4e98ab08d30901df3af943b8ff9a.png

El gráfico se vería de la siguiente forma:


Tomado de: Stack Overflow.

En este punto, los diagramas se vuelven muy complejos por lo que no siempre es una buena idea graficarlos.

5.4.5 Forecast con series de tiempo#

Las series de tiempo son un tipo de datos que se caracterizan por tener una secuencia de datos ordenados en el tiempo. Por ejemplo, el precio de una acción, la cantidad de ventas de un producto, la cantidad de visitas a un sitio web, etc.

En ocasiones, es posible predecir el futuro de una serie de tiempo utilizando sus valores en el pasado. A éste proceso se lo conoce como time series forecast.

Es un modelo de regresión porque busca predecir un valor numérico (variable continua). Se puede expresar aproximadamente de la siguiente forma:

\[y_{t+1} = f(y_t, y_{t-1}, y_{t-2}, ..., y_1)\]
\[y_t = a*y_{t-1}+b+\mu\]
air = pd.read_csv('https://raw.githubusercontent.com/alejo-acosta/pmdb-material/master/data/AirPassengers.csv').rename(columns={'#Passengers':'passengers', 'Month':'month'})
air['month'] = pd.to_datetime(air['month'])

air.set_index('month', inplace=True)
air.interpolate(method='linear', inplace=True)
air.plot()
plt.show()
_images/bb481027409eefdb09a90f650429bb582e258fb05643feb1fb37718f027e5064.png

Hay muchas maneras de realizar un time series forecast. Una de las más simples es utilizando el método de promedio móvil. El método de promedio móvil es un método que busca predecir el valor de una serie de tiempo utilizando el promedio de los valores anteriores. Por ejemplo, si queremos predecir el valor de una serie de tiempo en el tiempo \(t+1\), podemos utilizar el promedio de los valores de la serie de tiempo en los tiempos \(t\), \(t-1\) y \(t-2\).

# moving average of passengers
air.plot()
air['passengers'].rolling(12).mean().plot()
plt.show()
_images/4a6c0e7541750e8e361ca97e6adbf2b00d1504206b8448f02c6280aa1adcfbaf.png

Éste acercamiento tiene sus limitaciones, ya que no toma en cuenta la tendencia de la serie de tiempo. Por ejemplo, si la serie de tiempo tiene una tendencia creciente, el método de promedio móvil no va a tomar en cuenta ésta tendencia.

Otra forma es usar un modelo autoregresivo. Un modelo autoregresivo es un modelo que busca predecir el valor de una serie de tiempo utilizando los valores anteriores de la misma serie de tiempo. Por ejemplo, si queremos predecir el valor de una serie de tiempo en el tiempo \(t+1\), podemos utilizar los valores de la serie de tiempo en los tiempos \(t\), \(t-1\) y \(t-2\).

# sarima model on oil
from statsmodels.tsa.statespace.sarimax import SARIMAX
from statsmodels.tsa.seasonal import seasonal_decompose

decomposition = seasonal_decompose(air, model='additive', period=12)
decomposition.plot()
_images/a6489490f3e589f5ea423216b0f98c686402b9a2e27c5d43537575940342f85f.png _images/a6489490f3e589f5ea423216b0f98c686402b9a2e27c5d43537575940342f85f.png
oil = pd.read_csv('https://raw.githubusercontent.com/alejo-acosta/curso-python-ciee/main/data/oil.csv')
oil['date'] = oil['date'].astype('datetime64[ns]')
oil.set_index('date', inplace=True)
oil.interpolate(method='linear', inplace=True)
oil.interpolate(method='bfill', inplace=True)
oil.plot()
<Axes: xlabel='date'>
_images/02b872a17620887c5d66e0136e0270698ada8b1af0cf8c7ce5961918ae0810a8.png
decomposition = seasonal_decompose(oil, model='additive', period=12)
decomposition.plot()
_images/52edf4db6fa3cdbb8ea68b594a1160f13c394902d1ab429f5bf946629323fc54.png _images/52edf4db6fa3cdbb8ea68b594a1160f13c394902d1ab429f5bf946629323fc54.png
# autoarima forecast
from pmdarima import auto_arima

model = auto_arima(air, m=12, seasonal=True, trace=True)
model.summary()
Performing stepwise search to minimize aic
 ARIMA(2,1,2)(1,1,1)[12]             : AIC=1020.048, Time=1.06 sec
 ARIMA(0,1,0)(0,1,0)[12]             : AIC=1031.508, Time=0.02 sec
 ARIMA(1,1,0)(1,1,0)[12]             : AIC=1020.393, Time=0.08 sec
 ARIMA(0,1,1)(0,1,1)[12]             : AIC=1021.003, Time=0.13 sec
 ARIMA(2,1,2)(0,1,1)[12]             : AIC=1019.935, Time=0.48 sec
 ARIMA(2,1,2)(0,1,0)[12]             : AIC=1019.290, Time=0.13 sec
 ARIMA(2,1,2)(1,1,0)[12]             : AIC=1019.546, Time=0.48 sec
 ARIMA(1,1,2)(0,1,0)[12]             : AIC=1024.160, Time=0.08 sec
 ARIMA(2,1,1)(0,1,0)[12]             : AIC=1017.847, Time=0.11 sec
 ARIMA(2,1,1)(1,1,0)[12]             : AIC=1017.914, Time=0.41 sec
 ARIMA(2,1,1)(0,1,1)[12]             : AIC=1018.359, Time=0.43 sec
 ARIMA(2,1,1)(1,1,1)[12]             : AIC=1018.248, Time=0.85 sec
 ARIMA(1,1,1)(0,1,0)[12]             : AIC=1022.393, Time=0.06 sec
 ARIMA(2,1,0)(0,1,0)[12]             : AIC=1022.393, Time=0.04 sec
 ARIMA(3,1,1)(0,1,0)[12]             : AIC=1019.084, Time=0.12 sec
 ARIMA(1,1,0)(0,1,0)[12]             : AIC=1020.393, Time=0.04 sec
 ARIMA(3,1,0)(0,1,0)[12]             : AIC=1023.666, Time=0.05 sec
 ARIMA(3,1,2)(0,1,0)[12]             : AIC=1021.083, Time=0.19 sec
 ARIMA(2,1,1)(0,1,0)[12] intercept   : AIC=inf, Time=0.28 sec

Best model:  ARIMA(2,1,1)(0,1,0)[12]          
Total fit time: 5.066 seconds
SARIMAX Results
Dep. Variable: y No. Observations: 144
Model: SARIMAX(2, 1, 1)x(0, 1, [], 12) Log Likelihood -504.923
Date: Thu, 25 Jan 2024 AIC 1017.847
Time: 19:45:36 BIC 1029.348
Sample: 01-01-1949 HQIC 1022.520
- 12-01-1960
Covariance Type: opg
coef std err z P>|z| [0.025 0.975]
ar.L1 0.5960 0.085 6.987 0.000 0.429 0.763
ar.L2 0.2143 0.091 2.343 0.019 0.035 0.394
ma.L1 -0.9819 0.038 -25.601 0.000 -1.057 -0.907
sigma2 129.3133 14.556 8.884 0.000 100.783 157.844
Ljung-Box (L1) (Q): 0.00 Jarque-Bera (JB): 7.68
Prob(Q): 0.98 Prob(JB): 0.02
Heteroskedasticity (H): 2.33 Skew: -0.01
Prob(H) (two-sided): 0.01 Kurtosis: 4.19


Warnings:
[1] Covariance matrix calculated using the outer product of gradients (complex-step).
\[y_t = 0.5* y_{t-1} + 0.2 * y_{t-2}\]
forecast, ci = model.predict(n_periods=60, return_conf_int=True)
forecast = pd.DataFrame(forecast, columns=['forecast'])
ci = pd.DataFrame(ci, columns=['lower', 'upper'])
ci.index = forecast.index

df_plot = pd.concat([air, forecast, ci], axis=1)

fig, ax = plt.subplots(figsize=(12, 5), dpi=150)
df_plot[['passengers', 'forecast']].plot(ax=ax)
plt.fill_between(df_plot.index, df_plot['lower'], df_plot['upper'], alpha=0.3, color='grey')

plt.show()
_images/04a0e3a41dad20adfa95f43a435bffa5b10ce2aef595235bdea74e890e7b38b4.png

5.5. Aprendizaje no supervisado#

El aprendizaje no supervisado es aquel que utiliza datos no etiquetados para entrenar el modelo. En otras palabras, el modelo aprende a partir de casos en los cuales solo tenemos las variables independientes (x) pero no tenemos las variables (y).

5.5.1. Clústering#

El clustéring es un modelo que busca agrupar los datos en grupos (clústers) de acuerdo a su similitud. Por ejemplo, podemos tener un set de datos de viviendas y queremos agruparlas en grupos de acuerdo a sus características. De ésta forma, podemos tener un grupo de viviendas grandes, un grupo de viviendas pequeñas, un grupo de viviendas con piscina, etc.

Existen diversos algoritmos para clusterizar los datos, el más común es k-means.

k-means es un algoritmo que busca agrupar los datos en k grupos (clústers) de acuerdo a su similitud.

from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler

vars1 = ['GrLivArea', 'LotArea']

# remove atypical values form vars 1
df1 = df[vars1]
df1 = df1[(np.abs(stats.zscore(df1)) < 2).all(axis=1)]
df1 = df1.sample(frac=0.5, random_state=42)

# standardize
scaler = StandardScaler()
df1 = scaler.fit_transform(df1)
df1 = pd.DataFrame(df1, columns=vars1)

# kmeans
kmeans = KMeans(n_clusters=5)
kmeans.fit(df1)
df1['cluster'] = kmeans.predict(df1)

# plot
sns.scatterplot(x='GrLivArea', y='LotArea', data=df1, hue='cluster', palette='Set2')
plt.scatter(kmeans.cluster_centers_[:,0], kmeans.cluster_centers_[:,1], marker='x', s=100, c='r')
plt.show()
_images/9211707c7d90a63b3e671e85b39a56c4f317fa60a67f47d78672fd0a23fb4bf2.png
inertia = []
for i in range(1, 20):
    kmeans = KMeans(n_clusters=i)
    kmeans.fit(df1)
    inertia.append(kmeans.inertia_)
    
plt.plot(range(1, 20), inertia)
plt.xticks(range(1, 20))
plt.show()
_images/00ddee6eea5c5781cd6e4806b47a4a81597d0132a143f49662d18d4d0a9a76f2.png
# summary of clusters
X.groupby('cluster').mean().plot(kind='scatter', x='GrLivArea', y='SalePrice')
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[51], line 2
      1 # summary of clusters
----> 2 X.groupby('cluster').mean().plot(kind='scatter', x='GrLivArea', y='SalePrice')

File ~/.local/lib/python3.10/site-packages/pandas/core/frame.py:8402, in DataFrame.groupby(self, by, axis, level, as_index, sort, group_keys, squeeze, observed, dropna)
   8399     raise TypeError("You have to supply one of 'by' and 'level'")
   8400 axis = self._get_axis_number(axis)
-> 8402 return DataFrameGroupBy(
   8403     obj=self,
   8404     keys=by,
   8405     axis=axis,
   8406     level=level,
   8407     as_index=as_index,
   8408     sort=sort,
   8409     group_keys=group_keys,
   8410     squeeze=squeeze,
   8411     observed=observed,
   8412     dropna=dropna,
   8413 )

File ~/.local/lib/python3.10/site-packages/pandas/core/groupby/groupby.py:965, in GroupBy.__init__(self, obj, keys, axis, level, grouper, exclusions, selection, as_index, sort, group_keys, squeeze, observed, mutated, dropna)
    962 if grouper is None:
    963     from pandas.core.groupby.grouper import get_grouper
--> 965     grouper, exclusions, obj = get_grouper(
    966         obj,
    967         keys,
    968         axis=axis,
    969         level=level,
    970         sort=sort,
    971         observed=observed,
    972         mutated=self.mutated,
    973         dropna=self.dropna,
    974     )
    976 self.obj = obj
    977 self.axis = obj._get_axis_number(axis)

File ~/.local/lib/python3.10/site-packages/pandas/core/groupby/grouper.py:888, in get_grouper(obj, key, axis, level, sort, observed, mutated, validate, dropna)
    886         in_axis, level, gpr = False, gpr, None
    887     else:
--> 888         raise KeyError(gpr)
    889 elif isinstance(gpr, Grouper) and gpr.key is not None:
    890     # Add key to exclusions
    891     exclusions.add(gpr.key)

KeyError: 'cluster'

5.4.2. Reducción dimensional#

La reducción dimensional es un modelo que busca reducir la cantidad de variables independientes (x) de un set de datos. Por ejemplo, podemos tener un set de datos de viviendas con 100 variables independientes (x) y queremos reducirlo a 10 variables independientes (x). De ésta forma, podemos reducir la complejidad del modelo y hacerlo más eficiente.

from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
df.shape
(1420, 81)
df3.shape
(1420, 81)
x = df3.dropna().copy()
x.drop(['SalePrice'], axis=1, inplace=True)
cols = x.columns
scaler = StandardScaler()
x = scaler.fit_transform(x)
df3
Id MSSubClass MSZoning LotFrontage LotArea Street Alley LotShape LandContour Utilities ... PoolArea PoolQC Fence MiscFeature MiscVal MoSold YrSold SaleType SaleCondition SalePrice
0 1 60 3 65.0 8450 1 2 3 3 0 ... 0 2 4 4 0 2 2008 8 4 208500
1 2 20 3 80.0 9600 1 2 3 3 0 ... 0 2 4 4 0 5 2007 8 4 181500
2 3 60 3 68.0 11250 1 2 0 3 0 ... 0 2 4 4 0 9 2008 8 4 223500
3 4 70 3 60.0 9550 1 2 0 3 0 ... 0 2 4 4 0 2 2006 8 0 140000
4 5 60 3 84.0 14260 1 2 0 3 0 ... 0 2 4 4 0 12 2008 8 4 250000
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1455 1456 60 3 62.0 7917 1 2 3 3 0 ... 0 2 4 4 0 8 2007 8 4 175000
1456 1457 20 3 85.0 13175 1 2 3 3 0 ... 0 2 2 4 0 2 2010 8 4 210000
1457 1458 70 3 66.0 9042 1 2 3 3 0 ... 0 2 0 2 2500 5 2010 8 4 266500
1458 1459 20 3 68.0 9717 1 2 3 3 0 ... 0 2 4 4 0 4 2010 8 4 142125
1459 1460 20 3 75.0 9937 1 2 3 3 0 ... 0 2 4 4 0 6 2008 8 4 147500

1420 rows × 81 columns

x = pd.DataFrame(x, columns=cols)
# modelo
from sklearn.decomposition import PCA

pca = PCA()
pca.fit(x)
PCA()
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.
# plot components
fig, ax = plt.subplots(figsize=(7, 7), dpi=200)
ax.scatter(pca.components_[0], pca.components_[1])
for i in range(len(x.columns)):
    ax.annotate(x.columns[i], (pca.components_[0][i], pca.components_[1][i]), fontsize=5, color='black')
plt.show()
_images/f581c6a4357ba8debea92cbbddae7131017bef8477ddb1b78bce29392cd4a16b.png
# more components and elbow method

pca = PCA(15)
pca.fit(x)

fig, ax = plt.subplots()
ax.plot(range(1, len(pca.explained_variance_ratio_)+1), pca.explained_variance_ratio_)
plt.xlabel('Component')
plt.ylabel('Explained variance ratio')
plt.xticks(range(1, len(pca.explained_variance_ratio_)+1))
plt.show()
_images/aaf86690e409ece2cb65cddd5d5c5e981c7fe9e8664a1dda91c8dd24c4930785.png
df_pca = pd.DataFrame(pca.components_, columns=x.columns)
df_pca.T
0 1
Id -0.007768 0.005235
MSSubClass -0.007593 0.110742
MSZoning -0.090735 0.012530
LotFrontage 0.097947 0.013606
LotArea 0.051548 -0.016905
... ... ...
MiscVal -0.020495 -0.005653
MoSold 0.025686 0.035335
YrSold -0.008703 -0.026769
SaleType -0.016246 -0.002790
SaleCondition 0.077129 0.024580

80 rows × 2 columns

precio = cantidad + calidad