096bzn5da3xkcvdif.jpeg

Lanzar una red flexible que sólo retenga peces grandes

Nota: El código utilizado en este artículo utiliza tres scripts personalizados, data_cleaning, data_reviewy , edaal que se puede acceder a través de un acceso público repositorio de GitHub.

Foto por Eric BARBEAU en desempaquetar

Es como una red de pesca extensible que retiene «todos los peces grandes» Zou y Hastie (2005) p. 302

La regresión lineal es una herramienta de enseñanza comúnmente utilizada en ciencia de datos y, bajo las condiciones apropiadas (por ejemplo, relación lineal entre las variables independientes y dependientes, ausencia de multicolinealidad), puede ser un método eficaz para predecir una respuesta. Sin embargo, en algunos escenarios (por ejemplo, cuando la estructura del modelo se vuelve compleja), su uso puede resultar problemático.

Para abordar algunas de las limitaciones del algoritmo, se han sugerido técnicas de penalización o regularización. [1]. Dos métodos populares de regularización son la regresión de cresta y lazo, pero elegir entre estos métodos puede resultar difícil para quienes son nuevos en el campo de la ciencia de datos.

Un enfoque para elegir entre regresión de cresta y lazo es examinar la relevancia de las características para la variable de respuesta. [2]. Cuando la mayoría de las características del modelo son relevantes (es decir, contribuyen al poder predictivo del modelo), la penalización de la regresión de cresta (o penalización L2) debe agregarse a la regresión lineal.

Cuando se suma la penalización de la regresión de cresta, la función de costos del modelo es:

Imagen del autor
  • θ = el vector de parámetros o coeficientes del modelo
  • α = la fuerza general de la regularización
  • metro = el número de ejemplos de entrenamiento
  • norte = el número de características en el conjunto de datos

Cuando la mayoría de las características son irrelevantes (es decir, no contribuyen al poder predictivo del modelo), la penalización de regresión de lazo (o penalización L1) debe agregarse a la regresión lineal.

Cuando se agrega la penalización de regresión de lazo, la función de costo del modelo es:

Imagen del autor

La relevancia se puede determinar mediante revisión manual o validación cruzada; sin embargo, cuando se trabaja con varias funciones, el proceso requiere mucho tiempo y es costoso desde el punto de vista computacional.

Una solución eficiente y flexible a este problema es utilizar la regresión neta elástica, que combina las penalizaciones de cresta y lazo.

La función de costos para la regresión neta elástica es:

Imagen del autor
  • r = la proporción de mezcla entre la regresión de cresta y lazo.

Cuando r es 1, solo se usa la penalización de lazo y cuando r es 0, solo se usa la penalización de cresta. Cuando r tiene un valor entre 0 y 1, se utiliza una combinación de penalizaciones.

Además de ser adecuada para conjuntos de datos con varias características, la regresión neta elástica tiene otros atributos que la convierten en una herramienta atractiva para los científicos de datos. [1]:

  • Selección automática de características relevantes, lo que da como resultado modelos parsimoniosos que son fáciles de interpretar.
  • Contracción continua, que reduce gradualmente los coeficientes de las características menos relevantes hacia cero (en contraposición a una reducción inmediata a cero)
  • Capacidad de seleccionar grupos de características correlacionadas, en lugar de seleccionar una característica del grupo arbitrariamente

Debido a su utilidad y flexibilidad, Zou y Hastie (2005) compararon el modelo con una “…red de pesca extensible que retiene todos los peces grandes”. (p. 302), donde los peces grandes son análogos a características relevantes.

Ahora que tenemos algunos antecedentes, podemos avanzar y implementar la regresión neta elástica en un conjunto de datos real.

Un gran recurso para datos es el Repositorio de aprendizaje automático de la Universidad de California en Irvine (UCI ML Repo). Para el tutorial, usaremos el conjunto de datos de calidad del vino. [3]que tiene licencia bajo una Creative Commons Atribución 4.0 Internacional licencia.

La función que se muestra a continuación se puede utilizar para obtener conjuntos de datos e información variable del UCI ML Repo ingresando el número de identificación como parámetro de la función.

pip install ucimlrepo # unless already installed
from ucimlrepo import fetch_ucirepo
import pandas as pd

def fetch_uci_data(id):
"""
Function to return features datasets from the UCI ML Repository.

Parameters
----------
id: int
Identifying number for the dataset

Returns
----------
df: df
Dataframe with features and response variable
"""
dataset = fetch_ucirepo(id=id)

features = pd.DataFrame(dataset.data.features)
response = pd.DataFrame(dataset.data.targets)
df = pd.concat([features, response], axis=1)

# Print variable information
print('Variable Information')
print('--------------------')
print(dataset.variables)

return(df)

# Wine Quality's identification number is 186
df = fetch_uci_data(186)

Se asignó un marco de datos de pandas a la variable «df» y se imprimió información sobre el conjunto de datos.

Análisis exploratorio de datos

Variable Information
--------------------
name role type demographic \
0 fixed_acidity Feature Continuous None
1 volatile_acidity Feature Continuous None
2 citric_acid Feature Continuous None
3 residual_sugar Feature Continuous None
4 chlorides Feature Continuous None
5 free_sulfur_dioxide Feature Continuous None
6 total_sulfur_dioxide Feature Continuous None
7 density Feature Continuous None
8 pH Feature Continuous None
9 sulphates Feature Continuous None
10 alcohol Feature Continuous None
11 quality Target Integer None
12 color Other Categorical None

description units missing_values
0 None None no
1 None None no
2 None None no
3 None None no
4 None None no
5 None None no
6 None None no
7 None None no
8 None None no
9 None None no
10 None None no
11 score between 0 and 10 None no
12 red or white None no

Según la información de la variable, podemos ver que hay 11 «características», 1 «objetivo» y 1 «otra» variable en el conjunto de datos. Esta es información interesante: si hubiéramos extraído los datos sin la información variable, es posible que no hubiéramos sabido que había datos disponibles sobre la familia (o el color) del vino. En este momento, no incorporaremos la variable «color» en el modelo, pero es bueno saber que estará ahí para futuras iteraciones del proyecto.

La columna «descripción» en la información de la variable sugiere que la variable «calidad» es categórica. Es probable que los datos sean ordinales, lo que significa que tienen una estructura jerárquica, pero no se garantiza que los intervalos entre los datos sean iguales o conocidos. En términos prácticos, significa que un vino con una calificación de 4 no es dos veces mejor que un vino con una calificación de 2. Para solucionar este problema, convertiremos los datos al tipo de datos adecuado.

df['quality'] = df['quality'].astype('category')

Para comprender mejor los datos podemos utilizar el countplot() método de la seaborn paquete para visualizar la distribución de la variable “calidad”.

import seaborn as sns
import matplotlib.pyplot as plt

sns.set_theme(style='whitegrid') # optional

sns.countplot(data=df, x='quality')
plt.title('Distribution of Wine Quality')
plt.xlabel('Quality')
plt.ylabel('Count')
plt.show()

Imagen del autor

Al realizar un análisis de datos exploratorio, es beneficioso crear histogramas para características numéricas. Además, agrupar las variables por una variable categórica puede proporcionar nuevos conocimientos. La mejor opción para agrupar los datos es la “calidad”. Sin embargo, dado que hay 7 grupos de calidad, las tramas podrían resultar difíciles de leer. Para simplificar la agrupación, podemos crear una nueva función, «calificación», que organiza los datos sobre «calidad» en tres categorías: baja, media y alta.

def categorize_quality(value):
if 0 <= value <= 3:
return 0 # low rating
elif 4 <= value <= 6:
return 1 # medium rating
else:
return # high rating

# Create new column for 'rating' data
df['rating'] = df['quality'].apply(categorize_quality)

