Predictor de infidelidad (III): Ejemplo de regresión logística en Python

Paloma Recuero de los Santos    27 febrero, 2019
Ya estamos llegando al final del nuestro experimento. Tras introducir el problema y explorar el dataset en el primer post, y aprender cómo funciona el algoritmo de regresión logística, en el segundo, ya estamos listos para crear nuestro modelo a partir de los datos y… aplicarlo.  ¿Te animas a llegar hasta el final?
 
 
En este tercer y último  post aprenderemos lo siguiente:
  • Como crear un predictor usando el modelo de regresión logística de scikit-learn
  • Cómo valorar sus métricas 
  • Cómo hacer una predicción
  • Qué conclusiones podemos extraer

Retomamos pues, nuestro Python notebook, donde, ya habíamos realizado la carga y exploración de los datos y creado la variable objetivo, a la que llamamos “infidelity”. 

 

(Como hemos hecho en los post anteriores, primero, explicaremos paso a paso con imágenes cómo hacerlo, y al final del proceso, incorporamos la versión final editable de la que podéis copiar directamente el código para pegarlo en vuestro notebook )

 

3. Aplicación del modelo.

 

Para aplicar el modelo de regresión logística, vamos a usar una librería de Python, Patsy, que permite generar de forma muy cómoda el formato de matrices con el que funciona este modelo. Vamos a recordar un poco cómo era la notación matemática, para entender cuál debe ser el formato de entrada al modelo. La regresión logística era una transformación lineal (con salida no lineal) que se podía expresar de la siguiente manera:

Fórmula de una transformación lineal.
Figura 1: Fórmula de una transformación lineal.

Donde Y es la variable dependiente u objetivo que queremos estimar (“infidelity”), y X son las variables dependientes o predictoras, que “condicionan” el valor de la Y (“age”, “religious”, “children” etc). Los valores de los coeficientes βi son los que el modelo va a aprender” entrenándose con valores conocidos del dataset. Una vez entrenado el modelo, será capaz de predecir qué valor tendrá Y para un caso no recogido en los datos de entrenamiento. La fórmula  también puede expresarse de esta forma, como producto escalar:

Transformación lineal expresada como producto escalar.
Figura 2: Transformación lineal expresada como producto escalar.

Si  generalizamos para más de una observación Xi, necesitamos generar una matriz como esta:

Transformación lineal expresada de forma matricial.
Figura 3: Transformación lineal expresada de forma matricial.

3.1 Formateamos los datos con Patsy

La librería Patsy permite, precisamente, generar estas matrices de forma muy ágil gracias a la función dmatrices   y a su notación de fórmula. Además, dmatrices añade de forma automática la columna de “1” necesaria para obtener los términos de corte (εi), conocidos como “intercept terms”.

Otra de las ventajas de Patsy es que permite trabajar con datos categóricos de forma muy flexible, gracias a la función C(), que indica que los datos entre los paréntesis deben tratarse como etiquetas y no como números. En nuestro ejemplo, vamos a usarlo para que no considere como números los códigos de ocupación. Esta operación es lo que se llama, convertir datos en “dummy”.

Por tanto, al aplicar la función dmatrices con esta sintaxis, obtenemos como resultado dos matrices. La primera, con los resultados o valores de la variable objetivo “y”, y la segunda, con los valores de las variables independientes X o datos predictores:

Sintaxis de de función dmatrices de Patsy.
Figura 4: Sintaxis de de función dmatrices de Patsy.
 

Para nuestro ejemplo:

y, X = dmatrices(‘infidelity ~ rate_marriage + age +  yrs_married + children + religious+ educ + C(occupation) + C(occupation_husb) ‘, dta, return_type = ‘dataframe’)

Con esta sentencia obtenemos las dos matrices que hemos mencionado antes, en las que los valores de  “infidelity”(y) son iguales al producto de los valores de la matriz que representa las variables independientes (X) por unos coeficientes, más un término de corte. Al mismo tiempo indicamos que no use los valores de códigos de ocupación como numéricos sino como categóricos.

Código para convertir la matriz de datos en el formato necesario para aplicar el modelo.
Figura 5: Código para convertir la matriz de datos en el formato necesario para aplicar el modelo.

Comprobamos las dimensiones de las matrices de salida, y sus índices:

