Regresión Logística con Python paso a paso

Breve Introducción a la Regresión Logística

Utilizaremos algoritmos de Machine Learning en Python para resolver un problema de Regresión Logística. A partir de un conjunto de datos de entrada (características), nuestra salida será discreta (y no continua) por eso utilizamos Regresión Logística (y no Regresión Lineal). La Regresión Logística es un Algoritmo Supervisado y se utiliza para clasificación.

Vamos a clasificar problemas con dos posibles estados “SI/NO”: binario o un número finito de “etiquetas” o “clases”: múltiple. Algunos Ejemplos de Regresión Logística son:

  • Clasificar si el correo que llega es Spam o No es Spam
  • Dados unos resultados clínicos de un tumor clasificar en “Benigno” o “Maligno”.
  • El texto de un artículo a analizar es: Entretenimiento, Deportes, Política ó Ciencia
  • A partir de historial bancario conceder un crédito o no

Confiaremos en la implementación del paquete sklearn en Python para ponerlo en práctica.

Ejercicio de Regresión Logística en Python

Para nuestro ejercicio he creado un archivo csv con datos de entrada a modo de ejemplo para clasificar si el usuario que visita un sitio web usa como sistema operativo Windows, Macintosh o Linux.

Nuestra información de entrada son 4 características que tomé de una web que utiliza Google Analytics y son:

  • Duración de la visita en Segundos
  • Cantidad de Páginas Vistas durante la Sesión
  • Cantidad de Acciones del usuario (click, scroll, uso de checkbox, sliders,etc)
  • Suma del Valor de las acciones (cada acción lleva asociada una valoración de importancia)

Como la salida es discreta, asignaremos los siguientes valores a las etiquetas:

0 – Windows
1 – Macintosh
2 -Linux

La muestra es pequeña: son 170 registros para poder comprender el ejercicio, pero recordemos que para conseguir buenos resultados siempre es mejor contar con un número abundante de datos que darán mayor exactitud a las predicciones y evitarán problemas de overfitting u underfitting. (Por decir algo, de mil a 5 mil registros no estaría mal).

Requerimientos técnicos

Para ejecutar el código necesitas tener instalado Python -tanto la versión 2.7 o 3.6- y varios paquetes usados comúnmente en Data Science. Recomiendo tener instalada la suite Anaconda o Canopy, muy sencillas y con los paquetes para “Data Science” ya pre-instalados y funcionan en todas las plataformas.

¿Cómo instalar tu ambiente de desarrollo Python Anaconda?

Para este ejemplo he creado un block de notas Jupyter donde se muestra paso a paso el ejercicio. Se puede descargar desde aqui o se puede seguir online desde el Jupyter Notebook Viewer.

Regresión Logística con SKLearn:

Identificar Sistema Operativo de los usuarios

Para comenzar hacemos los Import necesarios con los paquetes que utilizaremos en el Ejercicio.

Leemos el archivo csv (por sencillez, se considera que estará en el mismo directorio que el archivo de notebook .ipynb) y lo asignamos mediante Pandas a la variable dataframe. Mediante el método dataframe.head() vemos en pantalla los 5 primeros registros.

A continuación llamamos al método dataframe.describe() que nos dará algo de información estadística básica de nuestro set de datos. La Media, el desvío estándar, valores mínimo y máximo de cada característica.

Luego analizaremos cuantos resultados tenemos de cada tipo usando la función groupby y vemos que tenemos 86 usuarios “Clase 0”, es decir Windows, 40 usuarios Mac y 44 de Linux.

Visualización de Datos

Antes de empezar a procesar el conjunto de datos, vamos a hacer unas visualizaciones que muchas veces nos pueden ayudar a comprender mejor las características de la información con la que trabajamos y su correlación.

Primero visualizamos en formato de historial los cuatro Features de entrada con nombres “duración”, “páginas”,”acciones” y “valor” podemos ver gráficamente entre qué valores se comprenden sus mínimos y máximos y en qué intervalos concentran la mayor densidad de registros.

Y también podemos interrelacionar las entradas de a pares, para ver como se concentran linealmente las salidas de usuarios por colores: Sistema Operativo Windows en azul, Macintosh en verde y Linux en rojo.

Creamos el Modelo de Regresión Logística

Ahora cargamos las variables de las 4 columnas de entrada en X excluyendo la columna “clase” con el método drop(). En cambio agregamos la columna “clase” en la variable y. Ejecutamos X.shape para comprobar la dimensión de nuestra matriz con datos de entrada de 170 registros por 4 columnas.

(170, 4)

Y creamos nuestro modelo y hacemos que se ajuste (fit) a nuestro conjunto de entradas X y salidas ‘y’.

LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
intercept_scaling=1, max_iter=100, multi_class=’ovr’, n_jobs=1,
penalty=’l2′, random_state=None, solver=’liblinear’, tol=0.0001,
verbose=0, warm_start=False)

Una vez compilado nuestro modelo, le hacemos clasificar todo nuestro conjunto de entradas X utilizando el método “predict(X)” y revisamos algunas de sus salidas y vemos que coincide con las salidas reales de nuestro archivo csv.

