0% encontró este documento útil (0 votos)
18 vistas20 páginas

Sklearn - Regresion Lineal, Ejemplo Practico Mitad

El documento describe un proceso de análisis de datos de automóviles, que incluye la importación de bibliotecas, carga de datos desde un archivo CSV y preprocesamiento de datos para eliminar valores faltantes y atípicos. Se exploran las estadísticas descriptivas y se visualizan las distribuciones de variables como el precio, kilometraje y volumen del motor. Finalmente, se limpian los datos y se preparan para un análisis posterior, asegurando que las variables estén en un formato adecuado.

Cargado por

Noelia Cotignola
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOC, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
18 vistas20 páginas

Sklearn - Regresion Lineal, Ejemplo Practico Mitad

El documento describe un proceso de análisis de datos de automóviles, que incluye la importación de bibliotecas, carga de datos desde un archivo CSV y preprocesamiento de datos para eliminar valores faltantes y atípicos. Se exploran las estadísticas descriptivas y se visualizan las distribuciones de variables como el precio, kilometraje y volumen del motor. Finalmente, se limpian los datos y se preparan para un análisis posterior, asegurando que las variables estén en un formato adecuado.

Cargado por

Noelia Cotignola
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOC, PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 20

Ejemplo practico

Importar bibliotecas y modulos


import numpy as np
import pandas as pd
import statsmodels.api as sm
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
import seaborn as sns
sns.set()

Cargar la informacion en crudo


# Cargar los datos desde un .csv en la misma carpeta
raw_data = pd.read_csv('1.04. Real-life example.csv')

# Exploramos las 5 primeras filas del DF


raw_data.head()

Brand Price Body Mileage EngineV Engine Type \


0 BMW 4200.0 sedan 277 2.0 Petrol
1 Mercedes-Benz 7900.0 van 427 2.9 Diesel
2 Mercedes-Benz 13300.0 sedan 358 5.0 Gas
3 Audi 23000.0 crossover 240 4.2 Petrol
4 Toyota 18300.0 crossover 120 2.0 Petrol

Registration Year Model


0 yes 1991 320
1 yes 1999 Sprinter 212
2 yes 2003 S 500
3 yes 2007 Q7
4 yes 2011 Rav 4

Preprocesado
Exploramos las estadísticas descriptivas de las variables.
# Las estadísticas descriptivas son muy útiles para la exploración
inicial de las variables.
# Por defecto, solo se muestran descriptivas de las variables
numéricas.
# Para incluir los categóricos, debes especificar esto con un
argumento.
raw_data.describe(include='all')

# Tengan en cuenta que las variables categóricas no tienen algunos


tipos de descriptivos numéricos
# y las variables numéricas no tienen algunos tipos de descriptivos
categóricos

Brand Price Body Mileage EngineV \


count 4345 4173.000000 4345 4345.000000 4195.000000
unique 7 NaN 6 NaN NaN
top Volkswagen NaN sedan NaN NaN
freq 936 NaN 1649 NaN NaN
mean NaN 19418.746935 NaN 161.237284 2.790734
std NaN 25584.242620 NaN 105.705797 5.066437
min NaN 600.000000 NaN 0.000000 0.600000
25% NaN 6999.000000 NaN 86.000000 1.800000
50% NaN 11500.000000 NaN 155.000000 2.200000
75% NaN 21700.000000 NaN 230.000000 3.000000
max NaN 300000.000000 NaN 980.000000 99.990000

Engine Type Registration Year Model


count 4345 4345 4345.000000 4345
unique 4 2 NaN 312
top Diesel yes NaN E-Class
freq 2019 3947 NaN 199
mean NaN NaN 2006.550058 NaN
std NaN NaN 6.719097 NaN
min NaN NaN 1969.000000 NaN
25% NaN NaN 2003.000000 NaN
50% NaN NaN 2008.000000 NaN
75% NaN NaN 2012.000000 NaN
max NaN NaN 2016.000000 NaN

Determinando las variables de interés


### Determinando las variables de interés
# Para este caso, crearemos la regresión sin usar el feature 'Model'
# el mismo contiene muchos valores (312 clases unicas--> 311 dummies)
# y probablemente pueda ser definido por una combinacion de precio,
marca, tipo y tamano de motor
data = raw_data.drop(['Model'],axis=1)

# Revisemos los descriptivos sin 'Model'


data.describe(include='all')

Brand Price Body Mileage EngineV \


count 4345 4173.000000 4345 4345.000000 4195.000000
unique 7 NaN 6 NaN NaN
top Volkswagen NaN sedan NaN NaN
freq 936 NaN 1649 NaN NaN
mean NaN 19418.746935 NaN 161.237284 2.790734
std NaN 25584.242620 NaN 105.705797 5.066437
min NaN 600.000000 NaN 0.000000 0.600000
25% NaN 6999.000000 NaN 86.000000 1.800000
50% NaN 11500.000000 NaN 155.000000 2.200000
75% NaN 21700.000000 NaN 230.000000 3.000000
max NaN 300000.000000 NaN 980.000000 99.990000

Engine Type Registration Year


count 4345 4345 4345.000000
unique 4 2 NaN
top Diesel yes NaN
freq 2019 3947 NaN
mean NaN NaN 2006.550058
std NaN NaN 6.719097
min NaN NaN 1969.000000
25% NaN NaN 2003.000000
50% NaN NaN 2008.000000
75% NaN NaN 2012.000000
max NaN NaN 2016.000000

Lidiar con missing values


# data.isnull() # muestra un df con la información de si un punto de
datos es nulo
# Dado que Verdadero = falta el dato, mientras que Falso = no falta el
dato, podemos sumarlos
# Esto nos dará el número total de valores faltantes por feature.
data.isnull().sum()

Brand 0
Price 172
Body 0
Mileage 0
EngineV 150
Engine Type 0
Registration 0
Year 0
dtype: int64

# Simplemente eliminamos todos los valores faltantes.


# Esto no siempre se recomienda, sin embargo, cuando eliminamos menos
del 5% de los datos, está bien
data_no_mv = data.dropna(axis=0)

# Revisemos los descriptivos sin los valores faltantes.


data_no_mv.describe(include='all')

Brand Price Body Mileage EngineV \


count 4025 4025.000000 4025 4025.000000 4025.000000
unique 7 NaN 6 NaN NaN
top Volkswagen NaN sedan NaN NaN
freq 880 NaN 1534 NaN NaN
mean NaN 19552.308065 NaN 163.572174 2.764586
std NaN 25815.734988 NaN 103.394703 4.935941
min NaN 600.000000 NaN 0.000000 0.600000
25% NaN 6999.000000 NaN 90.000000 1.800000
50% NaN 11500.000000 NaN 158.000000 2.200000
75% NaN 21900.000000 NaN 230.000000 3.000000
max NaN 300000.000000 NaN 980.000000 99.990000

Engine Type Registration Year


count 4025 4025 4025.000000
unique 4 2 NaN
top Diesel yes NaN
freq 1861 3654 NaN
mean NaN NaN 2006.379627
std NaN NaN 6.695595
min NaN NaN 1969.000000
25% NaN NaN 2003.000000
50% NaN NaN 2007.000000
75% NaN NaN 2012.000000
max NaN NaN 2016.000000

Explorar las FDP


# Un gran paso en la exploración de datos es mostrar la función de
distribución de probabilidad (FDP-PDF probability density function)
# de una variable.
# La FDP nos mostrará como se distribuye esa variable
# Esto hace que sea muy fácil detectar anomalías, como valores
atípicos (outliers)
# La FDP suele ser la base sobre la que decidimos si queremos
transformar un feature
sns.displot(data_no_mv['Price'])

<seaborn.axisgrid.FacetGrid at 0x256f9615120>
Lidiando con los outliers (valores atipicos)
# Obviamente hay algunos valores atípicos presentes

# Sin profundizar demasiado en el tema, podemos solucionar el problema


fácilmente eliminando el 0,5% o el 1% de las muestras problemáticas.
# Aquí, los valores atípicos se sitúan alrededor de los precios más
altos (lado derecho del gráfico)
# También se debe aplicar la lógica
# Este es un conjunto de datos sobre autos usados,
#por lo tanto, uno puede imaginar que $300,000 dolares es un precio
excesivo.