Para determinar cuántos vinos hay en cada grupo, podemos utilizar el siguiente código:

df['rating'].value_counts()
rating
1 5190
2 1277
0 30
Name: count, dtype: int64

Según el resultado del código, podemos ver que la mayoría de los vinos se clasifican como «medios».

Ahora podemos trazar histogramas de los grupos de características numéricas por «calificación». Para trazar el histograma necesitaremos usar el gen_histograms_by_category() método de la eda script en el repositorio de GitHub compartido al principio del artículo.

import eda 

eda.gen_histograms_by_category(df, 'rating')

Imagen del autor

Arriba se muestra uno de los gráficos generados por el método. Una revisión del gráfico indica que hay cierta asimetría en los datos. Para obtener una medida más precisa de la asimetría, junto con otras estadísticas, podemos utilizar la get_statistics() método de la data_review guion.

from data_review import get_statistics

get_statistics(df)

-------------------------
Descriptive Statistics
-------------------------
fixed_acidity volatile_acidity citric_acid residual_sugar chlorides free_sulfur_dioxide total_sulfur_dioxide density pH sulphates alcohol quality
count 6497.000000 6497.000000 6497.000000 6497.000000 6497.000000 6497.000000 6497.000000 6497.000000 6497.000000 6497.000000 6497.000000 6497.000000
mean 7.215307 0.339666 0.318633 5.443235 0.056034 30.525319 115.744574 0.994697 3.218501 0.531268 10.491801 5.818378
std 1.296434 0.164636 0.145318 4.757804 0.035034 17.749400 56.521855 0.002999 0.160787 0.148806 1.192712 0.873255
min 3.800000 0.080000 0.000000 0.600000 0.009000 1.000000 6.000000 0.987110 2.720000 0.220000 8.000000 3.000000
25% 6.400000 0.230000 0.250000 1.800000 0.038000 17.000000 77.000000 0.992340 3.110000 0.430000 9.500000 5.000000
50% 7.000000 0.290000 0.310000 3.000000 0.047000 29.000000 118.000000 0.994890 3.210000 0.510000 10.300000 6.000000
75% 7.700000 0.400000 0.390000 8.100000 0.065000 41.000000 156.000000 0.996990 3.320000 0.600000 11.300000 6.000000
max 15.900000 1.580000 1.660000 65.800000 0.611000 289.000000 440.000000 1.038980 4.010000 2.000000 14.900000 9.000000
skew 1.723290 1.495097 0.471731 1.435404 5.399828 1.220066 -0.001177 0.503602 0.386839 1.797270 0.565718 0.189623
kurtosis 5.061161 2.825372 2.397239 4.359272 50.898051 7.906238 -0.371664 6.606067 0.367657 8.653699 -0.531687 0.23232

De acuerdo con el histograma, la característica denominada «acidez_fija» tiene una asimetría de 1,72, lo que indica una asimetría significativa hacia la derecha.

Para determinar si existen correlaciones entre las variables, podemos usar otra función del eda guion.

eda.gen_corr_matrix_hmap(df)
Imagen del autor

Aunque existen algunas relaciones moderadas y fuertes entre las características, la regresión neta elástica funciona bien con variables correlacionadas, por lo tanto, no se requiere ninguna acción. [2].

Limpieza de datos

Para que el algoritmo de regresión neta elástica se ejecute correctamente, los datos numéricos deben escalarse y las variables categóricas deben codificarse.

Para limpiar los datos, seguiremos los siguientes pasos:

  1. Escalar los datos usando el scale_data() método de la data_cleaning guion
  2. Codifique las variables de “calidad” y “calificación” utilizando el get_dummies() método de pandas
  3. Separe las características (es decir, X) y la variable de respuesta (es decir, y) usando el separate_data() método
  4. Divida los datos en conjuntos de tren y prueba usando train_test_split()