[2 2 2 2 2]

Y confirmamos cuan bueno fue nuestro modelo utilizando model.score() que nos devuelve la precisión media de las predicciones, en nuestro caso del 77%.

0.77647058823529413

Validación de nuestro modelo

Una buena práctica en Machine Learning es la de subdividir nuestro conjunto de datos de entrada en un set de entrenamiento y otro para validar el modelo (que no se utiliza durante el entrenamiento y por lo tanto la máquina desconoce). Esto evitará problemas en los que nuestro algoritmo pueda fallar por “sobregeneralizar” el conocimiento.

Para ello, subdividimos nuestros datos de entrada en forma aleatoria (mezclados) utilizando 80% de registros para entrenamiento y 20% para validar.

Volvemos a compilar nuestro modelo de Regresión Logística pero esta vez sólo con 80% de los datos de entrada y calculamos el nuevo scoring que ahora nos da 74%.

Logistic Regression: 0.743407 (0.115752)

Y ahora hacemos las predicciones -en realidad clasificación- utilizando nuestro “cross validation set”, es decir del subconjunto que habíamos apartado. En este caso vemos que los aciertos fueron del 85% pero hay que tener en cuenta que el tamaño de datos era pequeño.

0.852941176471

Finalmente vemos en pantalla la “matriz de confusión” donde muestra cuantos resultados equivocados tuvo de cada clase (los que no están en la diagonal), por ejemplo predijo 3 usuarios que eran Mac como usuarios de Windows y predijo a 2 usuarios Linux que realmente eran de Windows.

Reporte de Resultados del Modelo

También podemos ver el reporte de clasificación con nuestro conjunto de Validación. En nuestro caso vemos que se utilizaron como “soporte” 18 registros windows, 6 de mac y 10 de Linux (total de 34 registros). Podemos ver la precisión con que se acertaron cada una de las clases y vemos que por ejemplo de Macintosh tuvo 3 aciertos y 3 fallos (0.5 recall). La valoración que de aqui nos conviene tener en cuenta es la de F1-score, que tiene en cuenta la precisión y recall. El promedio de F1 es de 84% lo cual no está nada mal.

Clasificación (o predicción) de nuevos valores

Como último ejercicio, vamos a inventar los datos de entrada de  navegación de un usuario ficticio que tiene estos valores:

  • Tiempo Duración: 10
  • Paginas visitadas: 3
  • Acciones al navegar: 5
  • Valoración: 9

Lo probamos en nuestro modelo y vemos que lo clasifica como un usuario tipo 2, es decir, de Linux.

array([2])

Los invito a jugar y variar estos valores para obtener usuarios de tipo Windows o Macintosh.

Conclusiones

Durante este artículo vimos cómo crear un modelo de Regresión Logística en Python para poder clasificar el Sistema Operativo de usuarios a partir de sus características de navegación en un sitio web. A partir de este ejemplo, se podrá extender a otro tipos de tareas que pueden surgir durante nuestro trabajo en el que deberemos clasificar resultados en valores discretos. Si tuviéramos que predecir valores continuos, deberemos aplicar Regresión Lineal.

Espero que puedan seguir correctamente el ejercicio y si tienen inconvenientes técnicos me escriben en los comentarios para solucionarlos o si encuentran mejoras al texto/ejercicio, también espero sus sugerencias. Recuerda descargar los archivos para realizar el Ejercicio:

Si te interesa aprender algoritmos con Python, ahora está disponible “K-means” paso a paso y árbol de decisión te invito a leerlos.

Como siempre los invito a suscribirse al blog y a compartir las entradas en Redes Sociales para que podamos aumentar nuestra comunidad de “estudiantes” aprendiendo Machine Learning!

Suscribe Aprende Machine Learning

Suscribe al blog y te llegará el aviso del próximo artículo semanal/quincenal sobre Machine Learning.

Hasta la próxima!

GuardarGuardarGuardarGuardarGuardarGuardarGuardarGuardar

GuardarGuardar

18 Replies to “Regresión Logística con Python paso a paso”

  1. Hola, quisiera saber que algoritmo de machine learning me serviría para clasificar a mis clientes. Creo que Kmeans es el algoritmo utilizado en estos casos. Lo que me gustaría conseguir es optimizar la publicidad para conocer los perfiles más comunes de mis clientes y segmentarlos.

    Muchas gracias

    1. Hola Borja, si tienes características de tus clientes y no los tienes etiquetados, es una muy buena opción aplicar k-means para crear (y descubrir) clusters (grupos) de perfiles (pues es un algoritmo sin supervisión). Una vez que obtengas el valor óptimo de K (es decir, la cantidad de grupos) y ejecutado el algoritmo, deberás analizar el resultado para ver cual es el centro de cada grupo y comprender lo que los hace únicos y diferenciales del resto de grupos. Si necesitas ayuda me avisas!. ¿Has visto mi artículo sobre k-means? el enlace es k-means con Python paso a paso. Saludos y espero que nos mantengamos en contacto.

  2. Hola Juan Ignacio…. Lo felicito porque está muy bien explicado este tema…. siga así…. !!!!

    1. Hola efraín, muchas gracias por tus palabras!. Espero poder escribir un nuevo artículo sobre Redes Neuronales con Python pronto!. Saludos y seguimos en contacto

      1. Hola Juan Ignacio…. Estuve replicando este ejemplo tuyo con otra base de datos que tiene entradas mixtas (categóricas y numéricas) con salida categorica (1,2,3) y todo bien hasta cuando se va a crean el model.fit(X,y)
        No se si me puedas ayudar a entender porque pasa eso enviando el notebook y la BD. Gracias mil

        1. Efrain, sígueme por Twitter y te paso por mensaje directo mi email para que me adjuntes los archivos. O si quieres, escríbeme por aquí el error que te da y lo revisamos.

    1. Gracias Etienne! Siempre da alegría saber que les puedo ayudar! Espero seguir escribiendo nuevos artículos! Saludos

  3. Hola Juan Ignacio, muchas gracias, y muchas felicidades también por tan loable labor de compartir este conocimiento tan útil, me esta siendo de muchísima ayuda. Tengo una pregunta, en tu dataset en la variable objetivo “clase”, no están niveladas las categorías (86,40,44), al parecer en este caso no afecta en gran medida al resultado porque son pocos datos, pero si tuviéramos el mismo escenario pero con más datos ej. (8725,1230,2300), ¿nos serviría también este algoritmo, o tendríamos que prescindir de algunos datos para nivelar el numero?

    Gracias

    1. Hola Iven, gracias por participar en el Blog!. Muy buena tu observación. Te cuento que lo ideal siempre es tener las etiquetas o clases balanceadas. Esto es tener casi la misma cantidad de clases en el conjunto de entrenamiento. Esto es para que el algoritmo supervisado que aprende generalice correctamente el conocimiento. Si no, corremos el riesgo de que tenga un sesgo, o que caiga en Overfitting obteniendo inferencias erróneas.
      Hay que tener en cuenta 2 cosas:
      * Por una parte, según el algoritmo que utilicemos, tendrá mayor o menor “tolerancia” a estas “clases desniveladas”. Por ejemplo Naive Bayes se comporta bastante bien a pesar de tener pocas muestras de una clase. Sin embargo para Regresión continua o lineal conviene un buen equilibrio.
      * Por otra parte, tenemos técnicas para equilibrar las clases “artificialmente”, por ejemplo inventando muestras inexistentes como se suele hacer para redes neuronales que reconocen imágenes: se toma una misma imagen y se la “copia y pega” pero rotada unos grados a la izquierda, o se le aplica algún filtro de desenfoque.
      Saludos y espero que te ayude la respuesta!

      1. Muchas gracias por contestar tan rápido Juan Ignacio, me quedó muy clara la respuesta. Ahora bien, me gustaría aprender sobre ese tipo de técnicas que comentas para equilibrar las clases. ¿Tendrás a la mano información de este tipo o algún sitio en donde me pueda informar?
        Saludos y nuevamente felicitaciones por este proyecto.

  4. Hola Nacho. Muy buen artículo. Bastante bien explicado, aunque he tenido que buscar ayuda externa de k-fold cross validation, ya que no sabía lo que era (por si la vale a alguien, aquí lo explican muy bien en inglés: https://magoosh.com/data-science/k-fold-cross-validation/). Tengo una preguntilla: si al principio entrenamos el modelo con todos los datos, ¿cómo es que al predecir sobre esos mismos datos obtenemos sólo un 77% de acierto en vez de un 100%? Muchas gracias y un saludo

    1. Hola Alberto, gracias por participar. Con respecto a las definiciones y/o referencias a otros temas como k-folds o cross validación, me acabas de dar una buena idea, que es la de crear un glosario en el blog, en donde podré poner ese tipo de notas. Gracias también por el enlace sobre k-fold.
      Con respecto a tu pregunta te respondo: por más que utilizamos todos los datos de nuestro conjunto, el algoritmo será capaz de generalizar el conocimiento hasta un cierto punto. En este caso, logra acertar en el 77% de los casos. Si hubiera dado el 100% seguramente querría decir que está cayendo en Overfiting (lo que es un problema).
      En resumen y para que quede claro:
      * que utilicemos el 100% de datos no quiere decir que vayamos a tener un 100% de aciertos.
      * de hecho, es una mala práctica usar el 100%, pues conviene separar un subconjunto para utilizarlo como test del algoritmo
      * Si agregáramos muchas más EPOCHS (iteraciones) al algoritmo puede ser que mejoremos el porcentaje de aciertos, pero seguramente estemos teniendo Overfiting lo cual no es bueno.
      Saludos, espero que sigamos en contacto!

  5. Hola Nacho.
    Al ejecutar este código:

    predictions = model.predict(X)
    print(predictions)[0:5]

    me sale este error:

    TypeError Traceback (most recent call last)
    in ()
    1 predictions = model.predict(X)
    —-> 2 print(predictions)[0:5]

    TypeError: ‘NoneType’ object is not subscriptable

    ¿podrías ayudarme cómo corregirlo?

Leave a Reply