Saltar al contenido

Archivos de categoría Regresión logística

Regresión logística en Python

Vamos a crear un modelo basado en datos de telecomunicaciones para predecir cuándo los clientes buscarán otro competidor de tal forma que podamos tomar alguna decisión para retenerlos.

¿Cuál es la diferencia entre Regresión Logística y Regresión Lineal?

Mientras la Regresión Lineal es para estimar valores continuos (ej. estimar precios de casas), no es la mejor herramienta para predecir la clase de un punto de datos observados. Para estimar la clase de punto de datos, necesitaremos una guía de lo que sería la clase más probable para ese punto de datos. Por esto, utilizamos Regresión Logística.

Regresión Lineal:

Como sabes, la Regresión lineal encuentra una función que relaciona una variable continua dependiente, y, con algunos predictores (variables independientes x_1, x_2, etc.). Por ejemplo, la regresión lineal Simple asume una función de la forma:

y = \theta_0 + \theta_1 x_1 + \theta_2 x_2 + \cdots

y encuentra los valores de los parámetros \theta_0, \theta_1, \theta_2, etc, donde el término \theta_0 es «intersección». Generalmente se muestra como:

h_\theta(x)=\theta^T X

La Regresion Logística es una variación de una Regresión Lineal, útil cuando la variable dependiente observada, y, es categórica. Produce una fórmula que predice la probabilidad de la clase etiqueta como una función de las variables independientes.

La regresión logística es una curva especial en forma de s a partir de tomar la regresión lineal y transformar la estimación numérica en una probabilidad con la siguiente función, llamada sigmoide \sigma:

h_\theta(x)=\sigma(\theta^T X)=\frac{e^{(\theta_0 + \theta_1 x_1 + \theta_2 x_2 + \cdots)}}{1 + e^{(\theta_0 + \theta_1 x_1 + \theta_2 x_2 + \cdots)}}

O también: ProbabilidadDeUnaClase_1 = P(Y = 1 \vert X) = \sigma(\theta^T X) = \frac{e^{\theta^T X}}{1 + e^{\theta^T X}}

En esta ecuación, \theta^T X es el resultado de la regresión (la suma de las variables ponderadas por los coeficientes), e es la función exponencial y \sigma(\theta^T X) es la función sigmoide ó función logística, también llamada curva logística. Tiene una forma de «S» (curva sigmoide). En resumen, la Regresión Logística pasa la entrada a través de las funciones logística/sigmoide pero en realidad termina tratando al resultado como una probabilidad:
curva sigmoide

El objetivo del algoritmo de Regresión Logística, es encontrar los mejores parámetros \theta, para h_\theta (x) = \sigma(\theta^T X), de forma tal de que el modelo prediga lo mejor posible la clase de cada caso.

Cliente churn con Regresión Logística

Una compañía de telecomunicaciones está preocupada por el número de clientes que dejan sus líneas fijas de negocio por las de competidores de cable. Ellos necesitan entender quién se está yendo. Imagina que eres un analista en esta compañía y que tienes que descubrir quién es el cliente que se va y por qué

Primero, importemos las librerías necesarias:

import pandas as pd
import pylab as pl
import numpy as np
import scipy.optimize as opt
from sklearn import preprocessing
%matplotlib inline 
import matplotlib.pyplot as plt

Acerca del conjunto de datos

Utilizaremos datos de las telecomunicaciones para poder predecir el cliente cancelador (churn). Estos son datos históricos de clientes donde cada fila representa un cliente. Los datos son fáciles de comprender, y podrás descubrir conclusiones que puedes usar de inmediato. Generalmente, es menos caro mantener clientes que conseguir nuevos, así que el foco de este análisis es predecir los clientes que se quedarían en la compañía.
Estos datos proveen información que ayudarán a predecir comportamientos que retendrán a los clientes. Puedes analizar toda la información relevante del cliente y desarrollar programas de retención centrados en los clientes.

Los datos incluyen información acerca de:

  • Clientes que se fueron el último mes – la columna se llama Churn
  • Los servicios que cada cliente ha contratado – teléfono, líneas múltiples, internet, seguridad online, resguardo online, protección de dispositivos, soporte técnico y streaming de TV y películas
  • Información de la cuenta del cliente – cuánto hace que es cliente, contrato, método de pago, facturación digital, cargos mensuales y cargos totales
  • Información demográfica de los clientes – sexo, rango de edad y si tienen pareja y dependientes

Cargar los datos «Cancelaciones» de la Telco

«Telco Churn» es un archivo de datos ficticio que trata sobre los esfuerzos de una compañía de telecomunicaciones para reducir la huída de sus clientes. Cada caso corresponde a un cliente y se guarda información demográfica e información referente al uso del servicio. Antes de trabajar con los datos, debes utilizar la URL para obtener el archivo ChurnData.csv. Para descargarlo, utilizaremos !wget desde IBM Object Storage.

!wget -O ChurnData.csv https://s3-api.us-geo.objectstorage.softlayer.net/cf-courses-data/CognitiveClass/ML0101ENv3/labs/ChurnData.csv
--2020-02-12 16:42:15--  https://s3-api.us-geo.objectstorage.softlayer.net/cf-courses-data/CognitiveClass/ML0101ENv3/labs/ChurnData.csv
Resolving s3-api.us-geo.objectstorage.softlayer.net (s3-api.us-geo.objectstorage.softlayer.net)... 67.228.254.196
Connecting to s3-api.us-geo.objectstorage.softlayer.net (s3-api.us-geo.objectstorage.softlayer.net)|67.228.254.196|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 36144 (35K)