# Los valores atípicos son un gran problema para OLS, por lo que
debemos abordarlos de alguna manera
# Puede ser un ejercicio útil intentar entrenar un modelo sin eliminar
los valores atípicos

# Declaremos una variable que será igual al percentil 99 de la


variable 'Price'
q = data_no_mv['Price'].quantile(0.99)
# Luego podemos crear un nuevo df, con la condición de que todos los
precios deben estar por debajo del percentil 99 de 'Price'
data_1 = data_no_mv[data_no_mv['Price']<q]
# De esta manera, esencialmente hemos eliminado el 1% superior de los
datos sobre 'Price'
data_1.describe(include='all')

Brand Price Body Mileage EngineV \


count 3984 3984.000000 3984 3984.000000 3984.000000
unique 7 NaN 6 NaN NaN
top Volkswagen NaN sedan NaN NaN
freq 880 NaN 1528 NaN NaN
mean NaN 17837.117460 NaN 165.116466 2.743770
std NaN 18976.268315 NaN 102.766126 4.956057
min NaN 600.000000 NaN 0.000000 0.600000
25% NaN 6980.000000 NaN 93.000000 1.800000
50% NaN 11400.000000 NaN 160.000000 2.200000
75% NaN 21000.000000 NaN 230.000000 3.000000
max NaN 129222.000000 NaN 980.000000 99.990000

Engine Type Registration Year


count 3984 3984 3984.000000
unique 4 2 NaN
top Diesel yes NaN
freq 1853 3613 NaN
mean NaN NaN 2006.292922
std NaN NaN 6.672745
min NaN NaN 1969.000000
25% NaN NaN 2002.750000
50% NaN NaN 2007.000000
75% NaN NaN 2011.000000
max NaN NaN 2016.000000

# Podemos verificar la FDP una vez más para asegurarnos de que el


resultado aún se distribuya de la misma manera en general.
# sin embargo, hay muchos menos valores atípicos
sns.displot(data_1['Price'])

<seaborn.axisgrid.FacetGrid at 0x256f96174c0>
# Podemos tratar las otras variables numéricas de manera similar
sns.displot(data_no_mv['Mileage'])

<seaborn.axisgrid.FacetGrid at 0x25681562710>
q = data_1['Mileage'].quantile(0.99)
data_2 = data_1[data_1['Mileage']<q]

# Esta grafica parece corresponder a una distribucion mas parecida a


una normal, ¿no?
sns.displot(data_2['Mileage'])

<seaborn.axisgrid.FacetGrid at 0x25681fb56f0>
# La situación con el volumen del motor es muy extraña.
# En tales casos, tiene sentido comprobar manualmente qué puede estar
causando el problema.
# En nuestro caso, el problema surge del hecho de que la mayoría de
los valores faltantes se indican con 99,99 o 99.
# También hay algunas entradas incorrectas como 75
sns.displot(data_no_mv['EngineV'])

<seaborn.axisgrid.FacetGrid at 0x256820aa740>
# Una simple búsqueda en Google puede indicar el dominio natural de
esta variable
# Los volúmenes de los motores de los automóviles suelen ser
(¿siempre?) inferiores a 6,5 litros.
# Este es un excelente ejemplo del hecho de que un experto en el campo
(una persona que trabaja en la industria automotriz)
# puede resultarle mucho más fácil determinar problemas con los datos
que un tercero
data_3 = data_2[data_2['EngineV']<6.5]

# Siguiendo este gráfico, nos damos cuenta de que en realidad podemos


tratar EngineV como una variable categórica
# Aun así, en este caso no lo haremos, pero eso es algo más que pueden
intentar por su cuenta.
sns.displot(data_3['EngineV'])

<seaborn.axisgrid.FacetGrid at 0x2568214a0e0>
# Finalmente, la situación con 'Year' es similar a 'Price' y 'Mileage'
# Sin embargo, los valores atípicos están en el extremo inferior.
sns.displot(data_no_mv['Year'])

