Clasificador de dígitos escritos a mano#
Dataset:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report, confusion_matrix, accuracy_score
from sklearn import datasets
# Cargar el conjunto de datos de dígitos
digits = datasets.load_digits()
# Mostrar algunos ejemplos de imágenes de dígitos
_, axes = plt.subplots(2, 4)
images_and_labels = list(zip(digits.images, digits.target))
for ax, (image, label) in zip(axes.flatten(), images_and_labels[:8]):
ax.set_axis_off()
ax.imshow(image, cmap=plt.cm.gray_r, interpolation="nearest")
ax.set_title(f"Training: {label}")
Ajuste del modelo con regresión Logística:
El parámetro max_iter en LogisticRegression especifica el número máximo de iteraciones que el algoritmo de optimización debe realizar para intentar converger a una solución. En conjuntos de datos grandes o complejos, el algoritmo puede necesitar muchas iteraciones para converger adecuadamente. Establecer un valor alto para max_iter asegura que el algoritmo tenga suficiente oportunidad para converger y evita advertencias de scikit-learn sobre la falta de convergencia. Aumentar el número de iteraciones puede mejorar la precisión del modelo si el algoritmo necesita más tiempo para ajustar los parámetros correctamente.
# Aplanar las imágenes
n_samples = len(digits.images)
print("Número de ejemplos:", n_samples)
data = digits.images.reshape((n_samples, -1))
# Dividir el conjunto de datos en entrenamiento y prueba
X_train, X_test, y_train, y_test = train_test_split(
data, digits.target, test_size=0.3, random_state=34
)
Número de ejemplos: 1797
# Crear un modelo de regresión logística
logistic_model = LogisticRegression()
# Entrenar el modelo
logistic_model.fit(X_train, y_train)
# Calcular las predicciones de probabilidades para el conjunto de prueba
y_pred_prob = logistic_model.predict_proba(X_test)[:, 1]
c:Usersmigueanaconda3libsite-packagessklearnlinear_model_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1): STOP: TOTAL NO. of ITERATIONS REACHED LIMIT. Increase the number of iterations (max_iter) or scale the data as shown in: https://scikit-learn.org/stable/modules/preprocessing.html Please also refer to the documentation for alternative solver options: https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression n_iter_i = _check_optimize_result(
El modelo no converge, se aumentará el número de iteraciones:
max_iter=10000
# Crear un modelo de regresión logística
logistic_model = LogisticRegression(max_iter=10000)
# Entrenar el modelo
logistic_model.fit(X_train, y_train)
# Calcular las predicciones de probabilidades para el conjunto de prueba
y_pred_prob = logistic_model.predict_proba(X_test)[:, 1]
# Predecir los valores en el conjunto de prueba
y_pred = logistic_model.predict(X_test)
print("Valores reales en el conjunto de prueba:\n", y_test[:10])
print("Predicciones en el conjunto de prueba:\n", y_pred[:10])
Valores reales en el conjunto de prueba:
[5 3 2 6 2 2 7 3 0 8]
Predicciones en el conjunto de prueba:
[5 3 2 6 2 2 7 3 0 8]
Evaluación del modelo:
# Calcular las métricas de evaluación
accuracy = accuracy_score(y_test, y_pred)
class_report = classification_report(y_test, y_pred)
# Mostrar las métricas de evaluación
print("Accuracy:", accuracy)
print("Classification Report:\n", class_report)
Accuracy: 0.9703703703703703
Classification Report:
precision recall f1-score support
0 0.98 1.00 0.99 62
1 0.91 1.00 0.95 50
2 1.00 1.00 1.00 51
3 1.00 0.97 0.98 66
4 0.98 0.97 0.97 58
5 0.98 0.93 0.95 55
6 0.98 0.98 0.98 46
7 0.98 1.00 0.99 44
8 0.96 0.91 0.94 57
9 0.92 0.96 0.94 51
accuracy 0.97 540
macro avg 0.97 0.97 0.97 540
weighted avg 0.97 0.97 0.97 540
Matriz de confusión:
conf_matrix = confusion_matrix(y_test, y_pred)
plt.figure(figsize=(10, 7))
plt.imshow(conf_matrix, cmap=plt.cm.Blues)
plt.title("Matriz de Confusión")
plt.colorbar()
tick_marks = np.arange(len(digits.target_names))
plt.xticks(tick_marks, digits.target_names, rotation=45)
plt.yticks(tick_marks, digits.target_names)
thresh = conf_matrix.max() / 2.0
for i, j in np.ndindex(conf_matrix.shape):
plt.text(
j,
i,
format(conf_matrix[i, j], "d"),
horizontalalignment="center",
color="white" if conf_matrix[i, j] > thresh else "black",
)
plt.ylabel("Clase Verdadera")
plt.xlabel("Clase Predicha")
plt.tight_layout()
plt.show()
Imagen dígito escrito en papel#
Para usar cv2
, se necesita instalar la biblioteca OpenCV
.
pip install opencv-python
import cv2
Toma la foto con buena iluminación y en modo retrato.
# Cargar la imagen del dígito escrito en papel
nombre_archivo = "7.jpg"
img = cv2.imread(nombre_archivo, cv2.IMREAD_GRAYSCALE)
# Mostrar la imagen original
plt.imshow(img, cmap="gray")
plt.title("Imagen Original")
plt.axis("off")
plt.show()
umbralización (thresholding): es una técnica de procesamiento de imágenes utilizada para convertir una imagen en escala de grises en una imagen binaria (blanco y negro). La umbralización implica elegir un valor de umbral (threshold) y luego convertir cada píxel de la imagen en blanco si su valor de intensidad es mayor que el umbral, o en negro si su valor de intensidad es menor que el umbral.
Se recomienda hacer una captura de pantalla para centrar el número y evitar los bordes negros de la imagen.
# Aplicar un umbral para asegurarse de que el dígito esté en negro y el fondo en blanco
_, img = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY)
# Mostrar la imagen umbralizada
plt.imshow(img, cmap="gray")
plt.title("Imagen Umbralizada")
plt.axis("off")
plt.show()
# Redimensionar la imagen a 8x8 píxeles
img_resized = cv2.resize(img, (8, 8), interpolation=cv2.INTER_AREA)
# Mostrar la imagen redimensionada
plt.imshow(img_resized, cmap="gray")
plt.title("Imagen Redimensionada")
plt.axis("off")
plt.show()
# Invertir los colores (hacer blanco y negro)
img_resized = cv2.bitwise_not(img_resized)
# Normalizar los valores de los píxeles al rango 0-16 (como el conjunto de datos digits)
img_resized = (img_resized / 16).astype(np.float64)
# Aplanar la imagen (convertir a una sola fila de 64 elementos)
img_flattened = img_resized.flatten().reshape(1, -1)
# Hacer la predicción usando el modelo entrenado
prediction = logistic_model.predict(img_flattened)
print(f"El modelo predice: {prediction[0]}")
El modelo predice: 7