Saving to: ‘ChurnData.csv’

ChurnData.csv 100%[===================>] 35.30K –.-KB/s in 0.02s

2020-02-12 16:42:15 (1.56 MB/s) – ‘ChurnData.csv’ saved [36144/36144]

Cargar los Datos desde el Archivo CSV

churn_df = pd.read_csv("ChurnData.csv")
churn_df.head()
tenure age address income ed employ equip callcard wireless longmon pager internet callwait confer ebill loglong logtoll lninc custcat churn
0 11.0 33.0 7.0 136.0 5.0 5.0 0.0 1.0 1.0 4.40 1.0 0.0 1.0 1.0 0.0 1.482 3.033 4.913 4.0 1.0
1 33.0 33.0 12.0 33.0 2.0 0.0 0.0 0.0 0.0 9.45 0.0 0.0 0.0 0.0 0.0 2.246 3.240 3.497 1.0 1.0
2 23.0 30.0 9.0 30.0 1.0 2.0 0.0 0.0 0.0 6.30 0.0 0.0 0.0 1.0 0.0 1.841 3.240 3.401 3.0 0.0
3 38.0 35.0 5.0 76.0 2.0 10.0 1.0 1.0 1.0 6.05 1.0 1.0 1.0 1.0 1.0 1.800 3.807 4.331 4.0 0.0
4 7.0 35.0 14.0 80.0 2.0 15.0 0.0 1.0 0.0 7.10 0.0 0.0 1.0 1.0 0.0 1.960 3.091 4.382 3.0 0.0

Selección y pre-procesamiento de datos

Seleccionemos algunas características para el modelado. También cambiemos el tipo de dato del objetivo (target) para que sea un número entero (integer), ya que es un requerimiento del algoritmo skitlearn:

churn_df = churn_df[['tenure', 'age', 'address', 'income', 'ed', 'employ', 'equip',   'callcard', 'wireless','churn']]
churn_df['churn'] = churn_df['churn'].astype('int')
churn_df.head()
tenure age address income ed employ equip callcard wireless churn
0 11.0 33.0 7.0 136.0 5.0 5.0 0.0 1.0 1.0 1
1 33.0 33.0 12.0 33.0 2.0 0.0 0.0 0.0 0.0 1
2 23.0 30.0 9.0 30.0 1.0 2.0 0.0 0.0 0.0 0
3 38.0 35.0 5.0 76.0 2.0 10.0 1.0 1.0 1.0 0
4 7.0 35.0 14.0 80.0 2.0 15.0 0.0 1.0 0.0 0
churn_df.describe()
tenure age address income ed employ equip callcard wireless churn
count 200.000000 200.000000 200.000000 200.000000 200.00000 200.00000 200.000000 200.000000 200.000000 200.000000
mean 35.505000 41.165000 11.650000 75.130000 2.82500 10.22500 0.425000 0.705000 0.290000 0.290000
std 21.640971 13.076803 10.158419 128.430468 1.28555 8.95743 0.495584 0.457187 0.454901 0.454901
min 1.000000 19.000000 0.000000 9.000000 1.00000 0.00000 0.000000 0.000000 0.000000 0.000000
25% 16.750000 31.000000 3.000000 31.000000 2.00000 3.00000 0.000000 0.000000 0.000000 0.000000
50% 33.500000 40.000000 9.000000 48.000000 3.00000 7.50000 0.000000 1.000000 0.000000 0.000000
75% 55.250000 51.000000 18.000000 80.000000 4.00000 17.00000 1.000000 1.000000 1.000000 1.000000
max 72.000000 76.000000 48.000000 1668.000000 5.00000 44.00000 1.000000 1.000000 1.000000 1.000000

Definamos X, e y para nuestro set de datos:

X = np.asarray(churn_df[['tenure', 'age', 'address', 'income', 'ed', 'employ', 'equip']])
X[0:5]
array([[ 11.,  33.,   7., 136.,   5.,   5.,   0.],
       [ 33.,  33.,  12.,  33.,   2.,   0.,   0.],
       [ 23.,  30.,   9.,  30.,   1.,   2.,   0.],
       [ 38.,  35.,   5.,  76.,   2.,  10.,   1.],
       [  7.,  35.,  14.,  80.,   2.,  15.,   0.]])
y = np.asarray(churn_df['churn'])
y [0:5]
array([1, 1, 0, 0, 0])

También, normalicemos el set de datos:

from sklearn import preprocessing
X = preprocessing.StandardScaler().fit(X).transform(X)
X[0:5]
array([[-1.13518441, -0.62595491, -0.4588971 ,  0.4751423 ,  1.6961288 ,
        -0.58477841, -0.85972695],
       [-0.11604313, -0.62595491,  0.03454064, -0.32886061, -0.6433592 ,
        -1.14437497, -0.85972695],
       [-0.57928917, -0.85594447, -0.261522  , -0.35227817, -1.42318853,
        -0.92053635, -0.85972695],
       [ 0.11557989, -0.47262854, -0.65627219,  0.00679109, -0.6433592 ,
        -0.02518185,  1.16316   ],
       [-1.32048283, -0.47262854,  0.23191574,  0.03801451, -0.6433592 ,
         0.53441472, -0.85972695]])