<seaborn.axisgrid.FacetGrid at 0x256f9617c10>
# Simplemente los eliminamos
q = data_3['Year'].quantile(0.01)
data_4 = data_3[data_3['Year']>q]

# Aquí está el nuevo resultado


sns.displot(data_4['Year'])

<seaborn.axisgrid.FacetGrid at 0x25683763310>
# Cuando eliminamos observaciones, los índices originales se
conservan.
# Si eliminamos observaciones con índices 2 y 3, los índices quedarán
como: 0,1,4,5,6
# Eso es muy problemático ya que tendemos a olvidarlo

# Finalmente, una vez que restablezcamos el índice, se creará una


nueva columna que contendrá el índice anterior (por si acaso)
# No lo necesitaremos, por lo tanto 'drop=True' lo olvidaremos por
completo
data_cleaned = data_4.reset_index(drop=True)

# Vemos qué queda


data_cleaned.describe(include='all')

Brand Price Body Mileage EngineV \


count 3867 3867.000000 3867 3867.000000 3867.000000
unique 7 NaN 6 NaN NaN
top Volkswagen NaN sedan NaN NaN
freq 848 NaN 1467 NaN NaN
mean NaN 18194.455679 NaN 160.542539 2.450440
std NaN 19085.855165 NaN 95.633291 0.949366
min NaN 800.000000 NaN 0.000000 0.600000
25% NaN 7200.000000 NaN 91.000000 1.800000
50% NaN 11700.000000 NaN 157.000000 2.200000
75% NaN 21700.000000 NaN 225.000000 3.000000
max NaN 129222.000000 NaN 435.000000 6.300000

Engine Type Registration Year


count 3867 3867 3867.000000
unique 4 2 NaN
top Diesel yes NaN
freq 1807 3505 NaN
mean NaN NaN 2006.709853
std NaN NaN 6.103870
min NaN NaN 1988.000000
25% NaN NaN 2003.000000
50% NaN NaN 2008.000000
75% NaN NaN 2012.000000
max NaN NaN 2016.000000

Chequear las suposiciones del modelo OLS


# Aquí decidimos usar algo de código matplotlib, sin explicarlo
# Puedes simplemente usar plt.scatter() para cada uno de ellos
# Pero como el precio es el eje 'y' de todos los gráficos, tenía
sentido trazarlos uno al lado del otro (para que podamos compararlos)
f, (ax1, ax2, ax3) = plt.subplots(1, 3, sharey=True, figsize =(15,3))
#sharey -> share 'Price' as y
ax1.scatter(data_cleaned['Year'],data_cleaned['Price'])
ax1.set_title('Price and Year')
ax2.scatter(data_cleaned['EngineV'],data_cleaned['Price'])
ax2.set_title('Price and EngineV')
ax3.scatter(data_cleaned['Mileage'],data_cleaned['Price'])
ax3.set_title('Price and Mileage')

plt.show()

# A partir de las subtramas y la FDP del precio, podemos determinar


fácilmente que 'Price' está distribuido exponencialmente
# Una buena transformación en ese caso es una transformación
logarítmica.
sns.displot(data_cleaned['Price'])
<seaborn.axisgrid.FacetGrid at 0x25683b58790>

Relajar algunas suposiciones


# Transformemos 'Price' con una transformación logarítmica
log_price = np.log(data_cleaned['Price'])

# Luego lo agregamos a nuestro DF


data_cleaned['log_price'] = log_price
data_cleaned

Brand Price Body Mileage EngineV Engine Type


\
0 BMW 4200.0 sedan 277 2.0 Petrol

1 Mercedes-Benz 7900.0 van 427 2.9 Diesel

2 Mercedes-Benz 13300.0 sedan 358 5.0 Gas

3 Audi 23000.0 crossover 240 4.2 Petrol

4 Toyota 18300.0 crossover 120 2.0 Petrol


... ... ... ... ... ... ...

3862 Volkswagen 11500.0 van 163 2.5 Diesel

3863 Toyota 17900.0 sedan 35 1.6 Petrol

3864 Mercedes-Benz 125000.0 sedan 9 3.0 Diesel

