<jupyter_start><jupyter_text>The __$Binary-logistic$__ __$regression$__ class is defined below. First, it (optionally) standardizes and adds an intercept term.Then it estimates with gradient descent, using the gradient of the negative log-likelihood derived in the conceptsection<jupyter_code>import numpy as np
from sklearn import datasets
import matplotlib.pyplot as plt
from warnings import filterwarnings
import seaborn as sns
filterwarnings('ignore')
plt.style.use('seaborn-whitegrid')
# ---- import data ----
cancer = datasets.load_breast_cancer()
X = cancer['data']
y = cancer['target']<jupyter_output><empty_output><jupyter_text>Let’s first define some helper functions: the logistic function and a standardization function, equivalent __$scikitlearn’s$__ __$StandardScaler$__<jupyter_code>def logistic(z) :
    return (1 + np.exp(-z))**(-1)

def standard_scaler(X) :
    mean = X.mean(0)
    std = X.std(0)
    return (X - mean)/std
class BinaryLogisticRegression :
    def fit(self, X, y, n_iter, lr, standardize = True, has_intercept = False) -> None :
        if standardize : 
            X = standard_scaler(X)
        if not has_intercept :
            ones = np.ones(X.shape[0]).reshape(-1, 1)
            X = np.concatenate((ones, X), axis = 1)
        self.X = X
        self.N, self.D = X.shape
        self.y = y
        self.n_iter = n_iter
        self.lr = lr
        
        # ----- Calculate beta -----
        beta = np.random.randn(self.D)
        for i in range(n_iter) :
            # ---- vector of probabilities ----
            p = logistic(np.dot(self.X, beta))
            # -----  gradient -----
            gradient = -np.dot(self.X.T, (self.y - p))
            beta -= self.lr * gradient
            
        # ---- return values ------
        self.beta = beta 
        self.p = logistic(np.dot(self.X, self.beta))
        self.yhat = self.p.round()
binary_model = BinaryLogisticRegression()
binary_model.fit(X, y, n_iter = 10**4, lr = .0001)
print(f"In-sample accuracy : {str(np.mean(binary_model.yhat == binary_model.y))} ")
fig, ax = plt.subplots()
sns.distplot(binary_model.p[binary_model.yhat == 0], kde = False, bins = 8, 
            label = 'Class 0', color = 'cornflowerblue')
sns.distplot(binary_model.p[binary_model.yhat == 1], kde = False, bins = 8, 
             label = 'Class 1', color = 'darkblue')
ax.legend(loc = 9, bbox_to_anchor = (0, 0, 1.59, .9))
ax.set_title(r'Estimated $p(Y_n = 1)$', size = 14)
ax.set_title(r'Estimated $p(Y_n = 1)$ by True Class', size = 16)
sns.despine()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.14296844565640826, 'fraction_numerical': 0.013245033112582781, 'mean_word_length': 2.7434402332361514, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 10, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '2', 'dir': 'jupyter-structured-clean-dedup', 'id': '255697', 'license': 'MIT', 'n_tokens_mistral': 914, 'n_tokens_neox': 859, 'n_words': 217, 'path': 'Machine-Learning-Algorithms/Supervised/Classification/binarylogistic-regression.ipynb', 'repo_name': 'Now-Tiger/Python-Statistics', 'size': '2567'}