Martin Horvat преди 6 месеца
родител
ревизия
d0f5bb1ff1
променени са 4 файла, в които са добавени 66 реда и са изтрити 39 реда
  1. 1 9
      python/logistic/logit_reg_fit_gen.ipynb
  2. 51 21
      python/logistic/logit_utils_gen.py
  3. 7 4
      python/logistic/mono_cubic1.py
  4. 7 5
      python/logistic/mono_cubic2.py

+ 1 - 9
python/logistic/logit_reg_fit_gen.ipynb

@@ -20,7 +20,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 1,
+   "execution_count": null,
    "id": "3b351af7",
    "metadata": {},
    "outputs": [],
@@ -1031,14 +1031,6 @@
     "plt.savefig(os.path.join(results_path, \"logit_fit.pdf\"))\n",
     "plt.show()\n"
    ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "99df5a6b",
-   "metadata": {},
-   "outputs": [],
-   "source": []
   }
  ],
  "metadata": {

+ 51 - 21
python/logistic/logit_utils_gen.py

@@ -1,25 +1,54 @@
 """
-    Providing class for logistic regression utilities with polynomial 
+    The file provides a class for logistic regression utilities with polynomial 
     logit (log odds) function:
 
-        p(x|pars) = 1/(1 + exp(-F(x|b(pars))))
+        p(x|pars) = 1/(1 + exp(-F(x|beta(pars))))
     
     with log odds F of polynomial form:
 
-        F(x|b) = sum_{i=0}^degree b_i x^i
+        F(x|beta) = sum_{j=0}^degree beta_j x^j
                 
     with decision function (aka logit) F and parameters 
         
-        b(pars) = [b(pars)_i]_{i=0}^degree
+        beta(pars) = [beta(pars)_j]_{j=0}^degree
     
-    where pars are regression parameters. Coefficients
-    b(pars) can be constrained to be monotonic function of x by using 
-    monotonic cubic transformation:
+    where pars are regression parameters, len(pars) = degree + 1.
+    
+    Coefficients beta(pars) can be constrained to be monotonic 
+    function of x by using monotonic cubic transformation:
         
-        b(pars) = mc.forward_map(pars)
+        beta(pars) = mc.forward_map(pars)
     
     where mc is module mono_cubic2.
 
+    NOTES: The model defines the conditional probability 
+
+        Prob(Y = y|x, pars) = 1/(1 + exp(-s(y) F(x| beta(pars))))
+    
+    where
+    
+        s(y) = 2*y - 1
+    
+    with x in R and y in {0,1}. For degree = 1 this is standard logistic regression
+    
+        beta(pars) = (pars[0], pars[1]). 
+    
+    For degree = 3 and mono = True the coefficients beta(pars) are constrained to be 
+    monotonic by using monotonic cubic transformation.
+
+    We have data
+
+        {(x_i, y_i) : x_i in R, y_i in {0,1}, i = 0, ..., n-1 }
+    
+    and the model is fit to data by minimizing negative log-likelihood function:
+
+        nlff = -sum_i log(Prob(Y = y_i| x_i, pars))  : neg. log likelihood
+
+    with respect to parameters pars. We can have regularization term in cost function
+    and this case we minimize cost function:
+
+        cost(pars) = nllf(pars) + lambda ||pars||^2
+
     Author: Martin Horvat, January 2026
 """
 
@@ -80,11 +109,11 @@ def safe_expit(x, max_exp = 700): return 1/(1 + safe_exp(-x, max_exp))
     
     to model function 
 
-        f(x|pars) = 1/(1 + exp(-F(x|beta)))         beta = beta(pars)
+        f(x|pars) = 1/(1 + exp(-F(x|beta(pars))))
 
     with log odds of polynomial form:
 
-        log(f(x|pars)/(1 - f(x|pars))) = F(x|beta)  beta = beta(pars)
+        log(f(x|pars)/(1 - f(x|pars))) = F(x| beta(pars)) 
 
     where F is decision function (aka logit)
         
@@ -92,7 +121,7 @@ def safe_expit(x, max_exp = 700): return 1/(1 + safe_exp(-x, max_exp))
                 
     and coefficients
         
-        beta = [beta_i(pars)]_{i=0}^degrees
+        beta(pars) = [beta_i(pars)]_{i=0}^degrees
     
     Conditional probability
 
@@ -100,17 +129,17 @@ def safe_expit(x, max_exp = 700): return 1/(1 + safe_exp(-x, max_exp))
 
     with
 
-            s(y) = 2*y -1
+        s(y) = 2*y -1
 """
 class LogisticPolyRegression:
 
     """
-        Constructor
+        Class constructor. 
 
         Input:
             degree: int, degree of polynomial
             mono: boolean, default False
-            lambda: None or tuple float, L1 and L2 regularization
+            lambda: None or tuple float, L2 regularization
 
     """
     def __init__(self, degree = 1, mono = False, lam = None):
@@ -286,8 +315,7 @@ class LogisticPolyRegression:
             return (val[0] + pen[0], val[1] + pen[1]) if jac else val + pen
         
         return val
-           
-    
+
     """
         Estimate parameters.
 
@@ -376,7 +404,9 @@ class LogisticPolyRegression:
             thresh: float, default 0.5, threshold value for classification
 
         Return:
-            {"n": n, "k":k, "dof":n-k, 
+            {"n": n, 
+            "k": r, 
+            "dof": n - r, 
             "LLF": log_likelihood, 
             "AIC": AIC, 
             "BIC": BIC, 
@@ -421,7 +451,8 @@ class LogisticPolyRegression:
                 "n": n, "k": k, "dof": dof}
 
     """
-        Calculation of asymptotic variance-covariance matrix of parameters pars
+        Calculation of asymptotic variance-covariance matrix of regression 
+        parameters pars
 
            cov_{asymp}[pars] = H^{-1}
 
@@ -441,8 +472,8 @@ class LogisticPolyRegression:
             array of rxr floats; r = degree + 1
         
         Ref:
-            https://stats.stackexchange.com/questions/89484/how-to-compute-the-standard-errors-of-a-logistic-regressions-coefficients
-            https://goodboychan.github.io/machine_learning/2020/09/14/02-Regularized-likelihood-methods.html
+          * https://stats.stackexchange.com/questions/89484/how-to-compute-the-standard-errors-of-a-logistic-regressions-coefficients
+          * https://goodboychan.github.io/machine_learning/2020/09/14/02-Regularized-likelihood-methods.html
     """
     def cov(self, x, y, pars):
         
@@ -478,7 +509,6 @@ class LogisticPolyRegression:
         # covariance matrix C_params = H^-1
         return np.linalg.inv(H)
 
-
     """
         Calculating quantiles of the model parameters at given probabilities p 
         for normal distribution of parameters:

+ 7 - 4
python/logistic/mono_cubic1.py

@@ -1,7 +1,10 @@
-# Function supporting monotonic cubic polynomials: first parametrization
-# We define the polynomial:
-#       poly(x) = sum_i beta_i * x^i
-# where the coefficients beta_i are parameterized by the vector 'pars'.
+"""
+    Function supporting monotonic cubic polynomials: 
+        first parametrization
+    We define the polynomial:
+          poly(x) = sum_i beta_i * x^i
+    where the coefficients beta_i are parameterized by the vector 'pars'.
+"""
 
 import numpy as np
 

+ 7 - 5
python/logistic/mono_cubic2.py

@@ -1,8 +1,10 @@
-# Function supporting monotonic cubic polynomials: first parametrization
-# We define the polynomial:
-#       poly(x) = sum_i beta_i * x^i
-# where the coefficients beta_i are parameterized by the vector 'pars'.
-
+""" 
+    Function supporting monotonic cubic polynomials: 
+        second parametrization
+    We define the polynomial:
+          poly(x) = sum_i beta_i * x^i
+    where the coefficients beta_i are parameterized by the vector 'pars'.
+"""
 import numpy as np
 
 # Forward map: Parameters to polynomial coefficients