3865 BMW 6500.0 sedan 1 3.5 Petrol

3866 Volkswagen 13500.0 van 124 2.0 Diesel

Registration Year log_price


0 yes 1991 8.342840
1 yes 1999 8.974618
2 yes 2003 9.495519
3 yes 2007 10.043249
4 yes 2011 9.814656
... ... ... ...
3862 yes 2008 9.350102
3863 yes 2014 9.792556
3864 yes 2014 11.736069
3865 yes 1999 8.779557
3866 yes 2013 9.510445

[3867 rows x 9 columns]

# Comprobemos los tres graficos una vez más.


f, (ax1, ax2, ax3) = plt.subplots(1, 3, sharey=True, figsize =(15,3))
ax1.scatter(data_cleaned['Year'],data_cleaned['log_price'])
ax1.set_title('Log Price and Year')
ax2.scatter(data_cleaned['EngineV'],data_cleaned['log_price'])
ax2.set_title('Log Price and EngineV')
ax3.scatter(data_cleaned['Mileage'],data_cleaned['log_price'])
ax3.set_title('Log Price and Mileage')

plt.show()

# Las relaciones muestran una relación lineal bastante clara.


Recuerden que son datos reales, no van a estar tan "limpios"
# Este es un buen material de regresión lineal.
# Alternativamente podríamos haber transformado cada una de las
variables independientes (y no tomar log de Price.
# Dado que usaremos la variable de precio de registro, podemos
eliminar la antigua 'Price'
data_cleaned = data_cleaned.drop(['Price'],axis=1)

Multicolinealidad
# Vemos rápidamente las columnas de nuestro DF.
data_cleaned.columns.values

array(['Brand', 'Body', 'Mileage', 'EngineV', 'Engine Type',


'Registration', 'Year', 'log_price'], dtype=object)

# sklearn no tiene una forma integrada de comprobar la


multicolinealidad
# una de las razones principales es que este es un tema bien cubierto
en los marcos estadísticos y no en los de ML
# Puede llegar a ser un problema, por lo que intentaremos
solucionarlo.

# Aca está el módulo relevante


# documentación completa:
http://www.statsmodels.org/dev/_modules/statsmodels/stats/outliers_inf
luence.html#variance_inflation_factor
from statsmodels.stats.outliers_influence import
variance_inflation_factor

# Para hacer esto lo más fácil posible de usar, declaramos una


variable donde ponemos
# todas las features donde queremos verificar la multicolinealidad
# dado que nuestros datos categóricos aún no están preprocesados, solo
tomaremos los numéricos
variables = data_cleaned[['Mileage','Year','EngineV']]

# creamos un nuevo df que incluirá todos los VIF


# tenga en cuenta que cada variable tiene su propio factor de
inflación de varianza,
# ya que esta medida es específica de la variable (no específica del
modelo)
vif = pd.DataFrame()

# aquí hacemos uso del variance_inflation_factor, que básicamente


generará los respectivos VIF
vif["VIF"] = [variance_inflation_factor(variables.values, i) for i in
range(variables.shape[1])]
# Finalmente, incluir nombres para que sea más fácil explorar el
resultado.
vif["Features"] = variables.columns

vif

VIF Features
0 3.791584 Mileage
1 10.354854 Year
2 7.662068 EngineV

# Dado que Year tiene el VIF más alto, lo elimino del modelo.
# ¡¡¡Esto reducirá el VIF de otras variables!!! pueden recalcular los
VIF y chequear
# Entonces, incluso si EngineV también parece tener un VIF alto, una
vez que "Año" desaparezca, ese ya no será el caso.
data_no_multicollinearity = data_cleaned.drop(['Year'],axis=1)

Crear variables dummies


# Para incluir los datos categóricos en la regresión, creemos dummies
# Hay un método muy conveniente llamado: 'get_dummies' que lo hace sin
problemas
# Es extremadamente importante que eliminemos uno de los dummies;
sino, introduciremos multicolinealidad.
data_with_dummies = pd.get_dummies(data_no_multicollinearity,
drop_first=True)

data_with_dummies.head()

Mileage EngineV log_price Brand_BMW Brand_Mercedes-Benz \


0 277 2.0 8.342840 1 0
1 427 2.9 8.974618 0 1
2 358 5.0 9.495519 0 1
3 240 4.2 10.043249 0 0
4 120 2.0 9.814656 0 0

Brand_Mitsubishi Brand_Renault Brand_Toyota Brand_Volkswagen \


0 0 0 0 0
1 0 0 0 0
2 0 0 0 0
3 0 0 0 0
4 0 0 1 0

Body_hatch Body_other Body_sedan Body_vagon Body_van Engine


Type_Gas \
0 0 0 1 0 0
0
1 0 0 0 0 1
0
2 0 0 1 0 0
1
3 0 0 0 0 0
0
4 0 0 0 0 0
0

Engine Type_Other Engine Type_Petrol Registration_yes


0 0 1 1
1 0 0 1
2 0 0 1
3 0 1 1
4 0 1 1

Reacomodar las variables


# Para organizar mejor nuestro df, colocamos la variable dependiente
al principio del df
# Dado que cada problema es diferente, debe hacerse manualmente.
# Podemos mostrar todas las funciones posibles y luego elegir el orden
deseado.
data_with_dummies.columns.values

array(['Mileage', 'EngineV', 'log_price', 'Brand_BMW',


'Brand_Mercedes-Benz', 'Brand_Mitsubishi', 'Brand_Renault',
'Brand_Toyota', 'Brand_Volkswagen', 'Body_hatch', 'Body_other',
'Body_sedan', 'Body_vagon', 'Body_van', 'Engine Type_Gas',
'Engine Type_Other', 'Engine Type_Petrol', 'Registration_yes'],
dtype=object)

# Para parametrizar un poco más el código, declaremos una nueva


variable que contendrá el orden preferido
# Si deseas un pedido diferente, simplemente especifícalo aquí
# Convencionalmente, el orden 'log_price' más intuitivo es: variable
dependiente, variables numéricas independientes, variables dummie
cols = ['log_price','Mileage', 'EngineV', 'Brand_BMW',
'Brand_Mercedes-Benz', 'Brand_Mitsubishi', 'Brand_Renault',
'Brand_Toyota', 'Brand_Volkswagen', 'Body_hatch', 'Body_other',
'Body_sedan', 'Body_vagon', 'Body_van', 'Engine Type_Gas',
'Engine Type_Other', 'Engine Type_Petrol', 'Registration_yes']

# Para implementar el reordenamiento, crearemos un nuevo df, que es


igual al anterior pero con el nuevo orden de features
data_preprocessed = data_with_dummies[cols]
data_preprocessed.head()

log_price Mileage EngineV Brand_BMW Brand_Mercedes-Benz \


0 8.342840 277 2.0 1 0
1 8.974618 427 2.9 0 1
2 9.495519 358 5.0 0 1
3 10.043249 240 4.2 0 0
4 9.814656 120 2.0 0 0
Brand_Mitsubishi Brand_Renault Brand_Toyota Brand_Volkswagen \
0 0 0 0 0
1 0 0 0 0
2 0 0 0 0
3 0 0 0 0
4 0 0 1 0

Body_hatch Body_other Body_sedan Body_vagon Body_van Engine


Type_Gas \
0 0 0 1 0 0
0
1 0 0 0 0 1
0
2 0 0 1 0 0
1
3 0 0 0 0 0
0
4 0 0 0 0 0
0

Engine Type_Other Engine Type_Petrol Registration_yes


0 0 1 1
1 0 0 1
2 0 0 1
3 0 1 1
4 0 1 1

EJERCICIO
Parte 1 Calcular los factores de inflación de la varianza para todas las variables contenidas
en data_preprocessed. ¿Algo extraño?
Parte 2 Como se mencionó en la clase, la tarea es calcular el factor de inflación de varianza
(VIF) de todas las variables, incluidas las variables dummies (pero sin la variable
dependiente).
Parte 3 Ahora calcule los VIF para un dataframe donde incluimos los dummies, sin
'log_price', pero SIN DROPEAR EL PRIMER DUMMY. ¿Algo extraño?

También podría gustarte