from sklearn.model_selection import train_test_split
from data_cleaning import scale_data, separate_data

df_scaled = scale_data(df)
df_encoded = pd.get_dummies(df_scaled, columns=['quality', 'rating'])

# Separate features and response variable (i.e., 'alcohol')
X, y = separate_data(df_encoded, 'alcohol')

# Create test and train sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size =0.2, random_state=0)

Construcción y evaluación de modelos

Para entrenar el modelo, usaremos ElasticNetCV() que tiene dos parámetros, alpha y l1_ratioy validación cruzada incorporada. El alpha El parámetro determina la fuerza de la regularización aplicada al modelo y l1_ratio determina la combinación de la penalización de lazo y cresta (es equivalente a la variable r que fue revisada en el Fondo sección).

  • Cuando l1_ratio se establece en un valor de 0, se utiliza la penalización de regresión de cresta.
  • Cuando l1_ratio se establece en un valor de 1, se utiliza la penalización de regresión de lazo.
  • Cuando l1_ratio se establece en un valor entre 0 y 1, se utiliza una combinación de ambas penalizaciones.

Eligiendo valores para alpha y l1_ratio puede ser un desafío; sin embargo, la tarea se facilita mediante el uso de validación cruzada, que está integrada en ElasticNetCV(). Para facilitar el proceso, no es necesario proporcionar una lista de valores de alpha y l1_ratio — Puedes dejar que el método haga el trabajo pesado.

from sklearn.linear_model import ElasticNet, ElasticNetCV

# Build the model
elastic_net_cv = ElasticNetCV(cv=5, random_state=1)

# Train the model
elastic_net_cv.fit(X_train, y_train)

print(f'Best Alpha: {elastic_net_cv.alpha_}')
print(f'Best L1 Ratio:{elastic_net_cv.l1_ratio_}')

Best Alpha: 0.0013637974514517563
Best L1 Ratio:0.5

Según la impresión, podemos ver los mejores valores para alpha y l1_ratio son 0,001 y 0,5, respectivamente.

Para determinar qué tan bien funcionó el modelo, podemos calcular el error cuadrático medio y la puntuación R cuadrado del modelo.

from sklearn.metrics import mean_squared_error

# Predict values from the test dataset
elastic_net_pred = elastic_net_cv.predict(X_test)

mse = mean_squared_error(y_test, elastic_net_pred)
r_squared = elastic_net_cv.score(X_test, y_test)

print(f'Mean Squared Error: {mse}')
print(f'R-squared value: {r_squared}')

Mean Squared Error: 0.2999434011721803
R-squared value: 0.7142939720612289

Conclusión

Según las métricas de evaluación, el modelo funciona moderadamente bien. Sin embargo, su rendimiento podría mejorarse mediante algunos pasos adicionales, como detectar y eliminar valores atípicos, ingeniería de características adicionales y proporcionar un conjunto específico de valores para alpha y l1_ratio en ElasticNetCV(). Desafortunadamente, esos pasos están más allá del alcance de este sencillo tutorial; sin embargo, pueden proporcionar algunas ideas sobre cómo otros podrían mejorar este proyecto.

Gracias por tomarse el tiempo de leer este artículo. Si tiene alguna pregunta o comentario, deje un comentario.

[1] H. Zou & T. Hastie, Regularización y selección de variables a través de la red elástica, Revista de la Royal Statistical Society Serie B: Metodología estadística, volumen 67, número 2, abril de 2005, páginas 301–320, https://doi.org/10.1111/j.1467-9868.2005.00503.x

[2] A. Géron, Aprendizaje automático práctico con Scikit-Learn, Keras y Tensorflow: conceptos, herramientas y técnicas para construir sistemas inteligentes (2021), O’Reilly.

[3] P. Cortez, A. Cerdeira, F. Almeida, T. Matos y Reis, J. (2009). Calidad del vino. Repositorio de aprendizaje automático de la UCI. https://doi.org/10.24432/C56S3T.