Entrenar/Probar el set de datos

Ahora, dividamos nuestro set de datos en dos sets, entrenamiento y prueba:

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=4)
print ('Train set:', X_train.shape,  y_train.shape)
print ('Test set:', X_test.shape,  y_test.shape)
Train set: (160, 7) (160,)
Test set: (40, 7) (40,)

Modelando (Regresión Logística con Scikit-learn)

Construyamos nuestro modelo utilizando LogisticRegression con el package Scikit-learn. Esta función implementa regresión logística y puede usar distintos optimizadores numéricos para encontrar parámetros, a saber, ‘newton-cg’, ‘lbfgs’, ‘liblinear’, ‘sag’, ‘saga’ solvers. Puedes también encontrar más información sobre los pros y contras de estos optimizadores si buscas en internet.

La versión de Regresión Logística soporta regularización. Esto es, una técnica que soluciona problemas de sobreajuste en modelos de machine learning. El parámetro C indica fuerza de regularización inversa la cual debe ser un número flotante positivo. Valores más pequeños indican regularización más fuerte. Llenemos nuesto modelo con el subconjunto de entrenamiento:

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix
LR = LogisticRegression(C=0.01, solver='liblinear').fit(X_train,y_train)
LR
LogisticRegression(C=0.01, class_weight=None, dual=False, fit_intercept=True,
          intercept_scaling=1, max_iter=100, multi_class='warn',
          n_jobs=None, penalty='l2', random_state=None, solver='liblinear',
          tol=0.0001, verbose=0, warm_start=False)

Ahora, podremos predecir usando nuestro set de prueba:

yhat = LR.predict(X_test)
yhat
array([0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0])

predict_proba devuelve estimaciones para todas las clases. La primer columna es la probabilidad de la clase 1, P(Y=1|X), y la segunda columna es la probabilidad de la clase 0, P(Y=0|X):

yhat_prob = LR.predict_proba(X_test)
yhat_prob
array([[0.54132919, 0.45867081],
       [0.60593357, 0.39406643],
       [0.56277713, 0.43722287],
       [0.63432489, 0.36567511],
       [0.56431839, 0.43568161],
       [0.55386646, 0.44613354],
       [0.52237207, 0.47762793],
       [0.60514349, 0.39485651],
       [0.41069572, 0.58930428],
       [0.6333873 , 0.3666127 ],
       [0.58068791, 0.41931209],
       [0.62768628, 0.37231372],
       [0.47559883, 0.52440117],
       [0.4267593 , 0.5732407 ],
       [0.66172417, 0.33827583],
       [0.55092315, 0.44907685],
       [0.51749946, 0.48250054],
       [0.485743  , 0.514257  ],
       [0.49011451, 0.50988549],
       [0.52423349, 0.47576651],
       [0.61619519, 0.38380481],
       [0.52696302, 0.47303698],
       [0.63957168, 0.36042832],
       [0.52205164, 0.47794836],
       [0.50572852, 0.49427148],
       [0.70706202, 0.29293798],
       [0.55266286, 0.44733714],
       [0.52271594, 0.47728406],
       [0.51638863, 0.48361137],
       [0.71331391, 0.28668609],
       [0.67862111, 0.32137889],
       [0.50896403, 0.49103597],
       [0.42348082, 0.57651918],
       [0.71495838, 0.28504162],
       [0.59711064, 0.40288936],
       [0.63808839, 0.36191161],
       [0.39957895, 0.60042105],
       [0.52127638, 0.47872362],
       [0.65975464, 0.34024536],
       [0.5114172 , 0.4885828 ]])

Evaluación

Índice jaccard

Probemos con el índice jaccard para la evaluación de precisión. Podemos definir como jaccard al tamaño de la intersección dividida por el tamaño de la unión de dos set de etiquetas. Si todo el set de etiquetas de muestra predichas coinciden con el set real de etiquetas, entonces la precisión es 1.0; sino, sería 0.0.

from sklearn.metrics import jaccard_similarity_score
jaccard_similarity_score(y_test, yhat)
0.75

Matriz de confusión

Otra forma de mirar la precisión del clasificador es ver la matriz de confusión.

from sklearn.metrics import classification_report, confusion_matrix
import itertools
def plot_confusion_matrix(cm, classes, normalize=False, title='Confusion matrix', cmap=plt.cm.Blues):
  """
  Esta función muestra y dibuja la matriz de confusión.
  La normalización se puede aplicar estableciendo el valor `normalize=True`.
  """
  if normalize:
    cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
    print("Matriz de confusión normalizada")
  else:
    print('Matriz de confusión sin normalización')

  print(cm)

  plt.imshow(cm, interpolation='nearest', cmap=cmap)
  plt.title(title)
  plt.colorbar()
  tick_marks = np.arange(len(classes))
  plt.xticks(tick_marks, classes, rotation=45)
  plt.yticks(tick_marks, classes)

  fmt = '.2f' if normalize else 'd'
  thresh = cm.max() / 2.
  for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
    plt.text(j, i, format(cm[i, j], fmt), horizontalalignment="center", color="white" if cm[i, j] > thresh else "black")