Código para comprobar las dimensiones de las matrices.
Figura 6: Código para comprobar las dimensiones de las matrices.

3.2 Aplicamos el modelo

Ya sólo nos queda un último paso para poder aplicar el modelo de regresión logística de scikit-learn, y es convertir el vector columna y en matriz 1D.  A continuación, ya podemos aplicar directamente el modelo LogisticRegression. Como resultado del entrenamiento del modelo, obtenemos la matriz de coeficientes:

Aplicación del modelo.
Figura 7: Aplicación del modelo.

Podemos ver que la precisión del modelo es de un 73%:

Estimación de la precisión.
Figura 8: Estimación de la precisión.

 

También, podemos estimar también qué porcentaje de individuos tienen alguna aventura, obteniendo un resultado de un 32%

 

 

Porcentaje de individuos infieles.
Figura 9: Porcentaje de individuos infieles.
La matriz de coeficientes obtenida muestra qué peso tiene cada uno de los coeficientes. Para visualizarlo, podemos usar List(zip), que crea una matriz a partir de dos listas, la que contiene el nombre de los índices, en la primera columna, y los valores en la segunda.

 

Código para obtener la matriz de coeficientes.
Figura 10: Código para obtener la matriz de coeficientes.
Por ejemplo, podemos ver cómo los incrementos en rate_marrige y religiousnes disminuyen la probabilidad de infidelidad. Lo cual es consistente con el análisis de correlación de variables que hicimos en el primer post.

 

 
Coeficientes.
Figura 11: Coeficientes.

 

3.3 Evaluamos el modelo

Para evaluar el modelo, dividimos el dataset en dos partes. Dejamos un 75% de los datos como datos de entrenamiento (train), y reservamos el 25% restando como datos de prueba (test). A continuación, entrenamos el modelo de nuevo, pero ahora sólo con los datos de entrenamiento. 

 
Dividimos el dataset en train y test.
Figura 12: Dividimos el dataset en train y test.
 
Una vez entrenado el modelo, lo aplicamos a los datos reservados como “test”, y calculamos las  métricas precisión (Accurary) y exactitud (Precision). Cuidado con los “false friends”-
 
Hemos obtenido unos valores de un 73% para la precisión, que no es que sea muy alto, pero tampoco es un mal resultado. Indica que la dispersión de los valores es baja. Sin embargo, la exactitud, es sólo de un 62%. No es un dato muy bueno, ya que se refiere a lo cerca que está un resultado del valor verdadero.

 

 
Los valores de la diagonal principal de la matriz de confusión (993, 176) indican las predicciones correctas, tanto para verdaderos positivos, como verdaderos negativos. La otra diagonal (con valores 316, 117) recoge las predicciones erróneas.

 

 
 Calculamos precisión, exactitud y matriz de confusión.
Figura 13: Calculamos precisión, exactitud y matriz de confusión.
 
 
Para ver la matriz de confusión de forma mucho más “visual”, podemos hacerlo en forma de mapa de calor:

 

 
Vemos la matriz de confusión como mapa de calor usando seaborn.
Figura 14: Código para ver la matriz de confusión como mapa de calor usando seaborn.
Matriz de confusión en forma de mapa de calor.
Figura 15: Matriz de confusión en forma de mapa de calor.

3.4 Hacemos una predicción

 
Por último, ya sólo nos queda hacer una predicción usando el modelo que acabamos de crear.  Para que nos resulta más fácil “escribir” los datos de entrada, usaremos el indexador iloc para extraer ,como ejemplo, uno de los registros de la matriz de datos. En particular hemos elegido el registro número 4.
 

 

Extraemos un registro del dataset como ejemplo.
Figura 16: Extraemos un registro del dataset como ejemplo.
 
Como resultado, podemos ver el aspecto que tiene este registro en concreto, lo reconvertimos en el formato necesario para poder aplicar el modelo y, ya que estamos, lo probamos. En este caso, la probabilidad de infidelidad es de un 30%.
 
Visualización de ese registro concreto.
Figura 17: Visualización de ese registro concreto.

A continuación, lo usaremos de base para introducir en el modelo los datos concretos para los que queremos obtener una predicción mediante el método keys(). Por ejemplo: mujer de 35 años, con 3 hijos, no religiosa,nivel educativo alto, con ocupaciones (ambos) técnicos especializados y una buena valoración de su matrimonio.

 

F.keys();F[‘age’]=35; F[‘children’]=3; F[‘yrs_married’]=10; F[‘religious’]=1; F[‘religious’]=1; F[‘C(occupation_husb)[T.3.0]’]=1

 

Cambiamos con F.keys() los valores de cada variable para introducir los que queramos

Figura 18: Cambiamos con F.keys() los valores de cada variable para introducir los que queramos





 

Al aplicar el modelo a este caso en particular, obtenemos como resultado una probabilidad de infidelidad del 29%. Prueba con los datos que quieras, ¿qué resultados obtienes?

esultado obtenido al aplicar el modelo al nuevo caso.
Figura 19: Resultado obtenido al aplicar el modelo al nuevo caso.
 
 
¿Te animas a probarlo?
 
A continuación, tienes el código completo del experimento, que puedes cortar y pegar en tu Jupyter notebook. Te recomendamos que lo vayas haciendo paso a paso, como lo hemos explicado, para poder entender qué se hace en cada momento. Incluso, puedes ir introduciendo pequeñas modificaciones para probar cosas nuevas.g
 


#Importamos los módulos y librerías que vamos a necesitar
#!/usr/bin/env python -W ignore::DeprecationWarning
#!/usr/bin/env python -W ignore::FutureWarning

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt 
import statsmodels.api as sm
import seaborn as sns

from patsy import dmatrices
from scipy import stats
from sklearn import metrics
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
In [3]:
#Cargamos los datos
dta = sm.datasets.fair.load_pandas().data
dta.head(10)
Out[3]:
rate_marriage	age	yrs_married	children	religious	educ	occupation	occupation_husb	affairs
0	3.0	32.0	9.0	3.0	3.0	17.0	2.0	5.0	0.111111
1	3.0	27.0	13.0	3.0	1.0	14.0	3.0	4.0	3.230769
2	4.0	22.0	2.5	0.0	1.0	16.0	3.0	5.0	1.400000
3	4.0	37.0	16.5	4.0	3.0	16.0	5.0	5.0	0.727273
4	5.0	27.0	9.0	1.0	1.0	14.0	3.0	4.0	4.666666
5	4.0	27.0	9.0	0.0	2.0	14.0	3.0	4.0	4.666666
6	5.0	37.0	23.0	5.5	2.0	12.0	5.0	4.0	0.852174
7	5.0	37.0	23.0	5.5	2.0	12.0	2.0	3.0	1.826086
8	3.0	22.0	2.5	0.0	2.0	12.0	3.0	3.0	4.799999
9	3.0	27.0	6.0	0.0	1.0	16.0	3.0	5.0	1.333333
In [4]:
#Información sobre el dataset: descripción general, origen, 
#definición de variables,tipo de variables

print(sm.datasets.fair.NOTE)
print(sm.datasets.fair.SOURCE)
print(sm.datasets.fair.DESCRLONG)

dta.info()
::

    Number of observations: 6366
    Number of variables: 9
    Variable name definitions:

        rate_marriage   : How rate marriage, 1 = very poor, 2 = poor, 3 = fair,
                        4 = good, 5 = very good
        age             : Age
        yrs_married     : No. years married. Interval approximations. See
                        original paper for detailed explanation.
        children        : No. children
        religious       : How relgious, 1 = not, 2 = mildly, 3 = fairly,
                        4 = strongly
        educ            : Level of education, 9 = grade school, 12 = high
                        school, 14 = some college, 16 = college graduate,
                        17 = some graduate school, 20 = advanced degree
        occupation      : 1 = student, 2 = farming, agriculture; semi-skilled,
                        or unskilled worker; 3 = white-colloar; 4 = teacher
                        counselor social worker, nurse; artist, writers;
                        technician, skilled worker, 5 = managerial,
                        administrative, business, 6 = professional with
                        advanced degree
        occupation_husb : Husband's occupation. Same as occupation.
        affairs         : measure of time spent in extramarital affairs

    See the original paper for more details.


Fair, Ray. 1978. "A Theory of Extramarital Affairs," `Journal of Political
Economy`, February, 45-61.

The data is available at http://fairmodel.econ.yale.edu/rayfair/pdf/2011b.htm

Extramarital affair data used to explain the allocation
of an individual's time among work, time spent with a spouse, and time
spent with a paramour. The data is used as an example of regression
with censored data.

RangeIndex: 6366 entries, 0 to 6365
Data columns (total 9 columns):
rate_marriage      6366 non-null float64
age                6366 non-null float64
yrs_married        6366 non-null float64
children           6366 non-null float64
religious          6366 non-null float64
educ               6366 non-null float64
occupation         6366 non-null float64
occupation_husb    6366 non-null float64
affairs            6366 non-null float64
dtypes: float64(9)
memory usage: 447.7 KB
In [5]:
#Comprobamos que no falten datos (Resultado booleano: true=falta dato, false=dato)
#También se puede visualizar si faltan datos con los mapas de calor de seaborn.
#En este caso, no hace falta.

dta.isnull().head(10)
Out[5]:
rate_marriage	age	yrs_married	children	religious	educ	occupation	occupation_husb	affairs
0	False	False	False	False	False	False	False	False	False
1	False	False	False	False	False	False	False	False	False
2	False	False	False	False	False	False	False	False	False
3	False	False	False	False	False	False	False	False	False
4	False	False	False	False	False	False	False	False	False
5	False	False	False	False	False	False	False	False	False
6	False	False	False	False	False	False	False	False	False
7	False	False	False	False	False	False	False	False	False
8	False	False	False	False	False	False	False	False	False
9	False	False	False	False	False	False	False	False	False
In [6]:
# Veamos ahora la matriz de correlación. 
# Deberíamos eliminar las variables altamente correlacionadas >0,90
# Edad, años matrimonio-- lógica
# Correlación positiva--religious/rate marriage,age/yrs_marriage
# Correlación negativa: affairs/children, religious

print(dta.corr())

#Edad, años matrimonio-- lógicamente no son independientes, para eliminarlos habría que hacer:
#dta.drop(['age','yrs_married'],axis=1,inplace=True)
#dta.head()
                 rate_marriage       age  yrs_married  children  religious  \
rate_marriage         1.000000 -0.111127    -0.128978 -0.129161   0.078794   
age                  -0.111127  1.000000     0.894082  0.673902   0.136598   
yrs_married          -0.128978  0.894082     1.000000  0.772806   0.132683   
children             -0.129161  0.673902     0.772806  1.000000   0.141845   
religious             0.078794  0.136598     0.132683  0.141845   1.000000   
educ                  0.079869  0.027960    -0.109058 -0.141918   0.032245   
occupation            0.039528  0.106127     0.041782 -0.015068   0.035746   
occupation_husb       0.027745  0.162567     0.128135  0.086660   0.004061   
affairs              -0.178068 -0.089964    -0.087737 -0.070278  -0.125933   

                     educ  occupation  occupation_husb   affairs  
rate_marriage    0.079869    0.039528         0.027745 -0.178068  
age              0.027960    0.106127         0.162567 -0.089964  
yrs_married     -0.109058    0.041782         0.128135 -0.087737  
children        -0.141918   -0.015068         0.086660 -0.070278  
religious        0.032245    0.035746         0.004061 -0.125933  
educ             1.000000    0.382286         0.183932 -0.017740  
occupation       0.382286    1.000000         0.201156  0.004469  
occupation_husb  0.183932    0.201156         1.000000 -0.015614  
affairs         -0.017740    0.004469        -0.015614  1.000000  
In [7]:
#También podemos ver la matriz de correlación de forma gráfica
#Si los coeficientes son muy bajos, significa que la influencia 
#de esa variable es muy pequeña y,podríamos plantearnos una "reducción" 
#de estas para simplifacar el modelo, pero en este ejemplo no vamos a
#quitar ninguna

%matplotlib inline
sns.heatmap(dta.corr(), annot=True)
Out[7]:


In [8]:
#En la fase de exploración, podemos visualizar las variables y 
#sus relaciones mediante histogramas

#Para que muestre los gráficos en el notebook añadimos:
%matplotlib inline

# histograma sobre influencia del nivel educativo
dta.educ.hist()
plt.title('Influencia del Nivel Educativo')
plt.xlabel('Nivel Académico')
plt.ylabel('Frecuencia infidelidad')
Out[8]:
Text(0,0.5,'Frecuencia infidelidad')

In [9]:
# Creamos una nueva variable binaria "infidelity" para tratarlo
#como un problema de clasificación 0=fiel, 1=infiel
# Mostramos los 10 primeros ... infieles

dta['infidelity'] = (dta.affairs > 0).astype(int)
print(dta.head(10))
dta.shape
   rate_marriage   age  yrs_married  children  religious  educ  occupation  \
0            3.0  32.0          9.0       3.0        3.0  17.0         2.0   
1            3.0  27.0         13.0       3.0        1.0  14.0         3.0   
2            4.0  22.0          2.5       0.0        1.0  16.0         3.0   
3            4.0  37.0         16.5       4.0        3.0  16.0         5.0   
4            5.0  27.0          9.0       1.0        1.0  14.0         3.0   
5            4.0  27.0          9.0       0.0        2.0  14.0         3.0   
6            5.0  37.0         23.0       5.5        2.0  12.0         5.0   
7            5.0  37.0         23.0       5.5        2.0  12.0         2.0   
8            3.0  22.0          2.5       0.0        2.0  12.0         3.0   
9            3.0  27.0          6.0       0.0        1.0  16.0         3.0   

   occupation_husb   affairs  infidelity  
0              5.0  0.111111           1  
1              4.0  3.230769           1  
2              5.0  1.400000           1  
3              5.0  0.727273           1  
4              4.0  4.666666           1  
5              4.0  4.666666           1  
6              4.0  0.852174           1  
7              3.0  1.826086           1  
8              3.0  4.799999           1  
9              5.0  1.333333           1  
Out[9]:
(6366, 10)
In [10]:
#Patsy es una librería de Python que permite convertir los datos 
#en el formato de matriz necesario para aplicar el modelo
#También permite generar variables dummy mediante la función C()
#La sintaxis es:

#patsy.dmatrix(formula_like, data={}, eval_env=0, NA_action='drop', return_type='matrix')

from patsy import dmatrices

y, X = dmatrices('infidelity ~ rate_marriage + age +  yrs_married + children + religious+ educ + C(occupation) + C(occupation_husb) ', dta, return_type = 'dataframe')

#Comprobamos las dimensiones y los índices de las matrices resultado
print(X.shape)
print(y.shape)
print (X.columns)
print(y.columns)
(6366, 17)
(6366, 1)
Index(['Intercept', 'C(occupation)[T.2.0]', 'C(occupation)[T.3.0]',
       'C(occupation)[T.4.0]', 'C(occupation)[T.5.0]', 'C(occupation)[T.6.0]',
       'C(occupation_husb)[T.2.0]', 'C(occupation_husb)[T.3.0]',
       'C(occupation_husb)[T.4.0]', 'C(occupation_husb)[T.5.0]',
       'C(occupation_husb)[T.6.0]', 'rate_marriage', 'age', 'yrs_married',
       'children', 'religious', 'educ'],
      dtype='object')
Index(['infidelity'], dtype='object')
In [11]:
#Para que scikit-learn entienda y como variable dependiente (target)
#debemos convertirla de vector columna en matriz 1D
y=np.ravel(y)
print(y)

# sklearn output
model = LogisticRegression(fit_intercept = False, C = 1e9)
mdl = model.fit(X, y)
model.coef_
[ 1.  1.  1. ...,  0.  0.  0.]
Out[11]:
array([[  3.02618999e+00,   3.49733210e-01,   6.61853517e-01,
          4.31150708e-01,   1.01297621e+00,   1.06658685e+00,
          1.60404225e-01,   2.73983554e-01,   1.32893449e-01,
          1.62639164e-01,   1.73031585e-01,  -7.10360913e-01,
         -6.13554596e-02,   1.08087003e-01,   1.55318807e-02,
         -3.75392191e-01,  -1.96584314e-03]])
In [12]:
# Veamos la precisión del modelo (sobre los datos de entrenamiento) 73%
# Más adelante volveremos a entrenar el modelo, pero separando antes los
# datos en train y test. Volveremos a calcular la precisión del modelo
# entrenado sobre los datos train al aplicarlo a los test

model.score(X,y)
Out[12]:
0.72510210493245364
In [13]:
#¿Qué porcentaje tiene aventuras?: 32%-- 
#Si predecimos siempre "no", acertaríamos el 68% de las veces,
#algo mejor que el error nulo pero no mucho

y.mean()
Out[13]:
0.32249450204209867
In [14]:
# Podemos examinar la matriz de coeficientes, para ver qué peso tiene
# cada uno de los coeficientes. List(zip) permite crear una matriz
# a partir de dos listas, el nombre de los índices, en la primera columna
# y en la segunda, los valores
#pd.DataFrame(list(zip(X.columns, np.transpose(model.coef_)))

pd.DataFrame(list(zip(X.columns, np.transpose(model.coef_))))

# Por ejemplo, los incrementos en rate_marrige y religiousnes disminuyen 
# la probabilidad de infidelidad (coefientes negativos)
Out[14]:
0	1
0	Intercept	[3.02618998703]
1	C(occupation)[T.2.0]	[0.349733209538]
2	C(occupation)[T.3.0]	[0.661853517181]
3	C(occupation)[T.4.0]	[0.431150707917]
4	C(occupation)[T.5.0]	[1.01297621288]
5	C(occupation)[T.6.0]	[1.06658684973]
6	C(occupation_husb)[T.2.0]	[0.160404224729]
7	C(occupation_husb)[T.3.0]	[0.27398355359]
8	C(occupation_husb)[T.4.0]	[0.132893449067]
9	C(occupation_husb)[T.5.0]	[0.162639163742]
10	C(occupation_husb)[T.6.0]	[0.17303158544]
11	rate_marriage	[-0.710360913438]
12	age	[-0.0613554595525]
13	yrs_married	[0.10808700349]
14	children	[0.0155318806807]
15	religious	[-0.375392191185]
16	educ	[-0.00196584314225]
In [15]:
# Para evaluar el modelo, dividimos el dataset en dos partes
# un 75% de los datos para entrenar el modelo
# y el 25% restante para evaluarlo

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=0)

# Ahora, aplicamos el modelo sobre los datos reservados para entrenamiento "train"

model2 = LogisticRegression()
model2.fit(X_train, y_train)
Out[15]:
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
          intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,
          penalty='l2', random_state=None, solver='liblinear', tol=0.0001,
          verbose=0, warm_start=False)
In [16]:
# Una vez entrenado el modelo, lo aplicamos a los datos reservados para "test"

predicted = model2.predict(X_test)
print (predicted)

# Generamos las métricas de evaluación 
# Cuidado con los "false friends"
# "Accuracy" es la precisión, y "Precision" es la exactitud

print("Accuracy:",metrics.accuracy_score(y_test, predicted))
print("Precision:",metrics.precision_score(y_test, predicted))

# Generamos la matriz de confusión

cnf_matrix = metrics.confusion_matrix(y_test, predicted)
cnf_matrix
[ 1.  0.  0. ...,  0.  1.  1.]
Accuracy: 0.734296482412
Precision: 0.621908127208
Out[16]:
array([[993, 107],
       [316, 176]], dtype=int64)
In [17]:
#Podemos visualizarla con un mapa de calor
#Diagonal values represent accurate predictions, while non-diagonal elements are inaccurate predictions.
#In the output, 119 and 36 are actual predictions, and 26 and 11 are incorrect predictions.


#The accuracy is 73%, which is the same as we experienced when training and predicting on the same data.
#We can also see the confusion matrix and a classification report with other metrics.
In [18]:
# Importamos los módulos necesarios

class_names=[0,1] # name  of classes
fig, ax = plt.subplots()
tick_marks = np.arange(len(class_names))
plt.xticks(tick_marks, class_names)
plt.yticks(tick_marks, class_names)

# Creamos un mapa de calor

sns.heatmap(pd.DataFrame(cnf_matrix), annot=True, cmap="YlGnBu" ,fmt='g')
ax.xaxis.set_label_position("top")
plt.tight_layout()
plt.title('Confusion matrix', y=1.1)
plt.ylabel('Actual label')
plt.xlabel('Predicted label')
Out[18]:
Text(0.5,257.44,'Predicted label')

In [19]:
# Vamos a usar el modelo para hacer una predicción

# Para que nos resulta más fácil "escribir" los datos de entrada, 
# vamos a sacar un ejemplo de uno de los registros de la matriz de 
# datos, por ejemplo, el 4º, y después lo usaremos de base para 
# introducir en el modelo los datos que querarmos.

print(X.iloc[4])
F=X.iloc[4]
F.shape

#Con reshape(1,-1) indicamos que lo convierta en una matriz de 1 fila y 
#el número de columnas que corresponda para que la nueva forma sea  
#compatible con la original

F.values.reshape(1,-1)
model.predict_proba(F.values.reshape(1, -1))
Intercept                     1.0
C(occupation)[T.2.0]          0.0
C(occupation)[T.3.0]          1.0
C(occupation)[T.4.0]          0.0
C(occupation)[T.5.0]          0.0
C(occupation)[T.6.0]          0.0
C(occupation_husb)[T.2.0]     0.0
C(occupation_husb)[T.3.0]     0.0
C(occupation_husb)[T.4.0]     1.0
C(occupation_husb)[T.5.0]     0.0
C(occupation_husb)[T.6.0]     0.0
rate_marriage                 5.0
age                          27.0
yrs_married                   9.0
children                      1.0
religious                     1.0
educ                         14.0
Name: 4, dtype: float64
Out[19]:
array([[ 0.69041584,  0.30958416]])
A partir del registro F que hemos extraído del conjunto de datos, podemos configurar un registro nuevo con los valores que queramos para que el modelo prediga la probabilidad de infidelidad. Vamos asignado los valores variable a varible, y luego le daremos la forma necesaria para poder introducirlos en el modelo.

Por ejemplo, mujer de 35 años, con 3 hijos, no religiosa,nivel educativo alto, con ocupaciones (ambos) técnicos especializados y una buena valoración de su matrimonio

In [23]:
F.keys();
F['age']=35; F['children']=3; F['yrs_married']=10; F['religious']=1; F['religious']=1; F['C(occupation_husb)[T.3.0]']=1
print(F.values)
[  1.   0.   1.   0.   0.   0.   0.   1.   1.   0.   0.   5.  35.  10.   3.
   1.  14.]
In [24]:
# Aplicamos el modelo a este nuevo conjunto de valores y obtenmos
# la probabilidad de infidelidad que, en este caso es de un 29%

F.values.reshape(1,-1)
model.predict_proba(F.values.reshape(1, -1))
[[  1.   0.   1.   0.   0.   0.   0.   1.   1.   0.   0.   5.  35.  10.
    3.   1.  14.]]
Out[24]:
array([[ 0.70677527,  0.29322473]])
   

4. Conclusiones

Llegado el momento de sacar conclusiones, tenemos que pararnos a reflexionar. ¿Cuál ha sido el objetivo del experimento?. Hemos aprendido a crear un modelo de predicción basado en regresión logística. Hemos conocido y aprendido a cargar los datasets de Statsmodels. Hemos recordado un poco de álgebra de matrices para comprender mejor el modelo. Y sí, hemos aplicado el modelo a nuestros datos (¿a que no te has resistido?), pero ¿tiene algún tipo de validez el resultado?.

A pesar de haber hecho un análisis serio, que, por supuesto se podría haber hecho siguiendo otros enfoques, por ejemplo, reduciendo por ejemplo el número de variables a considerar tras el análisis de correlación, o aplicando el modelo de staatsmodel en lugar del del scikit learn, o incluso eligiendo otro algoritmo de clasificación; nunca debemos olvidar sobre qué estamos construyendo nuestro modelo. Nos referimos, por supuesto, a los datos. Y un dataset cuyo origen es una encuesta realizada en los años 70 por una revista femenina en EEUU no parece que pueda ser extrapolable al momento actual, ni a latitudes tan distantes como la nuestra. Si embargo, en la era de las apps “para ligar” o encontrar tu media naranja, hay que ser conscientes de lo que una buena analítica de datos podría obtener a partir de sus bases de datos que, por supuesto, están protegidas por leyes de privacidad. Pero…ahí están.

Aquí puedes encontrar todos los post de este experimento:

  1. Especial San Valentin: ¿Podemos predecir la infidelidad con IA? 
  2. Predictor de infidelidad (II): ¿Qué es la regresión logística? 
  3. Predictor de infidelidad (III): Un ejemplo de regresión logística sobre el dataset “Affairs” (este post)

Para mantenerte al día con LUCA visita nuestra página web,  suscríbete a LUCA Data Speaks o síguenos en TwitterLinkedIn YouTube.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *