<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Cooks Distance
See more at Cook's Distance. A very good description of influence and leverage can be found at Linear Regression in Python, Outliers / Leverage Detect (this post should make it into the Yellowbrick documentation in some form). 
A good description of outlier detection that also includes Cook's Distance is How to Make Your Machine Learning Models Robust to Outliers. Original motivating post is at How do you check the quality of your regression model in Python? - source code for this post is at 
Visual analytics and diagnostics of model fit for linear regression.
The statsmodels source code for Cook's Distance is at
Step1:  Random Test Data
For the purpose of generating tests for the visualizer, I'm using random test data. The compressive concrete strength dataset would also be good for integration testing.
Step2:  Statsmodels Results
For comparison to the custom computation, this section computes the statsmodels OLS model and Cook's Distance values. In a later section we will compare this to scikit-learn linear regression and the Yellowbrick cooks function.
Step3:  Scikit-Learn Cook's Distance
<ASSISTANT_TASK:>
Python Code:
%matplotlib notebook
import scipy as sp
import numpy as np
import pandas as pd 
import matplotlib.pyplot as plt 
# Note: statsmodels requires scipy 1.2
import statsmodels.formula.api as sm
from sklearn.datasets import make_regression
from sklearn.linear_model import LinearRegression
from statsmodels.stats.outliers_influence import OLSInfluence as influence
from yellowbrick.base import Visualizer
Explanation: Cooks Distance
See more at Cook's Distance. A very good description of influence and leverage can be found at Linear Regression in Python, Outliers / Leverage Detect (this post should make it into the Yellowbrick documentation in some form). 
A good description of outlier detection that also includes Cook's Distance is How to Make Your Machine Learning Models Robust to Outliers. Original motivating post is at How do you check the quality of your regression model in Python? - source code for this post is at 
Visual analytics and diagnostics of model fit for linear regression.
The statsmodels source code for Cook's Distance is at:
Outliers Influence
Linear Model
NumPy Linear Algebra
End of explanation
# Make Test Dataset
X, y = make_regression(
    n_samples=100, n_features=14, n_informative=6, bias=1.2, noise=49.8, tail_strength=0.6, random_state=637
)
# Convert to a DataFrame for statsmodels
data = pd.DataFrame(X)
data.columns = [f"X{i}" for i in range(X.shape[1])]
data["y"] = y
data.head()
Explanation: Random Test Data
For the purpose of generating tests for the visualizer, I'm using random test data. The compressive concrete strength dataset would also be good for integration testing.
End of explanation
# Compute an OLS model 
cols = data.columns
model = sm.ols(formula=f"{cols[-1]} ~ {' + '.join(cols[:-1])}", data=data)
model = model.fit()
print(model.summary())
# Compute the influence to get Cook's distance
inf = influence(model)
# cooks_distance is an attribute of incluence, here C, not sure about P (p-value maybe?)
C, P = inf.cooks_distance
def plot_cooks_distance(c):
    _, ax = plt.subplots(figsize=(9,6))
    ax.stem(c, markerfmt=",")
    ax.set_xlabel("instance")
    ax.set_ylabel("distance")
    ax.set_title("Cook's Distance Outlier Detection")
    return ax
plot_cooks_distance(C)
Explanation: Statsmodels Results
For comparison to the custom computation, this section computes the statsmodels OLS model and Cook's Distance values. In a later section we will compare this to scikit-learn linear regression and the Yellowbrick cooks function.
End of explanation
class CooksDistance(Visualizer):
    
    def fit(self, X, y):
        # Leverage is computed as the diagonal of the projection matrix of X 
        # TODO: whiten X before computing leverage
        self.leverage_ = (X * np.linalg.pinv(X).T).sum(1)
        
        # Compute the MSE
        rank = np.linalg.matrix_rank(X)
        df = X.shape[0] - rank
        
        resid = y - LinearRegression().fit(X, y).predict(X)
        mse = np.dot(resid, resid) / df 
        
        resid_studentized_internal = resid / np.sqrt(mse) / np.sqrt(1-self.leverage_)
        
        self.distance_ = resid_studentized_internal**2 / X.shape[1]
        self.distance_ *= self.leverage_ / (1 - self.leverage_)
        self.p_values_ = sp.stats.f.sf(self.distance_, X.shape[1], df)
        
        self.draw()
        return self
    
    
    def draw(self):
        self.ax.stem(self.distance_, markerfmt=",", label="influence")
        self.ax.axhline(4/len(self.distance_), c='r', ls='--', lw=1, label="$\frac{4}{n}$")
    
    def finalize(self):
        self.ax.legend()
        self.ax.set_xlabel("instance")
        self.ax.set_ylabel("influence")
        self.ax.set_title("Cook's Distance Outlier Detection")
    
    
viz = CooksDistance().fit(X, y)
viz.finalize()
Explanation: Scikit-Learn Cook's Distance
End of explanation
<END_TASK>