​  plt.tight_layout()
  plt.ylabel('Etiqueta Real')
  plt.xlabel('Etiqueta Predicha')
print(confusion_matrix(y_test, yhat, labels=[1,0]))
[[ 6  9]
 [ 1 24]]
# Calcular la matriz de confusión
cnf_matrix = confusion_matrix(y_test, yhat, labels=[1,0])
np.set_printoptions(precision=2)

​# Dibujar la matriz de confusión no normalizada
plt.figure()
plot_confusion_matrix(cnf_matrix, classes=['churn=1','churn=0'],normalize= False, title='Matriz de confusión')
Matriz de confusión sin normalización
[[ 6  9]
 [ 1 24]]

Observa la primer fila. Ahí están los clientes cuyo valor churn en el set de prueba es 1. Como podrás calcular, de 40 clientes, el valor churn de 15 de ellos es 1. Y de otros 15, el clasificador predijo que 6 de ellos son 1 y 9 0.
Quiere decir que, para 6 clientes, el valor actual de churn fue 1 en el set de pruebas y el clasificador los predijo correctamente como 1. Sin embargo, mientras la etiqueta actual de 9 clientes era 1, el clasificador los predijo como 0, lo cual no es muy bueno. Lo podemos considerar como un error del modelo para la primer fila.
¿Qué pasa con los clientes con valor churn 0? Miremos la segunda fila. Parece que hay 25 clientes con valor churn 0.
El clasificador predijo correctamente 24 de ellos como 0 y uno de ellos equivocadamente como 1. Así que ha hecho un buen trabajo prediciendo los clientes con churn 0. Una ventaja de la matriz de confusión es que muestra la abilidad del modelo para correctamente predecir o separar las clases. En el caso de clasificador binario, como el ejemplo, podemos entender a estos números como la cantidad de positivos verdaderos, negativos verdaderos y negativos falsos.

print (classification_report(y_test, yhat))
              precision    recall  f1-score   support

           0       0.73      0.96      0.83        25
           1       0.86      0.40      0.55        15

   micro avg       0.75      0.75      0.75        40
   macro avg       0.79      0.68      0.69        40
weighted avg       0.78      0.75      0.72        40


Partiendo de la cantidad de cada sección podemos calcular la precisión y el grado(recall) de cada etiqueta:

  • Precision es una medida de certeza basada en una etiqueta predicha. Se define de esta forma: precision = TP / (TP + FP)
  • Recall es un grado positivo verdadero. Se define de esta forma: Recall = TP / (TP + FN)

Por lo tanto, podemos calcular la precisión y grado de cada clase.

F1 score: Ahora estamos en condiciones de calcular los puntajes F1 para cada etiqueta basada en la precisión y grado de cada etiqueta.

El puntaje F1 es el promedio armónico de la precisión y grado, donde un grado F1 alcanza su mejor valor en 1 (precisión y grado perfectos) y peor escenario en 0. Es una buena forma de mostrar que un clasificador tiene un buen valor tanto para la precisión como para el grado.

Y finalmente, podemos decir que la exactitud promedio para este clasificador es el promedio del score f1 para ambas etiquetas, cuyo valor es is 0.72 en nuestro caso.

log loss

Ahora, probemos log loss para la evaluación. En regresión logística, la salida puede ser que la probabilidad de cliente churn sea sí (o su equivalente 1). Esta probabilidad es un valor entre 0 y 1. Log loss( pérdida logarítmica) mida el rendimiento de un clasificador donde la salida predicha es una probabilidad de valor entre 0 y 1.

from sklearn.metrics import log_loss
log_loss(y_test, yhat_prob)
0.6017092478101185

Modelo con valores diferentes

Vamos a construir el modelo de Regresión Logística de nuevo para el mismo set de datos, pero esta vez, utilizando valores diferentes de solucionador y regularización.

LR2 = LogisticRegression(C=0.01, solver='sag').fit(X_train,y_train)
yhat_prob2 = LR2.predict_proba(X_test)
print ("LogLoss: : %.2f" % log_loss(y_test, yhat_prob2))
LogLoss: : 0.61
0 Seguir leyendo →

Cálculo de los parámetros de la función logística

Cálculo de los parámetros de la función logística

El objetivo principal es el cálculo de los parámetros de la función logística para que sea la mejor estimación de las etiquetas de las muestras en el conjunto de datos. Resumiendolo mucho, primero tenemos que mirar la función de costo y ver cuál es la relación entre la función de coste y los parámetros \theta. Por lo tanto, debemos formular la función de coste y usando su derivada podemos encontrar cómo cambiar los parámetros para reducir el costo, o mejor dicho, el error.

1. Búsqueda de la función de costo

Normalmente hay una ecuación general para calcular el costo que es la diferencia entre los valores reales de «y» y el resultado de nuestro modelo. Esta es una regla general para la mayoría de las funciones de coste en Machine Learning (aprendizaje automatizado). Podemos mostrarlo como el «Coste de nuestro modelo comparándolo con las etiquetas reales», o la «diferencia entre el
valor predicho de nuestro modelo y valor real del campo objetivo». Normalmente se usa el cuadrado de esa diferencia para evitar resultados negativos, y, por simplificar, la mitad de ese valor se considera como la función de coste:

Cost(\hat y, y)=\frac{1}{2}(\sigma(\theta^T X) - y)^2

Ahora, podemos escribir la función de costo para todas las muestras de nuestro conjunto de datos como la suma promedio de las funciones de coste de todos los casos. También se le llama error cuadrado medio (Mean Squared Error), y, como es una función de un parámetro vector θ, se muestra como J(θ).

J(\theta)=\frac{1}{m}\displaystyle\sum_{i-1}^{m}Cost(\hat y, y)

Para encontrar los mejores pesos o parámetros que minimizan esta función de coste deberíamos calcular el punto mínimo de esta función. Este punto mínimo se calcula utilizando la derivada, pero no hay una manera fácil de encontrarla para el punto mínimo global. La solución es encontrar otra función de coste en su lugar, una que tenga el mismo comportamiento pero sea más fácil para encontrar su punto mínimo.

funcion -logRecordemos que nuestro modelo es \hat y, que el valor real es y (que es igual a 0 o 1) y que nuestro modelo trata de estimarlo. Vamos a suponer que el valor deseado para y es 1. Esto significa que nuestro modelo es mejor si estima y=1 y en ese caso la función de coste devería devolver 0, ya que es igual a la etiqueta real. El costo debería aumentar a medida que el resultado de nuestro modelo se aleje de 1, llegando a ser muy grande si el resultado de nuestro modelo es cercano a 0. Podemos ver que la función -log() proporciona tal función de coste. Por lo tanto, podemos usar la función -log() para calcular el costo de nuestro modelo de regresión logística. Ahora podemos conectarlo a nuestra función de costo total y reescribirlo como esta función. Por lo tanto, esta es la función de costo de regresión logística. Hay que recordar que \hat y no devuelve una clase como salida, sino que es un valor entre 0 y 1, lo que debe ser asumido como una probabilidad.

