TUTORIAL 6
Lenguaje de programación: Python
Autor: José Gerardo Carrillo González
Contenido
Regresión .....................................................................................................................................2
Regresión lineal simple...............................................................................................................2
Ejemplo de regresión lineal simple ...........................................................................................3
Regresión lineal múltiple ............................................................................................................7
Ejemplo de Regresión lineal múltiple ........................................................................................7
Regresión polinomial ............................................................................................................... 10
Ejemplo de Regresión polinomial ........................................................................................... 11
Función exponencial ................................................................................................................ 14
Ejemplo .............................................................................................................................. 15
Subajuste (underfitting) y sobreajuste (overfitting) ....................................................................... 16
Ejemplo de subajuste ............................................................................................................ 20
Ejemplo de sobreajuste.......................................................................................................... 21
Dividir datos para entrenar y evaluar un modelo .......................................................................... 22
Ejemplo de dividir datos........................................................................................................ 23
Regresión logística ................................................................................................................... 24
Ejemplo de Regresión logística .............................................................................................. 26
Regresión
Una regresión trata de explicar por medio de una función la relación que existe entre variables, por
lo general una o varias variables independientes y una dependiente. Llamaremos a las variables
independientes como entradas, regresores o predictores. Llamaremos a la variable dependiente
como salida o respuesta. Por simplicidad, podemos usar y para referirnos a la variable dependiente
y x para referirnos a la variable independiente, sin embargo, si hay dos o más variables
independientes se pueden representar con el vector 𝑥 = (𝑥1 , … , 𝑥𝑚 ), con m siendo el número de
variables independientes.
Si existe una relación entre la variable dependiente y las independientes podemos expresarla así,
𝑓(𝑥1 , … , 𝑥𝑚 ) = 𝑏0 + 𝑏1 𝑥1 + ⋯ + 𝑏𝑚 𝑥𝑚
Lo que hace la regresión es calcular el valor de los coeficientes, de modo que la relación que existe
entre la salida y las entradas es capturada por la función. La regresión calculará el valor de los
coeficientes de modo que los residuales, es decir, las diferencias 𝑦 𝑖 − 𝑓(𝑥1𝑖 … 𝑥𝑚
𝑖
), con 𝑖 = 1 … 𝑛,
siendo n el número de observaciones, sean lo menor posible. Entonces, para obtener el valor de
los coeficientes se busca minimizar la sumatoria de los residuales al cuadrado (SSR), es decir,
𝑛
𝑆𝑆𝑅 = ∑ (𝑦 𝑖 − 𝑓(𝑥1𝑖 … 𝑥𝑚
𝑖
))2
𝑖=1
A este método se le conoce como el método de mínimos cuadrados ordinarios. El coeficiente de
determinación 𝑅 2 nos dirá la cantidad de la variación de y que puede ser explicada por la
dependencia que existe con x. Por lo que entre más alto el valor de 𝑅 2 , el modelo está explicando
mejor la variación de la salida con las entradas seleccionadas. Si obtenemos 𝑅 2 = 1, se tendría
que 𝑆𝑆𝑅 = 0, por lo que para todos los valores de i se tendría que 𝑓(𝑥1𝑖 … 𝑥𝑚 𝑖
) = 𝑦 𝑖 . La formula
del coeficiente de determinación es,
2
∑𝑛𝑖=1(𝑦 𝑖 − 𝑓(𝑥1𝑖 … 𝑥𝑚𝑖
))2
𝑅 =1−
∑𝑛𝑖=1(𝑦 𝑖 − 𝑦̅)2
Siendo 𝑦̅ el promedio de las observaciones de salida.
Regresión lineal simple
La regresión lineal simple es el caso más sencillo de regresión lineal ya que tendremos una sola
variable independiente, por lo que nuestro modelo será,
𝑓(𝑥) = 𝑏 + 𝑚𝑥
a b se le conoce como intercepto y es el punto en donde la recta estimada cruza con el eje-y, es el
valor de 𝑓(𝑥) cuando 𝑥 = 0. m establece la pendiente de la recta estimada,
𝑐𝑎𝑚𝑏𝑖𝑜 𝑣𝑒𝑟𝑡𝑖𝑐𝑎𝑙 ∆𝑦 𝑦2 − 𝑦1
𝑚= = =
𝑐𝑎𝑚𝑏𝑖𝑜 ℎ𝑜𝑟𝑖𝑧𝑜𝑛𝑎𝑙 ∆𝑥 𝑥2 − 𝑥1
Imagen tomada de [Link]
Ejemplo de regresión lineal simple
Importaremos NumPy (biblioteca para trabajar con arreglos), scikit-learn (biblioteca de
aprendizaje automático), y statsmodels (biblioteca para la estimación de modelos estadísticos).
Las tres bibliotecas antes mencionadas son de código abierto. Además, importaremos matplotlib,
que es una librería para graficar. Primero importamos las librerías,
import numpy as np
from sklearn.linear_model import LinearRegression
import [Link] as plt
Introducimos los datos con los que vamos a trabajar. La entrada x y la salida y serán arreglos:
x = [Link]([1,2,3,4,5,6,7,8,9]).reshape((-1, 1))
y = [Link]([1.1,2.5,3.4,4.8,5.7,6.3,7.9,8.8,9.2])
El método reshape(-1,1) es para indicar que el arreglo tendrá tantos renglones como se necesiten
y una columna. Las dimensiones de x se pueden obtener con [Link], lo que nos daría (9,1), [Link]
nos da (9,). Creamos una instancia de la clase Linear Regression, esta variable representará el
modelo de regresión,
model = LinearRegression()
Los parámetros de LinearRegression son:
fit_intercept es un valor booleano que si se establece como True calcula el intercepto b, si False,
𝑏 = 0. Por default es True.
normalize es un valor booleano que si se estable como True normaliza las variables de entrada, si
False, no lo hace. Por default es False.
copy_X es un valor booleano que si se establece como True copia las variables de entrada, si False,
las sobrescribe. Por default es True.
n_jobs se especifica como un entero o como None. Es el número de procesadores que se usaran
en computación paralela. Por default es None, que usualmente sería un procesador. Con -1 se
indica usar todos los procesadores disponibles.
Como no especificamos el valor de ningún parámetro, el objeto model queda con los parámetros
por default. Para calcular los valores óptimos de los coeficientes escribimos,
[Link](x, y)
Pasamos la entrada y la salida como argumentos. La instrucción anterior regresa self, que es el
objeto model. Es posible combinar las últimas dos instrucciones en una sola,
model = LinearRegression().fit(x, y)
El coeficiente de determinación se obtiene con el método score(), que recibe como argumentos la
entrada y la salida,
r_sq = [Link](x, y)
print(f"Coeficiente de determinación = {r_sq}")
Los atributos de model son b, que se obtiene con intercept_, y m, que se obtiene con coef_,
print(f"intercepto = {model.intercept_}")
print(f"pendiente = {model.coef_}")
Tenemos que model.intercept_ es un escalar y model.coef_ es un arreglo de clase [Link].
Por convención, en scikit-learn se tiene que un atributo que finaliza con guion bajo indica que fue
un valor estimado. Como en el ejemplo 𝑚 = 1.03, significa que cuando x aumenta en una unidad,
y lo hará por 1.03 veces. Entonces, los valores modelados los guardamos de la siguiente manera,
y_mod = [Link](x)
Una vez que tenemos nuestro modelo lo podemos usar para hacer predicciones, es decir, calcular
f(x) para valores de entrada para los que no tenemos observaciones de salida. Podemos definir un
vector con valores de 𝑥 para los cuales queremos conocer f(x),
x_new= [Link]([1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5]).reshape((-1, 1))
y_ new = [Link](x_ new)
print(f"La respuesta es:\n{y_ new }")
Otra forma de calcular f(x) es
y_ new = model.intercept_ + model.coef_ * x_ new
Para graficar es necesario importar [Link], que es una interface a matplotlib. Podemos
visualizar las observaciones en negro, los valores modelados en azul, y las predicciones en rojo,
de la siguiente manera,
[Link](x, y, color = 'black', s=10)
[Link](x, y_mod, color = 'blue', s=10)
[Link](x_new, y_new, color = 'red', s=10)
[Link]('Regresión lineal simple')
[Link]('La variable independiente')
[Link]('La variable dependiente')
[Link](['observado', 'modelado', 'predicción'])
[Link]()
[Link]()
El argumento s es para especificar el tamaño del marcador; el argumento color es para especificar
el color del marcador. Las instrucciones anteriores nos entregan la siguiente gráfica,
Un residual es la diferencia entre una observación (punto negro) y un valor modelado (punto azul).
Las predicciones son los puntos rojos, estos son los valores f(x) para los valores de x que no tienen
un valor y asociado (no hay observación). El código completo a continuación,
Regresión lineal múltiple
La ecuación para hacer una regresión lineal múltiple con m variables independientes es,
𝑓(𝑥1 , … , 𝑥𝑚 ) = 𝑏0 + 𝑏1 𝑥1 + ⋯ + 𝑏𝑚 𝑥𝑚
donde se puede observar que para m variables independientes se tienen que estimar m+1
coeficientes, la estimación de los coeficientes busca minimizar la SSR.
Ejemplo de Regresión lineal múltiple
Importamos las librerías que necesitamos,
import numpy as np
from sklearn.linear_model import LinearRegression
import [Link] as plt
from [Link] import pearsonr
Creamos el vector con los valores de las variables independientes (dos en este caso) y el vector
con los valores de la variable dependiente,
x = [[10, 25], [20, 77], [30, 114], [40, 189], [50, 213], [60, 262], [70, 328], [80, 371],[90, 453]]
y = [2,4,8,16,32,64,128,256,512]
El vector que contiene los valores de las variables independientes debe ser de clase [Link],
por lo que hacemos la conversión,
x= [Link](x)
Para fines de graficar, creamos un vector que funcionara como índice,
ind=[]
for i in range(len(y))
[Link](i+1)
El coeficiente de correlación de Pearson (r) nos sirve para determinar si existe correlación lineal
entre dos variables. r varía entre -1 a 1, con 0 indicando que no existe correlación. Se tiene que un
+1 indica una correlación positiva perfecta y -1 indica una correlación negativa perfecta. Una
correlación positiva implica que a medida que x aumenta, y aumenta, o bien a medida que x
disminuye, y disminuye; una correlación negativa implica que a medida que x aumenta, y
disminuye, o bien que a medida que x disminuye, y aumenta. Para usar el coeficiente de correlación
de Pearson de [Link] importamos pearsonr (scipy es una librería que contiene módulos para
optimización, álgebra lineal, integración, interpolación, entre otros).
r, pvalue = pearsonr(x[:,0], y)
print(f"Coeficiente de correlación de Pearson = {r}" )
r, pvalue = pearsonr(x[:,1], y)
print(f"Coeficiente de correlación de Pearson = {r}" )
Comparando x1 con y obtenemos r = 0.8239, comparando x2 con y obtenemos r = 0.8565, lo cual
es un indicador de que x1 y x2 podrían explicar y. A continuación, creamos nuestro modelo,
obtenemos el coeficiente de determinación y los valores modelados (la salida),
model = LinearRegression().fit(x, y)
r_sq = [Link](x, y)
print(f"Coeficiente de determinación = {r_sq}")
y_mod = [Link](x)
El coeficiente de determinación = 0.8395. Para visualizar las variables lo haremos todo en una
misma gráfica,
[Link](ind, x[:,0], color = 'green', s=15)
[Link](ind, x[:,1], color = 'magenta', s=15)
[Link](ind, y, color = 'black', s=15, marker="x")
[Link](ind, y_mod, color = 'blue', s=30,marker="+")
[Link]('Índice')
[Link]('Valor de variables')
[Link]('Regresión múltiple')
[Link](['x1', 'x2', 'y', 'y_mod'])
[Link]()
[Link]()
Para cada valor de índice vemos el respectivo valor de x1, x2, y y f(x1,x2). Podemos ver que la
trayectoria de la variable dependiente no es lineal; ya que nuestro modelo nos da R2=0.8395
podemos concluir que captura hasta cierto punto la no linealidad de y con 𝑥1 y 𝑥2 como predictores.
El código completo es,
Regresión polinomial
El caso más simple es una variable independiente en un polinomio de orden dos (el termino de
mayor grado es dos), es decir,
𝑓(𝑥) = 𝑏0 + 𝑏1 𝑥 + 𝑏2 𝑥 2
Con dos variables independientes y polinomio de orden dos tenemos,
𝑓(𝑥1 , 𝑥2 ) = 𝑏0 + 𝑏1 𝑥1 + 𝑏2 𝑥2 + 𝑏3 𝑥12 + 𝑏4 𝑥1 𝑥2 + 𝑏5 𝑥22
Podemos formar nuestra función con diferentes términos (lineales y no lineales) para
posteriormente probar si describe las observaciones de manera correcta. Como en los casos
anteriores, los coeficientes se calculan para minimizar la SSR.
Ejemplo de Regresión polinomial
Primero importamos los módulos que necesitamos e introducimos los valores de la variable
dependiente y los de la variable independiente.
import numpy as np
from sklearn.linear_model import LinearRegression
from [Link] import PolynomialFeatures
import [Link] as plt
x = [Link]([1,2,3,4,5,6,7,8,9]).reshape((-1, 1))
y = [Link]([5,4,3,2,1,2,3,4,5])
Para este ejemplo tenemos una variable independiente y usaremos un polinomio de orden dos, por
lo que necesitamos agregar en el arreglo x la columna de los valores 𝑥 2 , la clase
PolynomialFeatures nos ayudará a hacer esto. Los principales parámetros de PolynomialFeatures:
degree si es un entero especifica el grado máximo del polinomio, que por default es 2. Si pasamos
la tupla (min_grado, max_grado), entonces min_grado es el grado mínimo y max_grado es el grado
máximo del polinomio.
interaction_only si True, solo se incluyen términos de interacción, es decir, términos con una
entrada con potencia de 2 o más son excluidos. Por default es False.
include_bias si True, incluye una columna con unos. Por default es True.
Para crear el nuevo vector a partir de los valores de la variable independiente escribimos,
x_ = PolynomialFeatures(degree=2, include_bias=False).fit_transform(x)
La instrucción anterior nos devuelve un arreglo de dos dimensiones; para este ejemplo en la
primera columna tenemos los valores de x, y en la segunda los valores de x2. Ya que tenemos dos
columnas de valores, los de x y los de x2, procedemos de manera similar a que si tuviéramos dos
variables independientes, es decir, procedemos como lo haríamos para el caso de una regresión
lineal múltiple,
model = LinearRegression().fit(x_, y)
r_sq = [Link](x_, y)
print(f"Coeficiente de determinación = {r_sq}")
print(f"Intercepto = {model.intercept_}")
print(f"Coeficientes = {model.coef_}")
y_mod = [Link](x_)
Tenemos que el coeficiente de determinación es R2= 0.9276. Otra manera de verificar que tan
exacta es nuestra función seria con el Error Absoluto Medio (EAM),
∑𝑛𝑖=1|𝑦 𝑖 − 𝑦_𝑚𝑜𝑑𝑖 |
𝐸𝐴𝑀 =
𝑛
Donde 𝑦 𝑖 es la respuesta observada, 𝑦_𝑚𝑜𝑑𝑖 es la respuesta modelada, y n es el número de
observaciones. En el código escribimos,
E=0;n=len(y)
for i in range(n):
E=E+( abs(y[i]-y_mod[i]) )
EAM=E/n
print(f"Error absoluto medio = {EAM}")
Lo que nos da EAM=0.28. Finalmente, graficamos para visualizar los datos observados y los
modelados.
Cabe mencionar que un polinomio de orden 2 soporta un cambio de dirección de la variable
dependiente (como es el caso de este ejemplo), uno de orden 3 soporta dos cambios de dirección,
entonces si k es el orden del polinomio esté puede describir hasta k-1 cambios de dirección. El
código completo es,
Función exponencial
Si tenemos dos variables, x la variable independiente y y la dependiente, y tenemos que x vs. y
tiene forma exponencial, podemos usar la siguiente ecuación para modelar la salida,
𝑦 = 𝑒 (𝑎𝑥) 𝑒 𝑏
Ejemplo
Salida,
Subajuste (underfitting) y sobreajuste (overfitting)
Subajuste sucede cuando el modelo es simple y no puede capturar de manera correcta las
dependencias que existen entre las entradas y la salida, por lo que tendremos una R2 de bajo valor
tanto con los datos para entrenar el modelo como con los datos para evaluarlo (datos diferentes a
los usados para entrenar el modelo). Sobreajuste sucede cuando el modelo es complejo y aprende
bien las dependencias entre las entradas y la salida, sin embargo, aprende también las fluctuaciones
al azar, la R2 puede resultar alta con los datos para entrenar el modelo pero puede no desempeñarse
bien con los datos para evaluarlo. Por ejemplo, si vamos a describir un fenómeno con un
polinomio, debemos tener cuidado al escoger el orden del polinomio para no caer en subajuste o
sobreajuste.
Para contextualizar el tema, primero manipularemos los datos con los que vamos a trabajar. Vamos
a leer el archivo [Link] (para lo cual es necesario importar la librería Pandas), el cual tiene
106 renglones y 65 columnas, y está disponible en la siguiente liga:
[Link]
Es importante colocar [Link] en la misma carpeta donde estará el código que vamos a
implementar. En [Link], un renglón son las velocidades de un segmento de calle que se
registraron de las 6:00 a las 22:00 a intervalos de 15 minutos, lo que nos da un total de 65 columnas
(mediciones) para cada renglón; el total de segmentos de calle son 106, por lo que este es el número
de renglones. El promedio de una columna representa la velocidad promedio a la que se puede
transitar en la red (integrada por los segmentos considerados) a determinada hora. A continuación,
obtendremos el promedio de cada columna y asignaremos esta información en la lista v, además
crearemos una lista t y le asignaremos la hora que le corresponde a cada promedio de velocidad,
entonces,
import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression
from [Link] import PolynomialFeatures
import [Link] as plt
velocidad = pd.read_csv('[Link]', header=None)
v=[];t=[];tiempo=6;
for i in range(len([Link])):
[Link](velocidad[i].mean())
[Link](tiempo)
tiempo=tiempo+(1*.25)
Si a continuación graficamos t vs v veremos la velocidad promedio de la red en cada tiempo,
entonces creamos una función para graficar,
def graficar(p1,p2,p3,p4):
[Link](p1, p2, color = p3, s=25, marker=p4)
[Link]('Tiempo (horas)')
[Link]('Velocidad promedio (m/s)')
graficar(t,v,'black','.')
[Link]();[Link]()
Supongamos que para entrenar nuestro modelo solo tenemos la información de lo que sucede hasta
las 18:00 horas,
j=[Link](18)
v1=v[:j+1];t1=t[:j+1]
v2=v[j+1:];t2=t[j+1:]
graficar(t1,v1,'black','.')
[Link]();[Link]()
Supongamos que escogemos un polinomio de orden 2 para modelar los datos de la grafica anterior,
entonces,
grado=2
t1=[Link](t1).reshape(-1,1)
t1_=PolynomialFeatures(degree=2, include_bias=False).fit_transform( t1)
t2=[Link](t2).reshape(-1,1)
t2_=PolynomialFeatures(degree=2, include_bias=False).fit_transform( t2 )
model = LinearRegression().fit(t1_, v1)
r_sq = [Link](t1_, v1)
print(f"Coeficiente de determinación = {r_sq}")
r_sq = [Link](t2_, v2)
print(f"Coeficiente de determinación = {r_sq}")
v_mod = [Link](t1_)
v_pro = [Link](t2_)
graficar(t,v,'black','.')
graficar(t1,v_mod,'blue','+')
graficar(t2,v_pro,'red','x')
[Link]('Polinomio de orden '+str(grado))
[Link](['observado', 'modelado', 'pronosticado'], loc='upper center')
[Link]();[Link]()
Tenemos que R2= 0.98 para la parte de los datos que usamos para entrenar el modelo, y que R2=
0.95 para la parte de los datos que usamos para evaluar el modelo. Podemos concluir que en este
caso un polinomio de orden 2 logra describir bien la respuesta (tanto de los datos para entrenar
como de los datos para evaluar) considerando que para entrenar el modelo tomamos únicamente
la velocidad promedio hasta las 18:00 horas; el modelo puede describir un cambio de dirección y
ya que este sucede previo a las 18:00 horas, captura el cambio de dirección y la trayectoria que
genera es adecuada para describir la velocidad promedio entre las 18:15 y las 22:00 horas (que es
el intervalo de tiempo para evaluar el modelo). El código completo es,
Ejemplo de subajuste
La ecuación de la recta (en el código, grado=1) no puede describir bien la velocidad promedio
entre las 6:00 y las 18:00 horas (R2= 0.67), después de las 18:00 horas es evidente el problema de
subajuste como se puede apreciar en la siguiente gráfica,
Ejemplo de sobreajuste
Si utilizamos un polinomio de orden 3 (en el código, grado=3) es evidente el problema de
sobreajuste. En la siguiente grafica se puede observar que el patrón que sigue el modelo después
de las 18:00 es incorrecto, aunque entre las 6:00 y las 18:00 horas el modelo es muy exacto al
describir la respuesta (R2=0.99).
Dividir datos para entrenar y evaluar un modelo
Es una práctica aceptada que cuando vamos a entrenar un modelo usemos una parte de los datos
para entrenarlo (usualmente el 75%, que llamaremos el conjunto de datos para entrenar) y otra
para evaluarlo (usualmente el 25%, que llamaremos el conjunto de datos para evaluar). Si tenemos
un conjunto de datos y queremos dividirlo, la librería sklearn nos puede ayudar, por lo que es
necesario importar lo siguiente,
import numpy as np
from sklearn.model_selection import train_test_split
Si x representa el arreglo de dos dimensiones de las entradas, y y el arreglo de una dimensión de
la salida, podemos dividir nuestros datos con la siguiente instrucción,
x_train, x_test, y_train, y_test = train_test_split(x, y)
Tenemos que x_train y y_train son los datos de entrada y de salida, respectivamente, para entrenar
el modelo, y que x_test y y_test son los datos de entrada y de salida, respectivamente, para evaluar
el modelo. La función train_test_split() tiene los siguientes parámetros:
train_size si es un float debe ser entre 0.0 y 1.0 y representa el porcentaje de los datos que se
usaran para entrenar. Si es un entero será el número de elementos que conformaran el conjunto de
datos para entrenar. Por default es None.
test_size si es un float debe ser entre 0.0 y 1.0 y representa el porcentaje de los datos que se usaran
para evaluar. Si es un entero será el número de elementos que conformaran el conjunto de datos
para evaluar. Se debe pasar el valor del parámetro train_size o bien el de test_size, si no pasamos
ninguno de los dos por default test_size=0.25.
random_state es un entero (o bien una instancia de RandomState) que se usa para controlar el
proceso que aleatoriamente divide los datos en los conjuntos para entrenar y para evaluar. Por
ejemplo, si random_state=1, cada vez que sea igual a 1 volveremos a obtener el mismo resultado.
Por default es None.
shuffle es un booleano que si True desordena los datos antes de dividirlos. Por default es True.
stratify es un arreglo que, de no ser None, especifica como dividir los datos de manera
estratificada. Por ejemplo, si una observación de salida puede tomar uno de dos valores posibles
(cero o uno), y si consideramos que de las observaciones de salida el 60% son ceros y el 40% son
unos, con stratify=y se trata de mantener estos porcentajes tanto en los datos para entrenar como
en los datos para evaluar.
Ejemplo de dividir datos
x = [Link](1, 41).reshape(20, 2)
y = [Link]([1,0,0,1,0,0,1,0,0,0,0,0,1,1,1,0,0,1,1,0])
x_train, x_test, y_train, y_test = train_test_split(x, y, train_size=0.8, random_state=1,
shuffle=True, stratify=y)
En este caso el 80% de los datos serán para entrenar el modelo, por lo que 20% de los datos serán
para evaluarlo; random_state=1, por lo que podemos repetir resultados con este número;
shuffle=True, por lo que los datos son desordenados antes de dividirlos; stratify=y, por lo que para
la respuesta en los datos para entrenar tenemos un 62.5% de ceros y un 37.5% de unos, y en los
datos para evaluar tenemos un 50% de ceros y un 50% de unos, siendo que en y tenemos que el
60% son ceros y el 40% son unos. Los valores de x_train, y_train, x_test y y_test son:
x_train
array([[27, 28],
[19, 20],
[33, 34],
[29, 30],
[ 3, 4],
[ 9, 10],
[39, 40],
[11, 12],
[31, 32],
[21, 22],
[13, 14],
[15, 16],
[25, 26],
[37, 38],
[ 1, 2],
[ 5, 6]])
y_train
array([1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0])
x_test
array([[ 7, 8],
[23, 24],
[35, 36],
[17, 18]])
y_test
array([1, 0, 1, 0])
Regresión logística
Lo que hace la regresión logística es predecir la variable dependiente (la salida) cuando esta
pertenece a una determinada categoría, para esto toma en cuenta el valor de las variables
independientes (las entradas). Por ejemplo, las variables independientes podrían ser: la cantidad
de cursos tomados, que puede ser un valor del conjunto {1,2,3}, la experiencia laboral, que puede
ser un valor del conjunto {Novato, Intermedio, Avanzado}, y el nivel de estudios, que puede ser
un valor del conjunto {Licenciatura, Maestría, Doctorado}; la variable dependiente podría ser una
estimación del ingreso laboral, que puede ser un valor del conjunto {Bajo, Medio, Alto}. En este
ejemplo se puede apreciar que la experiencia laboral (una variable independiente) es manipulada
para corresponder con una de 3 categorías posibles, y la estimación del ingreso laboral (la variable
dependiente) también es manipulada para tomar un valor (no numérico) de tres valores posibles;
el número de categorías de las variables independientes y de la variable dependiente puede variar.
Para hacer una regresión logística en Python tenemos que importar LogisticRegression de
sklearn.linear_model, LogisticRegression tiene los siguientes parámetros:
penalty : {'l1', 'l2', 'elasticnet', None}, default=’l2’
• None: no se considera una penalidad.
• 'l2': agrega el termino de penalidad L2, este es el valor por default.
• 'l1': agrega el termino de penalidad L1.
• 'elasticnet': los términos de penalidad L1 y L2 son agregados.
dual : bool, default=False
Con False se usa primal, con True se usa dual.
tol : float, default=0.0001
Define la tolerancia para detener el proceso.
C : float, default=1.0
Inverso de la fuerza de regularización, debe ser positivo. Se tiene que los valores más pequeños
indican una regularización más fuerte.
fit_intercept : bool, default=True
Especifica si la constante (el intercepto) se debe agregar a la función de decisión.
intercept_scaling : float, default=1.0
Define la escala del intercepto (b0).
class_weight : dict or 'balanced', default=None
Define los pesos asociados a cada categoría, con None cada categoría tiene un peso de uno.
random_state : int, RandomSate instance, default=None
Se usa cuando solver == 'sag', 'saga' o 'liblinear' para reorganizar los datos.
solver : {'lbfgs', 'liblinear', 'newton-cg', 'newton-cholesky', 'sag', 'saga'}, default='lbfgs'
Para especificar el solucionador para ajustar el modelo.
max_iter : int, default=100
Es el número máximo de iteraciones durante el proceso de ajustar el modelo.
multi_class : {'auto', 'ovr', 'multinomial'}, default='auto'
Define el enfoque a utilizar para manejar categorías múltiples.
verbose : int, default=0
Define la verbosidad para los solucionadores 'liblinear' y 'lbfgs'.
warm_start : bool, default=False
Con True, se reutiliza la solución anterior. Con False, se elimina la solución anterior.
j_jobs : int, default=None
Número de núcleos de CPU utilizados. None significa utilizar 1 (no así en el contexto
joblib.parallel_backend) y -1 significa usar todos los procesadores disponibles. Este parámetro
es ignorado si solver se especifica como 'liblinear'.
l1_ratio : float, default=None
Define el parámetro Elastic-Ne, con 0 <= l1_ratio <= 1. Solo se usa si pentalty='elasticnet'.
Estableciendo l1_ratio=0 es equivalente a usar penalty='l2', estableciendo l1_ratio=1 es
equivalente a usar penalty='l1'. Con 0 < l1_ratio < 1, la penalización es una combinación de L1
y L2.
LogisticRegression tiene los siguientes atributos:
classes_ : ndarray of shape (n_classes,)
Una lista con las etiquetas de las categorías conocidas por el clasificador.
coef_ : ndarray of shape (1, n_features) or (n_classes, n_features)
Cuando el problema dado es binario, coef_ tiene la forma (1, n_features).
intercept_ : ndarray of shape (1,) or (n_classes,)
Es el valor del intercepto de la función de decisión.
n_features_in_ : int
Es el número de características vistas durante el ajuste.
feature_names_in_ : ndarray of shape (n_features_in_,)
Es el nombre de las características vistas durante el ajuste.
n_iter_ : ndarray of shape (n_classes,) or (1,)
Regresa el número de iteraciones. Para el caso del solucionador liblinear, regresa el número
más alto de iteraciones de entre los presentados por las categorías.
Ejemplo de Regresión logística
Para nuestro ejemplo tomaremos los datos de la siguiente tabla:
Variables independientes Variable dependiente
Cursos Experiencia Nivel de Salario
tomados estudios
2 Intermedio Maestría Medio
3 Avanzado Doctorado Alto
1 Novato Licenciatura Bajo
2 Avanzado Doctorado Alto
2 Intermedio Doctorado Medio
3 Avanzado Maestría Alto
1 Intermedio Licenciatura Bajo
1 Intermedio Maestría Medio
3 Intermedio Doctorado Alto
2 Novato Licenciatura Bajo
2 Avanzado Maestría Medio
1 Avanzado Doctorado Alto
1 Novato Maestría Bajo
2 Novato Maestría Medio
3 Novato Licenciatura Bajo
Las variables independientes son Cursos tomados, Experiencia, y Nivel de estudios. La variable
dependiente es el Salario. Para la variable independiente Experiencia tomaremos Novato=1,
Intermedio=2, y Avanzado=3; previamente se tuvo que haber establecido cuantos años de
experiencia corresponden a cada categoría, por ejemplo, entre 0 y 9 años de experiencia se
considera Novato, entre 10 y 19 años de experiencia se considera Intermedio, y una cantidad >=20
años se considera Avanzado. Para la variable independiente Nivel de estudios tomaremos
Licenciatura=1, Maestría=2, y Doctorado=3. Para la variable dependiente Salario consideraremos
Bajo=1, Medio=2, y Alto=3, previamente se tiene que establecer que rango de salario corresponde
con cada categoría, por ejemplo, un salario entre 0 y 14,999 pesos se considera Bajo, un salario
entre 15,000 y 29,999 se considera Medio, y un salario >=30,000 pesos se considera Alto.
A continuación, empezamos a escribir el código. Primero, importamos las librerías que
necesitamos:
import [Link] as plt
import numpy as np
from sklearn.linear_model import LogisticRegression
from [Link] import classification_report, confusion_matrix
from sklearn.model_selection import train_test_split
En el arreglo x las variables independientes, en el arreglo y la variable dependiente.
cursos = [Link]((2,3,1,2,2,3,1,1,3,2,2,1,1,2,3))
experiencia = [Link]((2,3,1,3,2,3,2,2,2,1,3,3,1,1,1))
estudios = [Link]((2,3,1,3,3,2,1,2,3,1,2,3,2,2,1))
x=np.column_stack((cursos,experiencia,estudios))
y = [Link]((2,3,1,3,2,3,1,2,3,1,2,3,1,2,1))
Tomamos el 80% de los datos para entrenar el modelo, por consiguiente, tendremos el 20% de los
datos para evaluarlo.
x_train, x_test, y_train, y_test =\
train_test_split(x, y, train_size=0.8, random_state=9, shuffle=True, stratify=y)
Creamos el modelo.
model = LogisticRegression()
[Link](x_train, y_train)
Luego, obtenemos la salida que nos entrega el modelo considerando x_train, la cual nombramos
y_mod_train, y obtenemos la salida que nos entrega el modelo considerando x_test, la cual
nombramos y_mod_test. Además, obtenemos la matriz de confusión considerando y_train y
y_mod_train, y la matriz de confusión considerando y_test y y_mod_test,
y_mod_train = [Link](x_train)
y_mod_test = [Link](x_test)
cm_train = confusion_matrix(y_train, y_mod_train)
cm_test = confusion_matrix(y_test, y_mod_test)
Escribimos instrucciones para visualizar resultados,
print('y_train =',y_train)
print('y_mod_train =',y_mod_train, '\n')
print('confusion_matrix(y_train, y_mod_train):')
print(cm_train, '\n')
print('---------------------------------------\n')
print('y_test =',y_test)
print('y_mod_test =',y_mod_test,'\n')
print('confusion_matrix(y_test, y_mod_test):')
print(cm_test)
En pantalla veríamos,
y_train = [2 1 2 1 2 3 1 2 3 1 3 3]
y_mod_train = [3 1 2 1 2 3 1 2 3 1 3 3]
confusion_matrix(y_train, y_mod_train):
[[4 0 0]
[0 3 1]
[0 0 4]]
---------------------------------------
y_test = [2 3 1]
y_mod_test = [2 3 1]
confusion_matrix(y_test, y_mod_test):
[[1 0 0]
[0 1 0]
[0 0 1]]
Considerando los datos para entrenar nos podemos dar cuenta que todos los 1 (cuatro
observaciones) fueron modelados de manera correcta, con respecto a los 2 tres de cuatro
observaciones fueron modeladas de manera correcta, con respecto a los 3 las cuatro observaciones
son modeladas de manera correcta. En la matriz de confusión (cm_train) tenemos en el eje-y el
valor observado y en el eje-x el valor modelado, es decir:
1 4 0 0
Observado
2 0 3 1
3 0 0 4
1 2 3
Modelado
Podemos visualizar que la suma del renglón uno es 4, por lo que tenemos 4 observaciones con
valor 1, ya que en el renglón uno (que corresponde a observar un 1) y columna uno (que
corresponde a modelar un 1) tenemos un 4, significa que todos los 1 observados fueron modelados
de manera correcta. La suma del renglón dos es 4 por lo que tenemos 4 observaciones con valor 2,
tenemos que en el renglón dos (observar un 2) y columna dos (modelar un 2) tenemos un 3, por lo
que tenemos 3 observaciones del valor 2 modeladas correctamente, en el renglón dos (observar un
2) y columna tres (modelar un 3) tenemos un 1, lo que significa 1 observación del valor 2 modelada
incorrectamente. La suma del renglón tres es 4, por lo que tenemos 4 observaciones del valor 3,
como en el renglón tres (observar un 3) y columna 3 (modelar un 3) tenemos un 4, tenemos 4
observaciones del valor 3 modeladas correctamente.
Podemos calcular la exactitud que tiene el modelo teniendo en cuenta los datos para entrenar,
tenemos un total de 12 observaciones de las cuales 11 el modelo entrego un resultado correcto,
entonces el modelo predice correctamente el 11/12*100 = 91.66% de las observaciones utilizadas
para entrenarlo.
La matriz de confusión (cm_test) con los datos para evaluar es:
1 1 0 0
Observado
2 0 1 0
3 0 0 1
1 2 3
Modelado
Tenemos un total de 3 observaciones de las cuales el modelo predice correctamente 3, por lo que
el modelo predice correctamente el 3/3*100=100% de las observaciones para evaluarlo. El código
completo es,