Más sobre ciencia de datos: cienciadedatos.net
- Correlación lineal con Python
- Regresión logística con python
- Regularización Ridge, Lasso y Elastic Net con Python
- Machine learning con Python y Scikit-learn

Introducción
La regresión logística es un método estadístico que trata de modelar la probabilidad de una variable cualitativa binaria (dos posibles valores) en función de una o más variables independientes. La principal aplicación de la regresión logística es la creación de modelos de clasificación binaria.
Se llama regresión logística simple cuando solo hay una variable independiente y regresión logística múltiple cuando hay más de una. Dependiendo del contexto, a la variable modelada se le conoce como variable dependiente o variable respuesta, y a las variables independientes como regresores, predictores o features.
A lo largo de este documento, se describen de forma progresiva los fundamentos teóricos de la regresión logística, los principales aspectos prácticos a tener en cuenta y ejemplos de cómo crear este tipo de modelos en Python.
Modelos de regresión logística en Python
Dos de las implementaciones de modelos de regresión logística más utilizadas en Python son: scikit-learn y statsmodels. Aunque ambas están muy optimizadas, Scikit-learn está orientada principalmente a la predicción, por lo que no dispone de apenas funcionalidades que muestren las muchas características del modelo que se deben analizar para hacer inferencia. Statsmodels es más completa en este sentido.
Definición matemática
El modelo de regresión lineal (Legendre, Gauss, Galton y Pearson) considera que, dado un conjunto de observaciones , la media de la variable respuesta se relaciona de forma lineal con la o las variables regresoras ... acorde a la ecuación:
El resultado de esta ecuación se conoce como la línea de regresión poblacional, y recoge la relación entre los predictores y la media de la variable respuesta.
Otra definición que se encuentra con frecuencia en los libros de estadística es:
En este caso, se está haciendo referencia al valor de para una observación concreta. El valor de una observación puntual nunca va a ser exactamente igual al promedio, de ahí que se añada el término de error .
En ambos casos, la interpretación de los elementos del modelo es la misma:
: es la ordenada en el origen, se corresponde con el valor promedio de la variable respuesta cuando todos los predictores son cero.
: es el efecto promedio que tiene sobre la variable respuesta el incremento en una unidad de la variable predictora , manteniéndose constantes el resto de variables. Se conocen como coeficientes parciales de regresión.
: es el residuo o error, la diferencia entre el valor observado y el estimado por el modelo. Recoge el efecto de todas aquellas variables que influyen en pero que no se incluyen en el modelo como predictores.
En la gran mayoría de casos, los valores y poblacionales se desconocen, por lo que, a partir de una muestra, se obtienen sus estimaciones y . Ajustar el modelo consiste en estimar, a partir de los datos disponibles, los valores de los coeficientes de regresión que maximizan la verosimilitud (likelihood), es decir, los que dan lugar al modelo que con mayor probabilidad puede haber generado los datos observados.
El método empleado con más frecuencia es el ajuste por mínimos cuadrados ordinarios (OLS), que identifica como mejor modelo la recta (o plano si es regresión múltiple) que minimiza la suma de las desviaciones verticales entre cada dato de entrenamiento y la recta, elevadas al cuadrado.
El término "lineal" en los modelos de regresión hace referencia al hecho de que los parámetros se incorporan en la ecuación de forma lineal, no a que necesariamente la relación entre cada predictor y la variable respuesta tenga que seguir un patrón de recta.
¿Qué ocurre cuando la variable respuesta es binaria, solo dos posibles valores?
Si una variable cualitativa con dos niveles (binaría) se codifica como 0 y 1, matemáticamente es posible ajustar un modelo de regresión lineal por mínimos cuadrados. Sin embargo, esta aproximación tiene dos problemas:
Al generar una recta (hiperplano si hay múltiples variables), se pueden obtener valores predichos distintos de 0 y 1, lo que entra en contradicción con la definición de la variable respuesta binaria.
Si se quiere interpretar las predicciones del modelo como probabilidades de pertenencia a cada clase, no se cumpliría la condición de que toda probabilidad ha de estar dentro del intervalo [0,1], ya que podrían obtenerse valores fuera de este.
Para evitar estos problemas, la regresión logística (David Cox 1958) transforma el valor devuelto por la regresión lineal con una función cuyo resultado siempre está comprendido entre 0 y 1. Existen varias funciones que cumplen esta descripción, una de las más utilizadas es la función logística (también conocida como función sigmoide):
Para valores de positivos muy grandes, es aproximadamente 0, por lo que el valor de la función sigmoide es 1. Para valores de negativos muy grandes, tiende a infinito, por lo que el valor de la función sigmoide es 0.
Sustituyendo la de la ecuación anterior por la función de un modelo lineal se obtiene que:
donde puede interpretarse como la probabilidad de que la variable respuesta adquiera el valor 1 (clase de referencia), dado los predictores .
El modelo resultante tiene los coeficientes de regresión en los exponentes, por lo que no es un modelo lineal y no puede ajustarse con la estrategia descrita al inicio del documento. ¿Cómo evitar este inconveniente?
La expresión obtenida tiene la característica de ser siempre positiva, ya que la función exponencial solo toma valores positivos y, el cociente de valores positivos, es siempre positivo. Esto hace posible aplicarle el logaritmo:
Al realizar la transformación, en el lado derecho se obtiene la ecuación de un modelo lineal. El término de la izquierda resulta ser el logaritmo de un cociente de probabilidades, lo que se conoce como razón de probabilidad (log of odds).
Como resultado de este proceso se consigue convertir un problema de clasificación no lineal, en un problema de regresión lineal que sí puede ajustarse mediante los métodos convencionales.
Una vez obtenidos los coeficientes del modelo () se puede obtener la probabilidad de que una nueva observación pertenezca a la clase con la ecuación:
Modelar el log of odds es la estrategia matemática que permite encontrar los valores de los coeficientes (ajustar el modelo).

En el apartado anterior, se han obviado dos demostraciones importantes con el objetivo de facilitar la narrativa. Sin embargo, es importante tenerlas en cuenta para entender bien el funcionamiento de este tipo de modelos.
Anexo 1
Combinación de la función sigmoide y la ecuación de un modelo lineal para obtener un modelo que relacione los predictores con la probabilidad de que .
Anexo 2
Transformación logarítmica para linealizar el modelo.
La probabilidad de que dado los predictores es:
Al ser un caso de clasificación binaria, la probabilidad de es la probabilidad complementaria:
Si se divide una probabilidad entre otra:
Odds y logaritmo de odds
Debido a las transformaciones necesarias, la regresión logística modela la probabilidad de que la variable respuesta pertenezca al grupo de referencia de forma indirecta mediante el uso del logaritmo de odds. Aunque la mayoría de implementaciones convierten el logaritmo de odds a probabilidades al mostrar las predicciones, conviene conocer su significado.
Supóngase un evento cuya probabilidad de ser verdadero es de 0.8 (). Dado que es una variable binaria, la probabilidad ser falso es de , (). Los odds o razón de probabilidad se definen como el ratio entre la probabilidad de evento verdadero y la probabilidad de evento falso . En este caso los odds son 0.8 / 0.2 = 4, lo que equivale a decir que se esperan 4 eventos verdaderos por cada evento falso.
Dado que las probabilidades están acotadas siempre al rango [0,1], los odds están acotados entre [0,]. Al aplicarles el logaritmo, el rango de valores pasa a ser de [-, +].
Interpretación del modelo
Los principales elementos que hay que interpretar en un modelo de regresión logística son los coeficientes de los predictores:
es la ordenada en el origen o intercept. Se corresponde con el valor esperado del logaritmo de odds cuando todos los predictores son cero. Puede transformarse a probabilidad con la ecuación . Tras la transformación, su valor se corresponde con la probabilidad esperada de pertenecer a la clase 1 cuando todos los predictores son cero.
los coeficientes de regresión parcial de cada predictor indican el cambio promedio del logaritmo de odds al incrementar en una unidad la variable predictora , manteniéndose constantes el resto de variables. Esto equivale a decir que, por cada unidad que se incrementa , se multiplican los odds por .
Dado que la relación entre y no es lineal, los coeficientes de regresión no se corresponden con el cambio en la probabilidad de asociada con el incremento en una unidad de . Cuánto se incremente la probabilidad de por unidad de depende del valor de , es decir, de la posición en la curva logística en la que se encuentre. Esta es una diferencia muy importante respecto a la interpretación de los coeficientes de un modelo de regresión lineal.
La magnitud de cada coeficiente parcial de regresión depende de las unidades en las que se mida la variable predictora a la que corresponde, por lo que su magnitud no está asociada con la importancia de cada predictor. Para poder determinar qué impacto tienen en el modelo cada una de las variables, se emplean los coeficientes parciales estandarizados, que se obtienen al estandarizar (sustraer la media y dividir entre la desviación estándar) las variables predictoras previo ajuste del modelo.
Si bien los coeficientes de regresión suelen ser el primer objetivo de la interpretación de un modelo lineal, existen muchos otros aspectos (significancia del modelo en su conjunto, significancia de los predictores...). Estos últimos suelen ser tratados con poca detalle cuando el único objetivo del modelo es realizar predicciones, sin embargo, son muy relevantes si se quiere realizar inferencia, es decir, explicar las relaciones entre los predictores y la variable respuesta. A lo largo de este documento se irán introduciendo cada uno de ellos.
Significancia del modelo
Likelihood Ratio
Uno de los primeros resultados que hay que evaluar al ajustar un modelo de regresión logística es el resultado del test de significancia likelihood ratio (LLR). Este contraste responde a la pregunta de si el modelo en su conjunto es capaz de predecir la variable respuesta mejor de lo esperado por azar, o lo que es equivalente, si al menos uno de los predictores que forman el modelo contribuye de forma significativa. Para realizar este análisis se compara la probabilidad de obtener los valores observados (log likelihood) con el modelo de interés () frente a las de un modelo sin predictores (modelo nulo ).
El estadístico LLR tiene una distribución chi-cuadrado con grados de libertad equivalentes a la diferencia de grados de libertad de los dos modelos comparados. Si se compara respecto al modelo nulo, los grados de libertad equivalen al número de predictores.
Con frecuencia, la hipótesis nula y alternativa de este test se describen como:
: = ... =
: al menos un
Si el test resulta significativo, implica que el modelo es útil, pero no que sea el mejor. Podría ocurrir que alguno de sus predictores no fuese necesario.
Pseudo R2
A diferencia de los modelos de regresión lineal, en los modelos logísticos no existe un equivalente a que determine exactamente la varianza explicada por el modelo. Se han desarrollado diferentes métodos conocidos como que intentan aproximarse al concepto de pero que, aunque su rango oscila entre 0 y 1, no se pueden considerar equivalentes. El más conocido es el propuesto por McFadden’s:
siendo el valor de likelihood de cada modelo.
tiene valor 0 si el modelo candidato no mejora al modelo nulo, y valor de 1 si se ajusta perfectamente a los datos.
Significancia de los predictores
En la mayoría de casos, aunque el estudio de regresión logística se aplica a una muestra, el objetivo último es obtener un modelo que explique la relación entre las variables en toda la población. Esto significa que, el modelo generado, es una estimación de la relación poblacional a partir de la relación que se observa en la muestra y, por lo tanto, está sujeta a variaciones. Para cada uno de los coeficientes de la ecuación de regresión logística () se puede calcular su significancia (p-value) y su intervalo de confianza. El test estadístico más empleado es el Wald chi-test.
El test de significancia para los coeficientes () del modelo logístico considera como hipótesis:
: el predictor no contribuye al modelo (), en presencia del resto de predictores.
: el predictor sí contribuye al modelo (), en presencia del resto de predictores.
En los modelos generados con statsmodels
se devuelve, junto con el valor de los coeficientes de regresión, el valor del estadístico obtenido para cada uno, los p-value y los intervalos de confianza correspondientes. Esto permite saber, además de las estimaciones, si son significativamente distintos de 0, es decir, si contribuyen al modelo.
Variables categóricas como predictores
Cuando se introduce una variable categórica como predictor, un nivel se considera el de referencia (normalmente codificado como 0) y el resto de niveles se comparan con él. En el caso de que el predictor categórico tenga más de dos niveles, se generan lo que se conoce como variables dummy o one-hot-encodding, que son variables creadas para cada uno de los niveles del predictor categórico y que pueden tomar el valor de 0 o 1. Cada vez que se emplee el modelo para predecir un valor, solo una variable dummy por predictor adquiere el valor 1 (la que coincida con el valor que adquiere el predictor en ese caso) mientras que el resto se consideran 0. El valor del coeficiente parcial de regresión de cada variable dummy indica el porcentaje promedio en el que influye dicho nivel sobre el logaritmo de odds de la variable dependiente en comparación con el nivel de referencia de dicho predictor.
La idea de variables dummy se entiende mejor con un ejemplo. Supóngase un modelo en el que la variable respuesta ojos verdes (si/no) se predice en función de nacionalidad del sujeto. La variable nacionalidad es cualitativa con 3 niveles (americana, europea y asiática). A pesar de que el predictor inicial es nacionalidad, se crea una variable nueva por cada nivel, cuyo valor puede ser 0 o 1. De tal forma que la ecuación del modelo completo es:
Si el sujeto es europeo, las variables dummy americana y asiática se consideran 0, de forma que el modelo para este caso se queda en:
Predicción
Una vez generado un modelo válido, es posible predecir la probabilidad de la variable respuesta para nuevos valores de las variables predictoras . Es importante tener en cuenta que las predicciones deben, a priori, limitarse al rango de valores dentro del que se encuentran las observaciones con las que se ha entrenado el modelo. Esto es importante puesto que, aunque los modelos de regresión logística pueden extrapolarse, solo en esta región se tiene certeza de que se cumplen las condiciones para que el modelo sea válido. Para calcular las predicciones, se emplea la ecuación:
Convertir probabilidad en clasificación
Una de las principales aplicaciones de un modelo de regresión logística es clasificar la variable cualitativa en función del valor que tomen los predictores. Dado que la salida de un modelo logístico es una probabilidad, para conseguir la clasificación, es necesario establecer un límite (threshold) a partir del cual se considera que la variable pertenece a uno de los niveles. Por ejemplo, se puede asignar una observación al grupo 1 si la probabilidad estimada es mayor de 0.5 y al grupo 0 de lo contrario.
Validación del modelo
Una vez seleccionado el mejor modelo que se puede crear con los datos disponibles, se tiene que comprobar su capacidad prediciendo nuevas observaciones que no se hayan empleado para entrenarlo, de este modo se verifica si el modelo se puede generalizar. Una estrategia comúnmente empleada es dividir aleatoriamente los datos en dos grupos, ajustar el modelo con el primer grupo y estimar la precisión de las predicciones con el segundo.
El tamaño adecuado de las particiones depende en gran medida de la cantidad de datos disponibles y la seguridad que se necesite en la estimación del error, 80% 20% suele dar buenos resultados.
Condiciones para la regresión logística
Para que un modelo de regresión logística, y las conclusiones derivadas de él, sean completamente válidas, se deben verificar que se cumplen las asunciones sobre las que se basa su desarrollo matemático. En la práctica, rara vez se cumplen, o se puede demostrar que se cumplen todas, sin embargo esto no significa que el modelo no sea útil. Lo importante es ser consciente de ellas y del impacto que esto tiene en las conclusiones que se extraen del modelo.
No colinealidad o multicolinealidad:
En los modelos de regresión logística múltiple, los predictores deben ser independientes, no debe de haber colinealidad entre ellos. La colinealidad ocurre cuando un predictor está linealmente relacionado con uno o varios de los otros predictores del modelo. Como consecuencia de la colinealidad, no se puede identificar de forma precisa el efecto individual que tiene cada predictor sobre la variable respuesta, lo que se traduce en un incremento de la varianza de los coeficientes de regresión estimados hasta el punto de que resulta imposible establecer su significancia estadística. Además, pequeños cambios en los datos, provocan grandes cambios en las estimaciones de los coeficientes. Si bien la colinealidad propiamente dicha existe solo si el coeficiente de correlación simple o múltiple entre predictores es 1, cosa que raramente ocurre en la realidad, es frecuente encontrar la llamada casi-colinealidad o multicolinealidad no perfecta.
En caso de encontrar colinealidad entre predictores, hay dos posibles soluciones. La primera es excluir uno de los predictores problemáticos intentando conservar el que, a juicio del investigador, está influyendo realmente en la variable respuesta. Esta medida no suele tener mucho impacto en el modelo en cuanto a su capacidad predictiva ya que, al existir colinealidad, la información que aporta uno de los predictores es redundante en presencia del otro. La segunda opción consiste en combinar las variables colineales en un único predictor, aunque con el riesgo de perder su interpretación.
Cuando se intenta establecer relaciones causa-efecto, la colinealidad puede llevar a conclusiones muy erróneas, haciendo creer que una variable es la causa cuando, en realidad, es otra la que está influenciando sobre ese predictor.
Relación lineal entre los predictores numéricos y el logaritmo de odds de la variable respuesta
Cada predictor numérico tiene que estar linealmente relacionado con el logaritmo de odds de la variable respuesta mientras los demás predictores se mantienen constantes, de lo contrario no se deben introducir en el modelo.
No autocorrelación (Independencia)
Los valores de cada observación son independientes de los otros. Esto es especialmente importante de comprobar cuando se trabaja con mediciones temporales. Se recomienda representar los residuos ordenados acorde al tiempo de registro de las observaciones, si existe un cierto patrón hay indicios de autocorrelación. También se puede emplear el test de hipótesis de Durbin-Watson.
Valores atípicos, con alto leverage o influyentes
Es importante identificar observaciones que sean atípicas o que puedan estar influenciando al modelo. La forma más fácil de detectarlas es a través de los residuos.
Tamaño de la muestra
No se trata de una condición de por sí pero, si no se dispone de suficientes observaciones, predictores que no son realmente influyentes podrían parecerlo. Un recomendación frecuente es que el número de observaciones sea como mínimo entre 10 y 20 veces el número de predictores del modelo.
Parsimonia
Este término hace referencia a que, el mejor modelo, es aquel capaz de explicar con mayor precisión la variabilidad observada en la variable respuesta empleando el menor número de predictores, por lo tanto, con menos asunciones.
La gran mayoría de condiciones se verifican utilizando los residuos, por lo tanto, se suele generar primero el modelo y posteriormente validar las condiciones. De hecho, el ajuste de un modelo debe verse como un proceso iterativo en el que se ajusta el modelo, se evalúan sus residuos y se mejora. Así hasta llegar a un modelo óptimo.
Ejemplo regresión logística simple
Un estudio quiere establecer un modelo que permita calcular la probabilidad de obtener matrícula de honor al final del bachillerato en función de la nota que se ha obtenido en matemáticas. La variable matrícula está codificada como 0 si no se tiene matrícula y 1 si se tiene.
Librerías
Las librerías utilizadas en este ejemplo son:
# Tratamiento de datos
# ==============================================================================
import pandas as pd
import numpy as np
# Gráficos
# ==============================================================================
import matplotlib.pyplot as plt
from matplotlib import style
import seaborn as sns
# Preprocesado y modelado
# ==============================================================================
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import statsmodels.api as sm
import statsmodels.formula.api as smf
from statsmodels.stats.weightstats import ttest_ind
# Configuración matplotlib
# ==============================================================================
plt.rcParams['image.cmap'] = "bwr"
plt.rcParams['savefig.bbox'] = "tight"
style.use('ggplot') or plt.style.use('ggplot')
# Configuración warnings
# ==============================================================================
import warnings
warnings.filterwarnings('once')
Datos
# Datos
# ==============================================================================
matricula = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1,
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1,
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0,
1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1,
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 0, 0, 1, 1])
matematicas = np.array([
41, 53, 54, 47, 57, 51, 42, 45, 54, 52, 51, 51, 71, 57, 50, 43,
51, 60, 62, 57, 35, 75, 45, 57, 45, 46, 66, 57, 49, 49, 57, 64,
63, 57, 50, 58, 75, 68, 44, 40, 41, 62, 57, 43, 48, 63, 39, 70,
63, 59, 61, 38, 61, 49, 73, 44, 42, 39, 55, 52, 45, 61, 39, 41,
50, 40, 60, 47, 59, 49, 46, 58, 71, 58, 46, 43, 54, 56, 46, 54,
57, 54, 71, 48, 40, 64, 51, 39, 40, 61, 66, 49, 65, 52, 46, 61,
72, 71, 40, 69, 64, 56, 49, 54, 53, 66, 67, 40, 46, 69, 40, 41,
57, 58, 57, 37, 55, 62, 64, 40, 50, 46, 53, 52, 45, 56, 45, 54,
56, 41, 54, 72, 56, 47, 49, 60, 54, 55, 33, 49, 43, 50, 52, 48,
58, 43, 41, 43, 46, 44, 43, 61, 40, 49, 56, 61, 50, 51, 42, 67,
53, 50, 51, 72, 48, 40, 53, 39, 63, 51, 45, 39, 42, 62, 44, 65,
63, 54, 45, 60, 49, 48, 57, 55, 66, 64, 55, 42, 56, 53, 41, 42,
53, 42, 60, 52, 38, 57, 58, 65])
datos = pd.DataFrame({'matricula': matricula, 'matematicas': matematicas})
datos.head(3)
matricula | matematicas | |
---|---|---|
0 | 0 | 41 |
1 | 0 | 53 |
2 | 0 | 54 |
Exploración gráfica
El primer paso antes de generar un modelo de regresión logística simple es representar los datos para poder intuir si existe una relación entre la variable independiente y la variable respuesta.
# Número de obsercaciones por clase
# ==============================================================================
datos.matricula.value_counts().sort_index()
matricula 0 151 1 49 Name: count, dtype: int64
# Gráfico
# ==============================================================================
fig, ax = plt.subplots(figsize=(6, 3.84))
sns.violinplot(
x = 'matricula',
y = 'matematicas',
data = datos,
ax = ax
)
ax.set_title('Distribución notas de matemáticas por clase');
# T-test entre clases
# ==============================================================================
res_ttest = ttest_ind(
x1 = matematicas[matricula == 0],
x2 = matematicas[matricula == 1],
alternative='two-sided'
)
print(f"t={res_ttest[0]}, p-value={res_ttest[1]}")
t=-8.245421127756739, p-value=2.248243794123437e-14
Tanto el gráfico como el t-test muestran evidencias de que existe una diferencia entre la nota de las personas con matrícula y sin matrícula. Esta información es útil para considerar la nota de matemáticas como un buen predictor para el modelo.
Ajuste del modelo
Se ajusta un modelo empleando como variable respuesta matricula
y como predictor matematicas
. Como en todo estudio predictivo, no solo es importante ajustar el modelo, sino también cuantificar su capacidad para predecir nuevas observaciones. Para poder hacer esta evaluación, se dividen los datos en dos grupos, uno de entrenamiento y otro de test.
Scikit-learn
# División de los datos en train y test
# ==============================================================================
X = datos[['matematicas']]
y = datos['matricula']
X_train, X_test, y_train, y_test = train_test_split(
X.values,
y.values,
train_size = 0.8,
random_state = 1234,
shuffle = True
)
# Creación del modelo
# ==============================================================================
# Para no incluir ningún tipo de regularización en el modelo se indica
# penalty='none'
modelo = LogisticRegression(penalty=None)
modelo.fit(X = X_train, y = y_train.ravel())
LogisticRegression(penalty=None)In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
Parameters
penalty | None | |
dual | False | |
tol | 0.0001 | |
C | 1.0 | |
fit_intercept | True | |
intercept_scaling | 1 | |
class_weight | None | |
random_state | None | |
solver | 'lbfgs' | |
max_iter | 100 | |
multi_class | 'deprecated' | |
verbose | 0 | |
warm_start | False | |
n_jobs | None | |
l1_ratio | None |
# Información del modelo
# ==============================================================================
print("Intercept:", modelo.intercept_)
print("Coeficiente:", list(zip(X.columns, modelo.coef_.flatten(), )))
print("Accuracy de entrenamiento:", modelo.score(X_train, y_train))
Intercept: [-8.98479044] Coeficiente: [('matematicas', np.float64(0.14393266992917017))] Accuracy de entrenamiento: 0.79375
Una vez entrenado el modelo, se pueden predecir nuevas observaciones.
# Predicciones probabilísticas
# ==============================================================================
# Con .predict_proba() se obtiene, para cada observación, la probabilidad predicha
# de pertenecer a cada una de las dos clases.
predicciones = modelo.predict_proba(X = X_test)
predicciones = pd.DataFrame(predicciones, columns = modelo.classes_)
predicciones.head(3)
0 | 1 | |
---|---|---|
0 | 0.685816 | 0.314184 |
1 | 0.838109 | 0.161891 |
2 | 0.443517 | 0.556483 |
# Predicciones con clasificación final
# ==============================================================================
# Con .predict() se obtiene, para cada observación, la clasificación predicha por
# el modelo. Esta clasificación se corresponde con la clase con mayor probabilidad.
predicciones = modelo.predict(X = X_test)
predicciones
array([0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
Statsmodels
La implementación de regresión logística de Statsmodels, es más completa que la de Scikitlearn ya que, además de ajustar el modelo, permite calcular los test estadísticos y análisis necesarios para verificar que se cumplen las condiciones sobre las que se basa este tipo de modelos. Statsmodels tiene dos formas de entrenar el modelo:
Indicando la fórmula del modelo y pasando los datos de entrenamiento como un dataframe que incluye la variable respuesta y los predictores. Esta forma es similar a la utilizada en R.
Pasar dos matrices, una con los predictores y otra con la variable respuesta. Esta es igual a la empleada por Scikitlearn con la diferencia de que a la matriz de predictores hay que añadirle una primera columna de 1s.
# División de los datos en train y test
# ==============================================================================
X = datos[['matematicas']]
y = datos['matricula']
X_train, X_test, y_train, y_test = train_test_split(
X.values,
y.values,
train_size = 0.8,
random_state = 1234,
shuffle = True
)
# Creación del modelo utilizando matrices como en scikitlearn
# ==============================================================================
# A la matriz de predictores se le tiene que añadir una columna de 1s para el intercept del modelo
X_train = sm.add_constant(X_train, prepend=True)
modelo = sm.Logit(endog=y_train, exog=X_train,)
modelo = modelo.fit()
print(modelo.summary())
Optimization terminated successfully. Current function value: 0.451215 Iterations 6 Logit Regression Results ============================================================================== Dep. Variable: y No. Observations: 160 Model: Logit Df Residuals: 158 Method: MLE Df Model: 1 Date: Mon, 18 Aug 2025 Pseudo R-squ.: 0.2247 Time: 10:42:49 Log-Likelihood: -72.194 converged: True LL-Null: -93.122 Covariance Type: nonrobust LLR p-value: 9.831e-11 ============================================================================== coef std err z P>|z| [0.025 0.975] ------------------------------------------------------------------------------ const -8.9848 1.543 -5.821 0.000 -12.010 -5.960 x1 0.1439 0.027 5.387 0.000 0.092 0.196 ==============================================================================
El coeficiente estimado para la intersección (Intercept o const) es el valor esperado del logaritmo de odds de que un estudiante obtenga matrícula teniendo un 0 en matemáticas. Como cabría imaginar, los odds son muy bajos , lo que se corresponde con una probabilidad de obtener matrícula de .
Acorde al modelo, el logaritmo de odds de que un estudiante tenga matrícula está positivamente relacionado con la puntuación obtenida en matemáticas (coeficiente de regresión = 0.1439). Esto significa que, por cada unidad que se incrementa la variable matemáticas, se espera que el logaritmo de odds de la variable matrícula se incremente en promedio 0.1439 unidades. Aplicando la inversa del logaritmo natural () se obtiene que, por cada unidad que se incrementa la variable matemáticas, los odds de obtener matrícula se incremente en promedio 1.169 unidades. No hay que confundir esto último con que la probabilidad de matrícula se incremente un 1.169 %.
A diferencia de la regresión lineal en la que se corresponde con el cambio promedio en la variable dependiente debido al incremento en una unidad del predictor , en regresión logística, indica el cambio en el logaritmo de odds debido al incremento en una unidad de , o lo que es lo mismo, multiplica los odds por . Dado que la relación entre y no es lineal, los coeficientes de regresión no se corresponden con el cambio en la probabilidad de asociada con el incremento en una unidad de . Cuánto se incremente la probabilidad de por unidad de depende del valor de , es decir, de la posición en la curva logística en la que se encuentre.
Además del valor de las estimaciones de los coeficientes parciales de correlación del modelo, es conveniente calcular sus correspondientes intervalos de confianza.
Intervalos de confianza de los coeficientes
# Intervalos de confianza para los coeficientes del modelo
# ==============================================================================
intervalos_ci = modelo.conf_int(alpha=0.05)
intervalos_ci = pd.DataFrame(intervalos_ci, columns = ['2.5%', '97.5%'])
intervalos_ci
2.5% | 97.5% | |
---|---|---|
0 | -12.009997 | -5.959608 |
1 | 0.091564 | 0.196301 |
Predicciones
Una vez entrenado el modelo, se pueden obtener predicciones para nuevos datos. Los modelos de regresión logística de statsmodels devuelven la probabilidad de pertenecer a la clase de referencia.
# Predicción de probabilidades
# ==============================================================================
predicciones = modelo.predict(exog = X_train)
predicciones[:4]
array([0.0437907 , 0.52073 , 0.05755755, 0.72042378])
Para obtener la clasificación final, se convierten los valores de probabilidad mayores de 0.5 a 1 y los mejores a 0.
# Clasificación predicha
# ==============================================================================
clasificacion = np.where(predicciones<0.5, 0, 1)
clasificacion
array([0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
Representación gráfica del modelo
Además de la línea de mínimos cuadrados, es recomendable incluir los límites superior e inferior del intervalo de confianza. Esto permite identificar la región en la que, según el modelo generado y para un determinado nivel de confianza, se encuentra el valor promedio de la variable respuesta.
# Predicciones en todo el rango de X
# ==============================================================================
# Se crea un vector con nuevos valores interpolados en el rango de observaciones.
grid_X = np.linspace(
start = min(datos.matematicas),
stop = max(datos.matematicas),
num = 200
).reshape(-1,1)
grid_X = sm.add_constant(grid_X, prepend=True)
predicciones = modelo.predict(exog = grid_X)
# Gráfico del modelo
# ==============================================================================
fig, ax = plt.subplots(figsize=(6, 3.84))
ax.scatter(
X_train[(y_train == 1).flatten(), 1],
y_train[(y_train == 1).flatten()].flatten()
)
ax.scatter(
X_train[(y_train == 0).flatten(), 1],
y_train[(y_train == 0).flatten()].flatten()
)
ax.plot(grid_X[:, 1], predicciones, color = "gray")
ax.set_title("Modelo regresión logística")
ax.set_ylabel("P(matrícula = 1 | matemáticas)")
ax.set_xlabel("Nota matemáticas");
Accuracy de test
Se calcula el porcentaje de aciertos que tiene el modelo al predecir las observaciones de test (accuracy).
# Accuracy de test del modelo
# ==============================================================================
X_test = sm.add_constant(X_test, prepend=True)
predicciones = modelo.predict(exog = X_test)
clasificacion = np.where(predicciones<0.5, 0, 1)
accuracy = accuracy_score(
y_true = y_test,
y_pred = clasificacion,
normalize = True
)
print("")
print(f"El accuracy de test es: {100*accuracy}%")
El accuracy de test es: 87.5%
Conclusión
El modelo logístico creado para predecir la probabilidad de que un alumno obtenga matrícula de honor a partir de la nota de matemáticas es en conjunto significativo (Likelihood ratio p-value = 9.831e-11). El p-value del predictor matemáticas es significativo (p-value = 7.17e-08).
Los resultados obtenidos con el conjunto de test indican que el modelo es capaz de clasificar correctamente el 87.5% de las observaciones.
Ejemplo regresión logística múltiple
El set de datos spam, obtenido de UCI Repository Of Machine Learning Databases contiene información sobre 4601 correos electrónicos clasificados como spam y no spam.
Para cada correo electrónico se dispone de 58 variables: las 48 primeras contienen la frecuencia con la que aparecen en el texto del email determinadas palabras. Las variables 49-54 indican la frecuencia con la que aparecen los caracteres ;’, ‘(’, ‘[’, ‘!’, ‘$’, ‘#’. Las variables 55-57 contienen la media, a longitud máxima y el número total de letras mayúsculas.
Se crear un modelo de regresión logística con el objetivo de clasificar si un correo es spam o no.
Librerías
Las librerías utilizadas en este ejemplo son:
# Tratamiento de datos
# ==============================================================================
import pandas as pd
import numpy as np
# Gráficos
# ==============================================================================
import matplotlib.pyplot as plt
from matplotlib import style
import seaborn as sns
# Preprocesado y modelado
# ==============================================================================
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.metrics import ConfusionMatrixDisplay
import statsmodels.api as sm
import statsmodels.formula.api as smf
# Configuración matplotlib
# ==============================================================================
plt.rcParams['image.cmap'] = "bwr"
plt.rcParams['savefig.bbox'] = "tight"
style.use('ggplot') or plt.style.use('ggplot')
# Configuración warnings
# ==============================================================================
import warnings
warnings.filterwarnings('ignore')
Datos
# Datos
# ==============================================================================
url = (
'https://raw.githubusercontent.com/JoaquinAmatRodrigo/'
'Estadistica-machine-learning-python/master/data/spam.csv'
)
datos = pd.read_csv(url)
datos.head(3)
make | address | all | num3d | our | over | remove | internet | order | ... | charSemicolon | charRoundbracket | charSquarebracket | charExclamation | charDollar | charHash | capitalAve | capitalLong | capitalTotal | type | ||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0.00 | 0.64 | 0.64 | 0.0 | 0.32 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.000 | 0.0 | 0.778 | 0.000 | 0.000 | 3.756 | 61 | 278 | spam |
1 | 0.21 | 0.28 | 0.50 | 0.0 | 0.14 | 0.28 | 0.21 | 0.07 | 0.00 | 0.94 | ... | 0.00 | 0.132 | 0.0 | 0.372 | 0.180 | 0.048 | 5.114 | 101 | 1028 | spam |
2 | 0.06 | 0.00 | 0.71 | 0.0 | 1.23 | 0.19 | 0.19 | 0.12 | 0.64 | 0.25 | ... | 0.01 | 0.143 | 0.0 | 0.276 | 0.184 | 0.010 | 9.821 | 485 | 2259 | spam |
3 rows × 58 columns
Se codifica la variable respuesta como 1 si es spam y 0 si no lo es, y se identifica cuantas observaciones hay de cada clase.
datos['type'] = np.where(datos['type'] == 'spam', 1, 0)
print("Número de observaciones por clase")
print(datos['type'].value_counts())
print("")
print("Porcentaje de observaciones por clase")
print(100 * datos['type'].value_counts(normalize=True))
Número de observaciones por clase type 0 2788 1 1813 Name: count, dtype: int64 Porcentaje de observaciones por clase type 0 60.595523 1 39.404477 Name: proportion, dtype: float64
El 66.6% de los correos no son spam y el 39.4% sí lo son. Un modelo de clasificación que sea útil debe de ser capaz de predecir correctamente un porcentaje de observaciones por encima del porcentaje de la clase mayoritaria. En este caso, el umbral de referencia que se tiene que superar es del 66.6%.
Ajuste del modelo
Se ajusta un modelo de regresión logística múltiple con el objetivo de predecir si un correo es spam en función de todas las variables disponibles.
# División de los datos en train y test
# ==============================================================================
X = datos.drop(columns = 'type')
y = datos['type']
X_train, X_test, y_train, y_test = train_test_split(
X,
y.values,
train_size = 0.8,
random_state = 1234,
shuffle = True
)
# Creación del modelo utilizando matrices como en scikitlearn
# ==============================================================================
# A la matriz de predictores se le tiene que añadir una columna de 1s para el intercept del modelo
X_train = sm.add_constant(X_train, prepend=True)
modelo = sm.Logit(endog=y_train, exog=X_train,)
modelo = modelo.fit()
print(modelo.summary())
Optimization terminated successfully. Current function value: 0.200751 Iterations 15 Logit Regression Results ============================================================================== Dep. Variable: y No. Observations: 3680 Model: Logit Df Residuals: 3622 Method: MLE Df Model: 57 Date: Mon, 18 Aug 2025 Pseudo R-squ.: 0.7009 Time: 10:42:50 Log-Likelihood: -738.76 converged: True LL-Null: -2469.6 Covariance Type: nonrobust LLR p-value: 0.000 ===================================================================================== coef std err z P>|z| [0.025 0.975] ------------------------------------------------------------------------------------- const -1.5530 0.156 -9.956 0.000 -1.859 -1.247 make -0.3077 0.255 -1.205 0.228 -0.808 0.193 address -0.1464 0.079 -1.860 0.063 -0.301 0.008 all 0.0882 0.125 0.705 0.481 -0.157 0.333 num3d 2.2531 1.454 1.550 0.121 -0.596 5.103 our 0.7254 0.128 5.682 0.000 0.475 0.976 over 0.7286 0.255 2.859 0.004 0.229 1.228 remove 1.9991 0.332 6.022 0.000 1.348 2.650 internet 0.5267 0.183 2.884 0.004 0.169 0.885 order 0.6556 0.316 2.076 0.038 0.037 1.274 mail 0.0833 0.075 1.106 0.269 -0.064 0.231 receive -0.1917 0.333 -0.576 0.565 -0.844 0.461 will -0.1788 0.087 -2.050 0.040 -0.350 -0.008 people -0.1835 0.251 -0.732 0.464 -0.675 0.308 report 0.1589 0.156 1.016 0.310 -0.148 0.466 addresses 1.0691 0.710 1.507 0.132 -0.322 2.460 free 1.0272 0.163 6.309 0.000 0.708 1.346 business 1.0484 0.258 4.059 0.000 0.542 1.555 email 0.0832 0.131 0.634 0.526 -0.174 0.340 you 0.0760 0.040 1.894 0.058 -0.003 0.155 credit 1.4274 0.750 1.903 0.057 -0.043 2.897 your 0.2196 0.057 3.826 0.000 0.107 0.332 font 0.2320 0.192 1.208 0.227 -0.144 0.608 num000 2.3195 0.540 4.296 0.000 1.261 3.378 money 0.3512 0.146 2.403 0.016 0.065 0.638 hp -1.8795 0.320 -5.880 0.000 -2.506 -1.253 hpl -1.1604 0.486 -2.387 0.017 -2.113 -0.207 george -12.9370 2.497 -5.182 0.000 -17.830 -8.044 num650 0.4662 0.208 2.243 0.025 0.059 0.874 lab -3.9850 2.593 -1.537 0.124 -9.067 1.097 labs -0.1316 0.342 -0.385 0.700 -0.801 0.538 telnet 1.0132 0.884 1.146 0.252 -0.720 2.746 num857 2.3901 3.536 0.676 0.499 -4.541 9.321 data -0.7578 0.363 -2.086 0.037 -1.470 -0.046 num415 0.8594 1.678 0.512 0.608 -2.429 4.147 num85 -1.9348 0.870 -2.225 0.026 -3.639 -0.231 technology 0.8951 0.354 2.529 0.011 0.201 1.589 num1999 0.0493 0.204 0.241 0.809 -0.351 0.449 parts 1.9359 1.232 1.571 0.116 -0.480 4.351 pm -0.9294 0.464 -2.001 0.045 -1.840 -0.019 direct -0.3704 0.432 -0.857 0.391 -1.217 0.477 cs -43.9842 27.447 -1.603 0.109 -97.779 9.811 meeting -3.0673 0.988 -3.104 0.002 -5.004 -1.130 original -0.8759 0.810 -1.082 0.279 -2.463 0.711 project -1.6666 0.583 -2.858 0.004 -2.809 -0.524 re -0.8289 0.171 -4.856 0.000 -1.163 -0.494 edu -1.1653 0.268 -4.355 0.000 -1.690 -0.641 table -2.0108 1.691 -1.189 0.234 -5.326 1.304 conference -5.0363 2.136 -2.358 0.018 -9.223 -0.850 charSemicolon -1.2001 0.491 -2.443 0.015 -2.163 -0.237 charRoundbracket -0.2822 0.278 -1.015 0.310 -0.827 0.263 charSquarebracket -0.8608 1.059 -0.813 0.416 -2.937 1.215 charExclamation 0.2735 0.072 3.798 0.000 0.132 0.415 charDollar 5.7530 0.836 6.880 0.000 4.114 7.392 charHash 1.4144 1.287 1.099 0.272 -1.108 3.936 capitalAve 0.0389 0.021 1.842 0.066 -0.002 0.080 capitalLong 0.0048 0.003 1.799 0.072 -0.000 0.010 capitalTotal 0.0014 0.000 5.068 0.000 0.001 0.002 ===================================================================================== Possibly complete quasi-separation: A fraction 0.28 of observations can be perfectly predicted. This might indicate that there is complete quasi-separation. In this case some parameters will not be identified.
Predicciones
Una vez entrenado el modelo, se pueden obtener predicciones para nuevos datos. Los modelos de statsmodels permiten calcular los intervalos de confianza asociados a cada predicción.
# Predicciones con intervalo de confianza
# ==============================================================================
predicciones = modelo.predict(exog = X_train)
# Clasificación predicha
# ==============================================================================
clasificacion = np.where(predicciones<0.5, 0, 1)
clasificacion
array([0, 0, 0, ..., 1, 1, 0], shape=(3680,))
Accuracy de test
Se calcula el porcentaje de aciertos que tiene el modelo al predecir las observaciones de test (accuracy).
# Accuracy de test del modelo
# ==============================================================================
X_test = sm.add_constant(X_test, prepend=True)
predicciones = modelo.predict(exog = X_test)
clasificacion = np.where(predicciones<0.5, 0, 1)
accuracy = accuracy_score(
y_true = y_test,
y_pred = clasificacion,
normalize = True
)
print("")
print(f"El accuracy de test es: {100*accuracy}%")
El accuracy de test es: 92.83387622149837%
# Matriz de confusión de las predicciones de test
# ==============================================================================
confusion_matrix = pd.crosstab(
y_test.ravel(),
clasificacion,
rownames=['Real'],
colnames=['Predicción']
)
confusion_matrix
Predicción | 0 | 1 |
---|---|---|
Real | ||
0 | 535 | 28 |
1 | 38 | 320 |
Conclusión
El modelo logístico creado para predecir la probabilidad de que un correo sea spam es en conjunto significativo (Likelihood ratio p-value = 0). El porcentaje de clasificación correcta en el conjunto del test es del 92.8%, un valor muy por encima del umbral de 66.6% esperado por azar.
Acorde al p-value individual de cada predictor, solo algunos de ellos aportan información al modelo. Es conveniente identificar cuáles son y excluirlos para simplificar el modelo y evitar la introducción de ruido. Una forma de conseguir reducir la influencia de predictores que no aportan a un modelo de regresión logística es incorporar regularización en su ajuste.
Información de sesión
import session_info
session_info.show(html=False)
----- matplotlib 3.10.1 numpy 2.2.6 pandas 2.3.1 seaborn 0.13.2 session_info v1.0.1 sklearn 1.7.1 statsmodels 0.14.4 ----- IPython 9.1.0 jupyter_client 8.6.3 jupyter_core 5.7.2 jupyterlab 4.4.5 notebook 7.4.5 ----- Python 3.12.9 | packaged by Anaconda, Inc. | (main, Feb 6 2025, 18:56:27) [GCC 11.2.0] Linux-6.14.0-27-generic-x86_64-with-glibc2.39 ----- Session information updated at 2025-08-18 10:42
Bibliografía
An Introduction to Statistical Learning: with Applications in R (Springer Texts in Statistics)
Linear Models with R, Julian J.Faraway
OpenIntro Statistics: Third Edition, David M Diez, Christopher D Barr, Mine Çetinkaya-Rundel
Points of Significance: Logistic regression by Jake Lever, Martin Krzywinski & Naomi Altman
Instrucciones para citar
¿Cómo citar este documento?
Si utilizas este documento o alguna parte de él, te agradecemos que lo cites. ¡Muchas gracias!
Regresión logística con Python por Joaquín Amat Rodrigo, disponible bajo una licencia Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0 DEED) en https://cienciadedatos.net/documentos/py17-regresion-logistica-python.html
¿Te ha gustado el artículo? Tu ayuda es importante
Tu contribución me ayudará a seguir generando contenido divulgativo gratuito. ¡Muchísimas gracias! 😊
Este documento creado por Joaquín Amat Rodrigo y Javier Escobar Ortiz tiene licencia Attribution-NonCommercial-ShareAlike 4.0 International.
Se permite:
-
Compartir: copiar y redistribuir el material en cualquier medio o formato.
-
Adaptar: remezclar, transformar y crear a partir del material.
Bajo los siguientes términos:
-
Atribución: Debes otorgar el crédito adecuado, proporcionar un enlace a la licencia e indicar si se realizaron cambios. Puedes hacerlo de cualquier manera razonable, pero no de una forma que sugiera que el licenciante te respalda o respalda tu uso.
-
No-Comercial: No puedes utilizar el material para fines comerciales.
-
Compartir-Igual: Si remezclas, transformas o creas a partir del material, debes distribuir tus contribuciones bajo la misma licencia que el original.