Cost(\hat y, y) = \left \{ \begin{matrix} -log(\hat y) & \mbox{si }y=1\\ -log(1 - \hat y) & \mbox{si }y=0\end{matrix}\right

J(\theta)=-\frac{1}{m}\displaystyle\sum_{i-1}^{m}y^{i}log(\hat y^i) + (1 - y^i)log(1 - \hat y^i)

2. Minimización de la función de costo

Para la minimización de la función de costo utilizamos un enfoque de optimización. Existen diferentes enfoques de optimización, pero vamos a utilizar uno de los más famosos y efectivos: el descenso gradual. Es un enfoque iterativo para encontrar el mínimo de la una función utilizando su derivada, así que con ella vamos a buscar el mínimo de la función de costo y así cambiar los valores de los parámetros, para minimizar el error.

Piense que los parámetros o pesos en nuestro modelo estan en un espacio bidimensional, por ejemplo, \theta_1, \theta_2, para 2 conjuntos de características, podrían ser edad e ingresos. Y tenemos una tercera dimensión que es el costo o error observado. Si trazamos la función de coste basada en todos los valores posibles de \theta_1, \theta_2, podemos ver algo como un tazón y representa el valor de error para diferentes valores de los parámetros. A esto se le llama «curva de error» o «tazón de error» de su función de costes. Ahora hay que buscar los valores de los parámetros que minimizan el valor de coste.
Se podría seleccionar valores de parámetros aleatorios que ubican un punto en el tazón y mientras que el valor del costo baje, podemos dar un paso más. También puede observarse que cuanto más empinada sea la pendiente, más lejos del punto mínimo estaremos, por lo que podremos elegir nuevos valores más lejos que los anteriores. Haciendo esto sucesivas veces y a medida que nos acercamos al punto más bajo, la pendiente disminuye, por lo que podemos dar pasos más pequeños hasta llegar a una superficie plana.

Para asegurarnos que descendemos, y qué los pasos son suficientemente grandes se debería calcular el gradiente de la función de coste en el punto estudiado. La derivada parcial de J(\theta) con respecto a cada parámetro en ese punto, da la pendiente del movimiento para cada parámetro en ese punto. Así que si nos movemos en la dirección opuesta a esa pendiente, garantizamos que bajamos en la curva de error. El valor del gradiente también indica el tamaño del paso a dar. Si la pendiente es grande, debemos dar un gran paso porque estamos lejos del mínimo y si la pendiente es pequeña deberíamos dar un paso más pequeño. El descenso en pendiente da pasos cada vez más pequeños hacia el mínimo con cada iteración. La derivada parcial de la función de coste J se calcula utilizando esta expresión.

\frac{\partial J}{\partial\theta_1}=-\frac{1}{m}\displaystyle\sum_{i=1}^{m}(y^i-\hat y^i)\hat y^i(1-\hat y^i)x_1

Esta ecuación devuelve la pendiente de ese punto, y deberíamos actualizar el parámetro en la dirección opuesta a la pendiente. Un vector de todas estas pendientes es el vector de gradiente:
\nabla J = \left [ \begin{matrix}\frac{\partial J}{\partial\theta_1} \\ \frac{\partial J}{\partial\theta_2} \\ \frac{\partial J}{\partial\theta_3} \\ \cdots \\ \frac{\partial J}{\partial\theta_k}\end{matrix} \right ]

Podemos usar este vector para cambiar o actualizar todos los parámetros, tomando los valores anteriores de los parámetros y restando la derivada de Error. Esto resulta en los nuevos parámetros para \theta que sabemos que disminuirá el costo: New \theta = old \theta - \nabla J. Además, si multiplicamos el valor del gradiente por un valor constante \eta, que se denomina velocidad de aprendizaje, tenemos un salto proporcional, dando un control adicional sobre la velocidad con la que nos movemos en la superficie: New \theta = old \theta - \eta\nabla J

En resumen, podemos decir simplemente que el descenso en pendiente es como dar pasos en la dirección actual de la pendiente, y el ritmo de aprendizaje es como la duración del paso que das. Así que, estos serían nuestros nuevos parámetros. Fíjate que es una operación iterativa y, en cada iteración, actualizamos los parámetros y minimizamos el coste, hasta que el algoritmo converge en un mínimo aceptable.

Recapitulando:

  • Paso 1. Inicializamos los parámetros con valores aleatorios.
  • Paso 2. Alimentamos la función de costes con la función y calcular el costo. Esperamos una alta tasa de error ya que los parámetros se establecen al azar.
  • Paso 3. Calculamos el gradiente del coste teniendo en cuenta que tenemos que usar una derivada parcial. Entonces, para calcular el vector de gradiente, necesitamos todos los datos de entrenamiento para alimentar la ecuación para cada parámetro. Por supuesto, esta es una parte costosa del algoritmo pero hay algunas soluciones para esto.
  • Paso 4. Las ponderaciones se actualizan con nuevos valores de parámetros.
  • Paso 5. Aquí volvemos al paso 2 y volvemos a alimentar la función de costes, que tiene nuevos parámetros. Esperamos menos errores a medida que vamos bajando por la superficie de los errores. Continuamos este ciclo hasta que alcanzamos un valor corto de costo, o un número limitado de iteraciones.
  • Paso 6. Los parámetros deben ser encontrados después de algunas iteraciones. Esto significa que el modelo está listo y podemos usarlo para predecir la probabilidad de que una observación pertenezca o no a una categoría.

Resulta obvio que todos estos pasos pueden realizarse mediante programas y sus librerias, puedes ver un ejemplo en este artículo: Regresión logística en Python

Ir al artículo anterior de la serie: Regresión lineal Vs. regresión logística

Ir al artículo siguiente de la serie: Máquinas de soporte de vectores

0 Seguir leyendo →

Regresión lineal Vs. regresión logística

Regresión lineal Vs. regresión logística

regresión linealVamos a ver la diferencia entre la regresión lineal vs. la regresión logística. Revisaremos la regresión lineal y veremos por qué no se puede utilizar correctamente para algunos problemas de clasificación binaria.

El objetivo de la regresión logística consiste en construir un modelo para predecir la clase de cada observación, y también la probabilidad de que cada muestra pertenezca a una clase. Idealmente, queremos construir un modelo, \hat y, que pueda estimar que la clase de una observación sea 1, dadas sus características, x. Hay que anotar que «y» son los «vectores de etiquetas» también llamados «valores reales» que nos gustaría predecir, y que «\hat y» es el vector de los valores pronosticados por nuestro modelo.

Cómo funciona la regresión lineal

Con la regresión lineal, se puede encajar una línea o polinomio a través de los datos. Podemos encontrar esta línea usando el entrenamiento de nuestro modelo, o calculándola matemáticamente basádonos en conjuntos de ejemplo. Por simplificar, vamos a decir que es una línea recta que tiene una ecuación a + b \cdot x_1. Ahora, utilizamos esta línea para predecir un valor continuo «y«.

funcion categorizadaPero, ¿podemos utilizar la misma técnica para predecir un campo categórico? Tenemos una característica, x_1, y una característica categórica con dos clases: por ejemplo «si» y «no». Podemos correlacionar «si» y «no» con valores enteros, 0 y 1. Gráficamente, podríamos representar nuestro conjunto de datos con un gráfico de dispersión. Pero esta vez sólo tenemos 2 valores para el eje y. Con la regresión lineal se puede encajar de nuevo un polinomio a través de los datos, que se muestra tradicionalmente como a + b \cdto x. Este polinomio también se puede mostrar tradicionalmente como \theta_0 + \theta_1 \cdot x_1. Esta línea tiene 2 parámetros, que se muestran con el vector \theta, donde los valores del vector son \theta_0 y \theta_1. También podemos mostrar la ecuación de esta línea formalmente como \theta^T \cdot X = \theta_0 + \theta_1 \cdot x_1. Y, en general, podemos mostrar la ecuación de un espacio multidimensional como \theta^T \cdot X = \theta_0 + \theta_1 \cdot x_1 + \theta_2 \cdot x_2 + \cdots, donde θ son los parámetros de la línea en un espacio bidimensional, o parámetros de un plano en un espacio tri-dimensional, y así sucesivamente. Como \theta^T=\left [ \theta_0, \theta_1, \theta_2, \cdots \right ] es un vector de parámetros, y se supone que para ser multiplicado por X, se muestra convencionalmente como \theta^T. θ también se llama el «vector de peso» o «confianzas de la ecuación», siendo estos dos términos usados indistintamente. Y X=\begin{bmatrix}{1}\\{x_1}\\{x_2}\\{\cdots}\end{bmatrix} es el conjunto de características, que representa una observación. De todos modos, dado un conjunto de datos, todos los conjuntos de características X, \theta parámetros, se pueden calcular a través de un algoritmo de optimización o matemáticamente, que resulta en la ecuación de la línea adecuada.
Por ejemplo, si los parámetros de esta línea son \theta^T=\left [ -1, 0.1 \right ], entonces la ecuación de la línea es \theta^T \cdot X = -1 + 0.1 \cdot x_1. Ahora, podemos utilizar esta línea de regresión para predecir. Por ejemplo, para un valor de 13 tenemos: \theta^T \cdot X = -1 + 0.1 \cdot x_1 = -1 + 0.1 \cdot 13 = 0.3. Ahora podemos definir un umbral, por ejemplo, en 0.5, para definir la clase. Así que escribimos una regla para nuestro modelo, \hat y, que nos permite separar la clase 0 de la clase 1. Si el valor de \theta^T \cdot X es menor que 0.5, entonces la clase es 0, de lo contrario, si el valor de \theta^T \cdot X es más de 0.5, entonces la clase es 1. Y debido a que el valor «y» de nuestro ejemplo es menor que el umbral, podemos decir que pertenece a la clase 0, basada en nuestro modelo.

Pero aquí hay un problema, ya que no es el mejor modelo para conocer la probabilidad de pertenencia a la clase. Además, si utilizamos la línea de regresión para calcular la clase de un punto, siempre devuelve un número independientemente de lo grande o pequeño, positivo o negativo que es la entrada. Así utilizando el umbral, podemos encontrar la clase de un registro sin importar lo grande que sea el valor, siempre que sea mayor que 0.5, simplemente es igual a 1. Y viceversa, independientemente de lo pequeño que sea el valor, la salida sería cero si es menor que 0.5. En otras palabras, no hay diferencia entre un valor de uno o de 1000; el resultado sería 1. Este método no nos da realmente la probabilidad de que una observación pertenezca a una clase, lo cual es muy deseable. Así que necesitamos un método que también nos pueda dar la probabilidad de caer en una clase.

Función sigmoide

Funcion sigmoideSi en vez de usar \theta^T \cdot X usamos una función específica llamada sigmoide (\sigma), entonces, \sigma(\theta^T \cdot X) = \sigma(\theta_0 + \theta_1 \cdot x_1 + \cdots) nos da la probabilidad de que un punto pertenezca a una clase, en lugar del valor de y directamente. En lugar de calcular el valor de \theta^T \cdot X directamente, devuelve la probabilidad de que un \theta^T \cdot X sea muy grande o muy pequeño. Siempre devuelve un valor entre 0 y 1 dependiendo de que tan grande es \thta^T \cdot Xrealmente.
Ahora, nuestro modelo es \sigma(\theta^T \cdot X), que representa la probabilidad de que la salida sea 1, dado x. La función sigmoide, también llamada la función logística, se asemeja a la función de paso y se utiliza la siguiente expresión en la regresión logística:

\sigma(\theta^T X) = \frac{1}{1+e^{-\theta^T X}}

Fíjese en que en la ecuación sigmoide, cuando \theta^T X se hace muy grande, el e^{-\theta^T X} en el denominador de la fracción se convierte en casi cero, y el valor de la función sigmoid se acerca más a 1. Si \theta^T X es muy pequeño, la función sigmoide se acerca a cero. Representando en el trazado sigmoide, cuando \theta^T X, se hace más grande, el valor de la función sigmoide se acerca a 1, y también, si el \theta^T X es muy pequeño, la función sigmoide se acerca a cero. Por lo tanto, el valor de la función sigmoide está entre 0 y 1, lo que hace que sea apropiado para interpretar los resultados como probabilidades. Es obvio que cuando el resultado de la función sigmoide se acerca más a 1, la probabilidad de y, dado x, sube, y en contraste, cuando el valor sigmoide está más cerca de cero, la probabilidad de y, dado x, es muy pequeña.

Regresión logística

En la regresión logística, modelamos la probabilidad de que una entrada X pertenezca a la clase por defecto Y=1, y podemos escribirlo formalmente como, P(Y=1 \vert X). También podemos escribir P(y=0 \vert x) = 1 - P(y=1 \vert x). Por lo tanto, nuestro trabajo es entrenar al modelo para que establezca sus valores de parámetros de tal manera que nuestro modelo es una buena estimación de P(y=1 \vert x). De hecho, esto es lo que un buen modelo clasificador construido por regresión logística se supone que debe hacer por nosotros. Además, debe ser una buena estimación de P(y=0 \vert x) que se puede mostrar como 1 - \sigma(\theta^T X).
Vamos a ver cuál es el proceso para lograr el cálculo:

  1. Inicializar el vector con valores aleatorios, como se hace con la mayoría de los algoritmos de aprendizaje automático.
  2. Calcular la salida del modelo, que es \sigma(\theta^T X), para una observación de la muestra. La salida de esta ecuación es el valor de la predicción, la probabilidad que el cliente pertenece a la clase 1.
  3. Comparar la salida de nuestro modelo, \hat y, con la etiqueta real de la observación. Luego, registre la diferencia como el error de nuestro modelo para esta observación. Este es el error para una sóla observación dentro del conjunto de datos.
  4. Calcular el error para todas las observaciones tal como lo hicimos en los pasos anteriores, y añadimos estos errores. El error total es el coste del modelo. La función de coste representa la diferencia entre el real y los valores pronosticados del modelo. Por lo tanto, el costo muestra lo mal que se encuentra el modelo estimando las etiquetas del cliente. Por lo tanto, cuanto más bajo es el costo, mejor es el modelo estimando correctamente las etiquetas del cliente. Por lo tanto, lo que queremos hacer es tratar de minimizar este costo.
  5. Pero, debido a que los valores iniciales para \theta fueron elegidos al azar, es muy probable que la función de coste sea muy alta. Por lo tanto, cambiamos la forma de ser de tal manera que esperemos reducir el coste total.
  6. Después de cambiar los valores de \theta, volvemos al paso 2.

A continuación, empezamos otra iteración y calculamos de nuevo el coste del modelo. Y seguimos haciendo esos pasos una y otra vez, cambiando los valores de \theta cada vez, hasta que el coste es lo suficientemente bajo. Por lo tanto, esto plantea dos preguntas: ¿Cómo podemos cambiar los valores de \theta de modo que el coste se reduzca en las iteraciones? ¿Cuándo debemos detener las iteraciones?
Hay diferentes maneras de cambiar los valores \theta, pero una de las formas más populares es la ascendencia gradiente. Además, hay varias formas de detener las iteraciones, pero esencialmente se detiene la formación mediante el cálculo de la precisión de su modelo, y detenerlo cuando sea satisfactorio.

Ir al artículo anterior de la serie: Introducción a la Regresión Logística

Ir al artículo siguiente de la serie: Cálculo de los parámetros de la función logística

0 Seguir leyendo →

Introducción a la Regresión Logística

¿Que es regresión logística?

La regresión logística es una técnica estadística de machine learning para clasificar los registros de un conjunto de datos, basandose en los valores de los campos de entrada. En regresión logística, usaremos una o mas variables independientes para predecir un resultado, al cual llamaremos variable dependiente. La regresión logística es análoga a la regresión lineal pero intenta predecir un campo objetivo categórico o discreto en lugar de uno numérico.
En la regresión lineal, se intenta predecir variables de valor continuo (precio de una casa, presión sanguínea o consumo de gasolina). En regresión logística se predicen variables binarias (Si/No, Verdadero/Falso, Suceso o No suceso, embarazada o no). En la regresión logística las variables dependientes deben ser continuas, por lo que, si son categóricas hay que transformarlas en algún valor continuo. La regresión logística puede ser usada tanto para clasificación binaria como para multiclase, pero para simplificar, nos centraremos en la clasificación binaria.

¿Qué tipo de problemas pueden ser resueltos?

  • Predecir la probabilidad de que una persona tenga un ataque al corazón en un periodo especificado de tiempo, basado en nuestro conocimiento de la edad de la persona, sexo, e indice de masa corporal.
  • Predecir la probabilidad de mortalidad en un paciente herido, o predecir si un paciente tiene una enfermedad, como la diabetes, basado en las características observadas de ese paciente, como el peso, la altura, la presión sanguínea, y el resultado de varios test de sangre, etc.
  • En un contexto de marketing, podemos usarlo para predecir la probabilidad de un cliente de estar pagando o cancelando una suscripción.
  • También podemos usar regresión logística para predecir la probabilidad de fallo de un proceso, sistema o producto.
  • Podemos precedir la probabilidad del propietario de dejar de pagar la hipoteca.

En todos estos ejemplos no solo predecimos la clase de cada caso, tambien medimos la probabilidad de que un caso pertenezca a una clase específica.

¿Y en qué situaciones la usaremos?

Hay cuatro situaciones en las que la regresión logística es una buena candidata:

  • Primero, cuando el campo objetivo en los datos es categórico, o especificamente binario como son 0/1, si/no, positivo/negativo, etc.
  • Segundo, si se necesita la probabilidad de la predicción, por ejemplo, si se quiere conocer cual es la probabilidad de que un cliente compre un producto. La regresión logística devuelve una probabilidad entre 0 y 1 para una muestra dada.
  • Tercero, si los datos son linealmente separables. La frontera de decisión de una regresión logística es un línea o un plano o un hiperplano. Un clasificador clasificará todos los puntos en el lado de la línea de decisión al que pertenecen. Y los demás en el otro lado al que pertenece la otra clase. Por ejemplo, si tenemos dos características (y no se está aplicando un proceso polinómico), podremos obtener una inecuación como θ0 + θ1×1 + θ2×2 > 0, lo cuál es un medio plano facilmente dibujable. Usando regresión logística, podemos lograr un límite de decisión complejo usando procesos polinómicos.
  • Cuarto, si se necesita comprender el impacto de una característica. Se puede seleccionar las mejores características basadas en el significado estadístico
    de los coeficientes o parametros del modelo de regresión logística. Esto es, despues de encontrar los parametros óptimos, una característica X con el peso θ1 cercano a 0, tiene un efecto mas pequeño en la predicción, que características con amplios valores absolutos de θ1. Esto nos permite comprender el impacto de una variable independiente sobre una dependiente mientras controlamos otras variables independientes.

Ir al artículo anterior de la serie: Construyendo árboles de decisión

Ir al artículo siguiente de la serie: Regresión lineal Vs. regresión logística

0 Seguir leyendo →