EVALUACIÓN Y OPTIMIZACIÓN DEL MODELO
Cuando todos los modelos tengan una precisión similar, ¿ahora qué?
Ha entrenado varios modelos de clasificación y todos parecen funcionar bien con puntuaciones de precisión altas. ¡Felicidades!
Pero un momento: ¿es realmente un modelo mejor que los demás? La precisión por sí sola no cuenta toda la historia. ¿Qué pasa si un modelo sobreestima constantemente su confianza, mientras que otro la subestima? Aquí es donde calibración del modelo entra.
Aquí veremos qué es la calibración de modelos y exploraremos cómo evaluar la confiabilidad de las predicciones de sus modelos, utilizando elementos visuales y ejemplos de códigos prácticos para mostrarle cómo identificar problemas de calibración. ¡Prepárese para ir más allá de la precisión e iluminar el verdadero potencial de sus modelos de aprendizaje automático!
La calibración del modelo mide qué tan bien probabilidades de predicción coincidir con su rendimiento real. Un modelo que proporciona una puntuación de probabilidad del 70 % debería ser correcto el 70 % de las veces para predicciones similares. Esto significa que sus puntuaciones de probabilidad deben reflejar la verdadera probabilidad de que sus predicciones sean correctas.
Por qué es importante la calibración
Mientras que la precisión nos dice con qué frecuencia un modelo es correcto en general, la calibración nos dice si podemos confiar en sus puntuaciones de probabilidad. Es posible que dos modelos tengan una precisión del 90%, pero uno podría dar puntuaciones de probabilidad realistas mientras que el otro ofrece predicciones demasiado seguras. En muchas aplicaciones reales, tener puntuaciones de probabilidad confiables es tan importante como tener predicciones correctas.
Calibración perfecta versus realidad
Un modelo perfectamente calibrado mostraría una coincidencia directa entre sus probabilidades de predicción y las tasas de éxito reales: cuando predice con un 90% de probabilidad, debería acertar el 90% de las veces. Lo mismo se aplica a todos los niveles de probabilidad.
Sin embargo, la mayoría de los modelos no están perfectamente calibrados. Pueden ser:
- Exceso de confianza: otorgar puntuaciones de probabilidad demasiado altas para su desempeño real
- Falta de confianza: otorgar puntuaciones de probabilidad que son demasiado bajas para su desempeño real.
- Ambos: exceso de confianza en algunos rangos y falta de confianza en otros
Este desajuste entre las probabilidades predichas y la exactitud real puede llevar a una mala toma de decisiones al utilizar estos modelos en aplicaciones reales. Por eso es necesario comprender y mejorar la calibración del modelo para construir sistemas confiables de aprendizaje automático.
Para explorar la calibración del modelo, continuaremos con el mismo conjunto de datos utilizado en mis artículos anteriores sobre algoritmos de clasificación: predecir si alguien jugará golf o no en función de las condiciones climáticas.
import pandas as pd
import numpy as np
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split# Create and prepare dataset
dataset_dict = {
'Outlook': ['sunny', 'sunny', 'overcast', 'rainy', 'rainy', 'rainy', 'overcast',
'sunny', 'sunny', 'rainy', 'sunny', 'overcast', 'overcast', 'rainy',
'sunny', 'overcast', 'rainy', 'sunny', 'sunny', 'rainy', 'overcast',
'rainy', 'sunny', 'overcast', 'sunny', 'overcast', 'rainy', 'overcast'],
'Temperature': [85.0, 80.0, 83.0, 70.0, 68.0, 65.0, 64.0, 72.0, 69.0, 75.0, 75.0,
72.0, 81.0, 71.0, 81.0, 74.0, 76.0, 78.0, 82.0, 67.0, 85.0, 73.0,
88.0, 77.0, 79.0, 80.0, 66.0, 84.0],
'Humidity': [85.0, 90.0, 78.0, 96.0, 80.0, 70.0, 65.0, 95.0, 70.0, 80.0, 70.0,
90.0, 75.0, 80.0, 88.0, 92.0, 85.0, 75.0, 92.0, 90.0, 85.0, 88.0,
65.0, 70.0, 60.0, 95.0, 70.0, 78.0],
'Wind': [False, True, False, False, False, True, True, False, False, False, True,
True, False, True, True, False, False, True, False, True, True, False,
True, False, False, True, False, False],
'Play': ['No', 'No', 'Yes', 'Yes', 'Yes', 'No', 'Yes', 'No', 'Yes', 'Yes', 'Yes',
'Yes', 'Yes', 'No', 'No', 'Yes', 'Yes', 'No', 'No', 'No', 'Yes', 'Yes',
'Yes', 'Yes', 'Yes', 'Yes', 'No', 'Yes']
}
# Prepare data
df = pd.DataFrame(dataset_dict)
Antes de entrenar nuestros modelos, normalizamos las mediciones meteorológicas numéricas mediante escala estándar y rasgos categóricos transformados con codificación one-hot. Estos pasos de preprocesamiento garantizan que todos los modelos puedan utilizar los datos de forma eficaz y, al mismo tiempo, mantener comparaciones justas entre ellos.
from sklearn.preprocessing import StandardScaler
df = pd.get_dummies(df, columns=['Outlook'], prefix='', prefix_sep='', dtype=int)
df['Wind'] = df['Wind'].astype(int)
df['Play'] = (df['Play'] == 'Yes').astype(int)# Rearrange columns
column_order = ['sunny', 'overcast', 'rainy', 'Temperature', 'Humidity', 'Wind', 'Play']
df = df[column_order]
# Prepare features and target
X,y = df.drop('Play', axis=1), df['Play']
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.5, shuffle=False)
# Scale numerical features
scaler = StandardScaler()
X_train[['Temperature', 'Humidity']] = scaler.fit_transform(X_train[['Temperature', 'Humidity']])
X_test[['Temperature', 'Humidity']] = scaler.transform(X_test[['Temperature', 'Humidity']])
Modelos y entrenamiento
Para esta exploración, entrenamos cuatro modelos de clasificación con puntuaciones de precisión similares:
- K-vecinos más cercanos (kNN)
- Bernoulli ingenuo Bayes
- Regresión logística
- Perceptrón multicapa (MLP)
Para aquellos que tengan curiosidad sobre cómo esos algoritmos hacen predicciones y su probabilidad, pueden consultar este artículo:
Si bien estos modelos lograron la misma precisión en este simple problema, calculan sus probabilidades de predicción de manera diferente.
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.neural_network import MLPClassifier
from sklearn.metrics import accuracy_score
from sklearn.naive_bayes import BernoulliNB# Initialize the models with the found parameters
knn = KNeighborsClassifier(n_neighbors=4, weights='distance')
bnb = BernoulliNB()
lr = LogisticRegression(C=1, random_state=42)
mlp = MLPClassifier(hidden_layer_sizes=(4, 2),random_state=42, max_iter=2000)
# Train all models
models = {
'KNN': knn,
'BNB': bnb,
'LR': lr,
'MLP': mlp
}
for name, model in models.items():
model.fit(X_train, y_train)
# Create predictions and probabilities for each model
results_dict = {
'True Labels': y_test
}
for name, model in models.items():
# results_dict[f'{name} Pred'] = model.predict(X_test)
results_dict[f'{name} Prob'] = model.predict_proba(X_test)[:, 1]
# Create results dataframe
results_df = pd.DataFrame(results_dict)
# Print predictions and probabilities
print("\nPredictions and Probabilities:")
print(results_df)
# Print accuracies
print("\nAccuracies:")
for name, model in models.items():
accuracy = accuracy_score(y_test, model.predict(X_test))
print(f"{name}: {accuracy:.3f}")
A través de estas diferencias, exploraremos por qué necesitamos mirar más allá de la precisión.
Para evaluar qué tan bien las probabilidades de predicción de un modelo coinciden con su desempeño real, utilizamos varios métodos y métricas. Estas mediciones nos ayudan a comprender si los niveles de confianza de nuestro modelo son confiables.
Puntuación de zarza
La puntuación de Brier mide el diferencia media al cuadrado entre las probabilidades previstas y los resultados reales. Varía de 0 a 1, donde puntuaciones más bajas indican una mejor calibración. Esta puntuación es particularmente útil porque considera tanto la calibración como la precisión juntas.
Pérdida de registro
Pérdida de registro Calcula la probabilidad logarítmica negativa de predicciones correctas. Esta métrica es especialmente sensible a predicciones confiables pero incorrectas: cuando un modelo dice que está 90% seguro pero está equivocado, recibe una penalización mucho mayor que cuando está 60% seguro y está equivocado. Los valores más bajos indican una mejor calibración.
Error de calibración esperado (ECE)
CEPE Mide la diferencia promedio entre las probabilidades predichas y reales (tomada como promedio de la etiqueta), ponderada por la cantidad de predicciones que caen en cada grupo de probabilidad. Esta métrica nos ayuda a comprender si nuestro modelo tiene sesgos sistemáticos en sus estimaciones de probabilidad.
Diagramas de confiabilidad
De manera similar a ECE, un diagrama de confiabilidad (o curva de calibración) visualiza la calibración del modelo agrupando las predicciones y comparándolas con los resultados reales. Mientras que ECE nos da un único número que mide el error de calibración, el diagrama de confiabilidad nos muestra la misma información gráficamente. Utilizamos el mismo enfoque de agrupación y calculamos la frecuencia real de resultados positivos en cada categoría. Cuando se representan, estos puntos nos muestran exactamente dónde se desvían las predicciones de nuestro modelo de una calibración perfecta, lo que aparecería como una línea diagonal.
Comparación de métricas de calibración
Cada una de estas métricas muestra diferentes aspectos de los problemas de calibración:
- Una puntuación Brier alta sugiere estimaciones de probabilidad deficientes en general.
- La pérdida logarítmica elevada indica predicciones erróneas y demasiado confiadas.
- Una ECE alta indica un sesgo sistemático en las estimaciones de probabilidad.
Juntas, estas métricas nos brindan una imagen completa de qué tan bien las puntuaciones de probabilidad de nuestro modelo reflejan su verdadero desempeño.
Nuestros modelos
Para nuestros modelos, calculemos las métricas de calibración y dibujemos sus curvas de calibración:
from sklearn.metrics import brier_score_loss, log_loss
from sklearn.calibration import calibration_curve
import matplotlib.pyplot as plt# Initialize models
models = {
'k-Nearest Neighbors': KNeighborsClassifier(n_neighbors=4, weights='distance'),
'Bernoulli Naive Bayes': BernoulliNB(),
'Logistic Regression': LogisticRegression(C=1.5, random_state=42),
'Multilayer Perceptron': MLPClassifier(hidden_layer_sizes=(4, 2), random_state=42, max_iter=2000)
}
# Get predictions and calculate metrics
metrics_dict = {}
for name, model in models.items():
model.fit(X_train, y_train)
y_prob = model.predict_proba(X_test)[:, 1]
metrics_dict[name] = {
'Brier Score': brier_score_loss(y_test, y_prob),
'Log Loss': log_loss(y_test, y_prob),
'ECE': calculate_ece(y_test, y_prob),
'Probabilities': y_prob
}
# Plot calibration curves
fig, axes = plt.subplots(2, 2, figsize=(8, 8), dpi=300)
colors = ['orangered', 'slategrey', 'gold', 'mediumorchid']
for idx, (name, metrics) in enumerate(metrics_dict.items()):
ax = axes.ravel()[idx]
prob_true, prob_pred = calibration_curve(y_test, metrics['Probabilities'],
n_bins=5, strategy='uniform')
ax.plot([0, 1], [0, 1], 'k--', label='Perfectly calibrated')
ax.plot(prob_pred, prob_true, color=colors[idx], marker='o',
label='Calibration curve', linewidth=2, markersize=8)
title = f'{name}\nBrier: {metrics["Brier Score"]:.3f} | Log Loss: {metrics["Log Loss"]:.3f} | ECE: {metrics["ECE"]:.3f}'
ax.set_title(title, fontsize=11, pad=10)
ax.grid(True, alpha=0.7)
ax.set_xlim([-0.05, 1.05])
ax.set_ylim([-0.05, 1.05])
ax.spines[['top', 'right', 'left', 'bottom']].set_visible(False)
ax.legend(fontsize=10, loc='upper left')
plt.tight_layout()
plt.show()
Ahora, analicemos el rendimiento de la calibración de cada modelo en función de esas métricas:
El modelo k-Vecinos más cercanos (KNN) funciona bien al estimar qué tan seguro debe ser acerca de sus predicciones. La línea de su gráfico permanece cerca de la línea de puntos, lo que muestra un buen rendimiento. Tiene puntuaciones sólidas: una puntuación Brier de 0,148 y la mejor puntuación ECE de 0,090. Si bien a veces muestra demasiada confianza en el rango medio, generalmente hace estimaciones confiables sobre su certeza.
El modelo Bernoulli Naive Bayes muestra un patrón de escalón inusual en su línea. Esto significa que salta entre diferentes niveles de certeza en lugar de cambiar suavemente. Si bien tiene el mismo puntaje Brier que KNN (0,148), su ECE más alto de 0,150 muestra que es menos preciso al estimar su certeza. el modelo cambia entre tener demasiada confianza y no tener la suficiente confianza.
El modelo de regresión logística muestra claros problemas con sus predicciones. Su línea se aleja mucho de la línea de puntos, lo que significa que a menudo juzga mal qué tan segura debería ser. Tiene el peor puntaje ECE (0,181) y un puntaje Brier pobre (0,164). El modelo muestra consistentemente demasiada confianza en sus prediccioneshaciéndolo poco confiable.
El perceptrón multicapa muestra un problema distinto. A pesar de tener el mejor puntaje de Brier (0.129), su línea revela que en su mayoría hace predicciones extremas – ya sea muy seguro o muy incierto, con poco en el medio. Su alto ECE (0,167) y su línea plana en los rangos medios muestran que le cuesta hacer estimaciones de certeza equilibradas.
Después de examinar los cuatro modelos, el k-Vecinos más cercanos claramente funciona mejor para estimar la certeza de su predicción. Mantiene un rendimiento constante en diferentes niveles de certeza y muestra el patrón más confiable en sus predicciones. Si bien otros modelos pueden obtener buenos resultados en ciertas medidas (como el puntaje Brier del Perceptrón Multicapa), sus gráficos revelan que no son tan confiables cuando necesitamos confiar en sus estimaciones de certeza.
Al elegir entre diferentes modelos, debemos considerar tanto su precisión como la calidad de la calibración. Un modelo con una precisión ligeramente inferior pero con una mejor calibración podría ser más valioso que un modelo muy preciso con estimaciones de probabilidad deficientes.
Al comprender la calibración y su importancia, podemos construir sistemas de aprendizaje automático más confiables en los que los usuarios puedan confiar no solo por sus predicciones, sino también por su confianza en esas predicciones.
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import BernoulliNB
from sklearn.metrics import brier_score_loss, log_loss
from sklearn.calibration import calibration_curve
import matplotlib.pyplot as plt# Define ECE
def calculate_ece(y_true, y_prob, n_bins=5):
bins = np.linspace(0, 1, n_bins + 1)
ece = 0
for bin_lower, bin_upper in zip(bins[:-1], bins[1:]):
mask = (y_prob >= bin_lower) & (y_prob < bin_upper)
if np.sum(mask) > 0:
bin_conf = np.mean(y_prob[mask])
bin_acc = np.mean(y_true[mask])
ece += np.abs(bin_conf - bin_acc) * np.sum(mask)
return ece / len(y_true)
# Create dataset and prepare data
dataset_dict = {
'Outlook': ['sunny', 'sunny', 'overcast', 'rainy', 'rainy', 'rainy', 'overcast','sunny', 'sunny', 'rainy', 'sunny', 'overcast', 'overcast', 'rainy','sunny', 'overcast', 'rainy', 'sunny', 'sunny', 'rainy', 'overcast','rainy', 'sunny', 'overcast', 'sunny', 'overcast', 'rainy', 'overcast'],
'Temperature': [85.0, 80.0, 83.0, 70.0, 68.0, 65.0, 64.0, 72.0, 69.0, 75.0, 75.0,72.0, 81.0, 71.0, 81.0, 74.0, 76.0, 78.0, 82.0, 67.0, 85.0, 73.0,88.0, 77.0, 79.0, 80.0, 66.0, 84.0],
'Humidity': [85.0, 90.0, 78.0, 96.0, 80.0, 70.0, 65.0, 95.0, 70.0, 80.0, 70.0,90.0, 75.0, 80.0, 88.0, 92.0, 85.0, 75.0, 92.0, 90.0, 85.0, 88.0,65.0, 70.0, 60.0, 95.0, 70.0, 78.0],
'Wind': [False, True, False, False, False, True, True, False, False, False, True,True, False, True, True, False, False, True, False, True, True, False,True, False, False, True, False, False],
'Play': ['No', 'No', 'Yes', 'Yes', 'Yes', 'No', 'Yes', 'No', 'Yes', 'Yes', 'Yes','Yes', 'Yes', 'No', 'No', 'Yes', 'Yes', 'No', 'No', 'No', 'Yes', 'Yes','Yes', 'Yes', 'Yes', 'Yes', 'No', 'Yes']
}
# Prepare and encode data
df = pd.DataFrame(dataset_dict)
df = pd.get_dummies(df, columns=['Outlook'], prefix='', prefix_sep='', dtype=int)
df['Wind'] = df['Wind'].astype(int)
df['Play'] = (df['Play'] == 'Yes').astype(int)
df = df[['sunny', 'overcast', 'rainy', 'Temperature', 'Humidity', 'Wind', 'Play']]
# Split and scale data
X, y = df.drop('Play', axis=1), df['Play']
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.5, shuffle=False)
scaler = StandardScaler()
X_train[['Temperature', 'Humidity']] = scaler.fit_transform(X_train[['Temperature', 'Humidity']])
X_test[['Temperature', 'Humidity']] = scaler.transform(X_test[['Temperature', 'Humidity']])
# Train model and get predictions
model = BernoulliNB()
model.fit(X_train, y_train)
y_prob = model.predict_proba(X_test)[:, 1]
# Calculate metrics
metrics = {
'Brier Score': brier_score_loss(y_test, y_prob),
'Log Loss': log_loss(y_test, y_prob),
'ECE': calculate_ece(y_test, y_prob)
}
# Plot calibration curve
plt.figure(figsize=(6, 6), dpi=300)
prob_true, prob_pred = calibration_curve(y_test, y_prob, n_bins=5, strategy='uniform')
plt.plot([0, 1], [0, 1], 'k--', label='Perfectly calibrated')
plt.plot(prob_pred, prob_true, color='slategrey', marker='o',
label='Calibration curve', linewidth=2, markersize=8)
title = f'Bernoulli Naive Bayes\nBrier: {metrics["Brier Score"]:.3f} | Log Loss: {metrics["Log Loss"]:.3f} | ECE: {metrics["ECE"]:.3f}'
plt.title(title, fontsize=11, pad=10)
plt.grid(True, alpha=0.7)
plt.xlim([-0.05, 1.05])
plt.ylim([-0.05, 1.05])
plt.gca().spines[['top', 'right', 'left', 'bottom']].set_visible(False)
plt.legend(fontsize=10, loc='lower right')
plt.tight_layout()
plt.show()
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import BernoulliNB
from sklearn.linear_model import LogisticRegression
from sklearn.neural_network import MLPClassifier
from sklearn.metrics import brier_score_loss, log_loss
from sklearn.calibration import calibration_curve
import matplotlib.pyplot as plt# Define ECE
def calculate_ece(y_true, y_prob, n_bins=5):
bins = np.linspace(0, 1, n_bins + 1)
ece = 0
for bin_lower, bin_upper in zip(bins[:-1], bins[1:]):
mask = (y_prob >= bin_lower) & (y_prob < bin_upper)
if np.sum(mask) > 0:
bin_conf = np.mean(y_prob[mask])
bin_acc = np.mean(y_true[mask])
ece += np.abs(bin_conf - bin_acc) * np.sum(mask)
return ece / len(y_true)
# Create dataset and prepare data
dataset_dict = {
'Outlook': ['sunny', 'sunny', 'overcast', 'rainy', 'rainy', 'rainy', 'overcast','sunny', 'sunny', 'rainy', 'sunny', 'overcast', 'overcast', 'rainy','sunny', 'overcast', 'rainy', 'sunny', 'sunny', 'rainy', 'overcast','rainy', 'sunny', 'overcast', 'sunny', 'overcast', 'rainy', 'overcast'],
'Temperature': [85.0, 80.0, 83.0, 70.0, 68.0, 65.0, 64.0, 72.0, 69.0, 75.0, 75.0,72.0, 81.0, 71.0, 81.0, 74.0, 76.0, 78.0, 82.0, 67.0, 85.0, 73.0,88.0, 77.0, 79.0, 80.0, 66.0, 84.0],
'Humidity': [85.0, 90.0, 78.0, 96.0, 80.0, 70.0, 65.0, 95.0, 70.0, 80.0, 70.0,90.0, 75.0, 80.0, 88.0, 92.0, 85.0, 75.0, 92.0, 90.0, 85.0, 88.0,65.0, 70.0, 60.0, 95.0, 70.0, 78.0],
'Wind': [False, True, False, False, False, True, True, False, False, False, True,True, False, True, True, False, False, True, False, True, True, False,True, False, False, True, False, False],
'Play': ['No', 'No', 'Yes', 'Yes', 'Yes', 'No', 'Yes', 'No', 'Yes', 'Yes', 'Yes','Yes', 'Yes', 'No', 'No', 'Yes', 'Yes', 'No', 'No', 'No', 'Yes', 'Yes','Yes', 'Yes', 'Yes', 'Yes', 'No', 'Yes']
}
# Prepare and encode data
df = pd.DataFrame(dataset_dict)
df = pd.get_dummies(df, columns=['Outlook'], prefix='', prefix_sep='', dtype=int)
df['Wind'] = df['Wind'].astype(int)
df['Play'] = (df['Play'] == 'Yes').astype(int)
df = df[['sunny', 'overcast', 'rainy', 'Temperature', 'Humidity', 'Wind', 'Play']]
# Split and scale data
X, y = df.drop('Play', axis=1), df['Play']
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.5, shuffle=False)
scaler = StandardScaler()
X_train[['Temperature', 'Humidity']] = scaler.fit_transform(X_train[['Temperature', 'Humidity']])
X_test[['Temperature', 'Humidity']] = scaler.transform(X_test[['Temperature', 'Humidity']])
# Initialize models
models = {
'k-Nearest Neighbors': KNeighborsClassifier(n_neighbors=4, weights='distance'),
'Bernoulli Naive Bayes': BernoulliNB(),
'Logistic Regression': LogisticRegression(C=1.5, random_state=42),
'Multilayer Perceptron': MLPClassifier(hidden_layer_sizes=(4, 2), random_state=42, max_iter=2000)
}
# Get predictions and calculate metrics
metrics_dict = {}
for name, model in models.items():
model.fit(X_train, y_train)
y_prob = model.predict_proba(X_test)[:, 1]
metrics_dict[name] = {
'Brier Score': brier_score_loss(y_test, y_prob),
'Log Loss': log_loss(y_test, y_prob),
'ECE': calculate_ece(y_test, y_prob),
'Probabilities': y_prob
}
# Plot calibration curves
fig, axes = plt.subplots(2, 2, figsize=(8, 8), dpi=300)
colors = ['orangered', 'slategrey', 'gold', 'mediumorchid']
for idx, (name, metrics) in enumerate(metrics_dict.items()):
ax = axes.ravel()[idx]
prob_true, prob_pred = calibration_curve(y_test, metrics['Probabilities'],
n_bins=5, strategy='uniform')
ax.plot([0, 1], [0, 1], 'k--', label='Perfectly calibrated')
ax.plot(prob_pred, prob_true, color=colors[idx], marker='o',
label='Calibration curve', linewidth=2, markersize=8)
title = f'{name}\nBrier: {metrics["Brier Score"]:.3f} | Log Loss: {metrics["Log Loss"]:.3f} | ECE: {metrics["ECE"]:.3f}'
ax.set_title(title, fontsize=11, pad=10)
ax.grid(True, alpha=0.7)
ax.set_xlim([-0.05, 1.05])
ax.set_ylim([-0.05, 1.05])
ax.spines[['top', 'right', 'left', 'bottom']].set_visible(False)
ax.legend(fontsize=10, loc='upper left')
plt.tight_layout()
plt.show()
Entorno técnico
Este artículo utiliza Python 3.7 y scikit-learn 1.5. Si bien los conceptos discutidos son generalmente aplicables, las implementaciones de código específicas pueden variar ligeramente con las diferentes versiones.
Acerca de las ilustraciones
A menos que se indique lo contrario, todas las imágenes son creadas por el autor e incorporan elementos de diseño con licencia de Canva Pro.
𝙎𝙚𝙚 𝙢𝙤𝙧𝙚 𝙈𝙤𝙙𝙚𝙡 𝙀𝙫𝙖𝙡𝙪𝙖𝙩𝙞𝙤𝙣 & 𝙊𝙥𝙩𝙞𝙢𝙞𝙯𝙖𝙩𝙞𝙤𝙣 𝙢𝙚𝙩𝙝𝙤𝙙𝙨 𝙝𝙚𝙧𝙚:
Evaluación y optimización del modelo
𝙔𝙤𝙪 𝙢𝙞𝙜𝙝𝙩 𝙖𝙡𝙨𝙤 𝙡𝙞𝙠𝙚: