Lab 6: Interpreting and Evaluating Logistic Regression Models#

This lab is adapted from AM207 (Harvard). Data files are in the book’s data/ folder. Worked solutions are collapsed: try each exercise before expanding them.

Hide code cell content

### Import basic libraries
import numpy as np
import pandas as pd
import sklearn as sk
from sklearn.linear_model import LogisticRegression
from sklearn.calibration import calibration_curve
import matplotlib.pyplot as plt
from pymc3 import model_to_graphviz, Model
import pymc3 as pm
%matplotlib inline
def plot_decision_boundary(x, y, models, ax, poly_degree=1):
    '''
    plot_decision_boundary plots the training data and the decision boundary of the classifier.
    input:
       x - a numpy array of size N x 2, each row is a patient, each column is a biomarker
       y - a numpy array of length N, each entry is either 0 (no cancer) or 1 (cancerous)
       model - the 'sklearn' classification model
       ax - axis to plot on
       poly_degree - the degree of polynomial features used to fit the model
    returns: 
       ax - the axis with the scatter plot
    
    '''
    # Plot data
    ax.scatter(x[y == 1, 0], x[y == 1, 1], alpha=0.2, c='red', label='class 1')
    ax.scatter(x[y == 0, 0], x[y == 0, 1], alpha=0.2, c='blue', label='class 0')
    
    # Create mesh
    interval = np.arange(-4, 4.1, 0.1)
    n = np.size(interval)
    x1, x2 = np.meshgrid(interval, interval)
    x1 = x1.reshape(-1, 1)
    x2 = x2.reshape(-1, 1)
    xx = np.concatenate((x1, x2), axis=1)

    # Predict on mesh points
    if(poly_degree > 1):
        polynomial_features = PolynomialFeatures(degree=poly_degree)
        xx = polynomial_features.fit_transform(xx)
    
    if len(models) > 1:
        alpha_line = 0.1
    else:
        alpha_line = 1.
        
    i = 0
    
    for model in models:
        yy = model.predict(xx)  
        yy = yy.reshape((n, n))

        # Plot decision surface
        x1 = x1.reshape(n, n)
        x2 = x2.reshape(n, n)
        ax.contourf(x1, x2, yy, alpha=0.2 * 1. / (i + 1)**2, cmap='bwr')
        ax.contour(x1, x2, yy, colors='black', linewidths=0.5, alpha=alpha_line)
        
        i += 1
        
    ax.set_xlim((-4, 4))
    ax.set_ylim((-4, 4))
    ax.set_xlabel('marker 1')
    ax.set_ylabel('marker 2')
    ax.legend(loc='best')
    return ax

Problem Description: Modeling Preterm Births#

You are given the birth mother data (normalized) for approximately 2,000 newborns in California between the years 2000 and 2001 (lab_6_data.csv). Previous studies have indicated that demographic factors of the birth mother strongly affects the risk of preterm births (preterm here means a gestational age of less than 37 weeks). Your task is to investigate whether or not this assertion holds for the dataset at hand.

Modeling for Testing Scientific Hypotheses#

We can investigate our hypothesis – that demographic factors of the birth mother strongly affects the risk of preterm births – in multiple ways:

  1. visualize the joint distribution of the covariates – color preterm births differently than the full term births. From the way the data looks, is there any evidence to support our hypothesis?

  2. visualize marginal distribution of the covariates. For each covariate, make two histograms on the same plot, one for preterm births, another for full-term births. From the way the marginals look, is there any evidence to support our hypothesis?

  3. In Chapter 15, we showed that fitting a logistic regression model to explain Bernoulli outcomes is the same as fitting a hyperplane (a decision boundary) to separate (or classify) two classes of data in covariate-space. Use sklearn’s logistic regression model (set the parameter C to be large), to find the MLE of the coefficients of a logistic regression model for this dataset.

    1. Extract and interpret the MLE coefficients found by your sklearn model (coef_, intercept_). What do these coefficients tell you about the relationship between demographic factors of the birth mother and the risk of preterm birth?

    2. Visualize the decision boundary of the MLE logistic regression model using the plot_decision_boundary function provided to you. What does this visualization tell you about the reliability of your conclusions about the relationship between demographic factors of the birth mother and the risk of preterm birth?

Model Evaluation#

Predictiveness#

There are multiple ways to evaluate your logistic regression model:

  1. One way is to predict or classify data points as preterm or full term depending on the \(\theta^{(n)}\) that your model predicts for the \(n\)-th observation. You can then evaluate the predictive accuracy (use sklearn’s .score() function). What does the predictive accuracy of your model tell you about the reliability of your conclusions about the relationship between demographic factors of the birth mother and the risk of preterm birth?

  2. Another way to evaluate your model is to look at the actual probabilities \(\theta^{(n)}\)’s that it predicts. We bin the observations according to the value of \(\theta^{(n)}\) predicted by the model, for a fixed bin ( \(a<\theta^{(n)}<b\) ) we compute the actual percentage of observations that have label \(y=1\) and compare with the predicted percentage \(\theta_n\). We say a model is miscalibrated if the predicted percentage is consistently different from the actual. We can plot the actual percentage against the predicted in a calibration plot (use sklearn.calibration.calibration_curve). What does your calibration plot say about your model?

Uncertainty#

Evaluating a single MLE model fitted on the observed data gives you no sense of how sensitive the model is to small changes in the data. We can easily test our model’s sensitivity:

  1. bootstrapping your data, fit 100 MLE logistic regression models. Compute the mean MLE coefficients (averaged over 100 bootstrap estimates). What do these coefficients tell you about the relationship between demographic factors of the birth mother and the risk of preterm birth?

  2. visualize the decision boundaries of all of these bootstrap MLE models. What does this visualization tell you about the reliability of your conclusions about the relationship between demographic factors of the birth mother and the risk of preterm birth?

A Bayesian Approach#

Repeat all of the above for a Bayesian logistic regression model of your data. In particular, compare the uncertainty estimation:

  1. Compare the uncertainty from the bootstrap MLE and the uncertainty from the posterior of the Bayesian model, which type of uncertainty is more reliable or informative? Why?

Data Heterogeneity#

Recall from the many examples in this book that it is often useful to break up the data into categories and fit a model for each category. This is especially true if the variations in the data is heterogeneous.

  1. look at the our data, is there any heterogeneity in the data? Do you think there would be any benefit in break up the data and fitting separate models for each subset?

  2. in the case of the kidney cancer data set, it was easy to break up the data into categories based on the county. If we wanted to break up this dataset, how would we do it?

Hide code cell source

df = pd.read_csv('../data/lab_6_data.csv')
df.head()
mothers income (normalized) mothers age (normalized) preterm
0 -0.400228 -0.926880 0
1 1.076102 1.180291 1
2 -0.922953 0.306167 0
3 0.897991 2.407370 1
4 1.506738 2.583626 1

Hide code cell content

X = df[['mothers income (normalized)', 'mothers age (normalized)']].values
y = df['preterm'].values