Skip to content

Commit

Permalink
✨ adds conf_limits_nct_minimize
Browse files Browse the repository at this point in the history
  • Loading branch information
MaaniBeigy committed Aug 16, 2024
1 parent 53f061b commit 8e81e2c
Show file tree
Hide file tree
Showing 9 changed files with 420 additions and 57 deletions.
8 changes: 4 additions & 4 deletions .logs/bandit.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"errors": [],
"generated_at": "2024-08-16T12:26:47Z",
"generated_at": "2024-08-16T13:20:17Z",
"metrics": {
"_totals": {
"CONFIDENCE.HIGH": 0,
Expand All @@ -11,7 +11,7 @@
"SEVERITY.LOW": 0,
"SEVERITY.MEDIUM": 0,
"SEVERITY.UNDEFINED": 0,
"loc": 1779,
"loc": 1878,
"nosec": 0,
"skipped_tests": 0
},
Expand Down Expand Up @@ -115,7 +115,7 @@
"SEVERITY.LOW": 0,
"SEVERITY.MEDIUM": 0,
"SEVERITY.UNDEFINED": 0,
"loc": 133,
"loc": 197,
"nosec": 0,
"skipped_tests": 0
},
Expand Down Expand Up @@ -245,7 +245,7 @@
"SEVERITY.LOW": 0,
"SEVERITY.MEDIUM": 0,
"SEVERITY.UNDEFINED": 0,
"loc": 36,
"loc": 71,
"nosec": 0,
"skipped_tests": 0
}
Expand Down
4 changes: 2 additions & 2 deletions .logs/bandit.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
Run started:2024-08-16 12:26:49.489295
Run started:2024-08-16 13:20:19.833480

Test results:
No issues identified.

Code scanned:
Total lines of code: 1779
Total lines of code: 1878
Total lines skipped (#nosec): 0
Total potential issues skipped due to specifically being disabled (e.g., #nosec BXXX): 0

Expand Down
Binary file modified .logs/complexity.txt
Binary file not shown.
Binary file modified .logs/docstring.txt
Binary file not shown.
2 changes: 1 addition & 1 deletion .logs/maintainability.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"maintainability": "90.0%"
"maintainability": "89.8%"
}
Binary file modified .logs/maintainability.txt
Binary file not shown.
336 changes: 288 additions & 48 deletions assets/docs/pycvcqv/examples.ipynb

Large diffs are not rendered by default.

78 changes: 77 additions & 1 deletion pycvcqv/noncentralt.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import Any, Dict, Optional, Union

import numpy as np
from scipy.optimize import minimize_scalar
from scipy.optimize import minimize, minimize_scalar
from scipy.stats import nct

from pycvcqv.checkers import is_dof_positive_natural_number, is_ncp_huge
Expand Down Expand Up @@ -166,3 +166,79 @@ def conf_limits_nct_minimize_scalar(
"prob_greater_upper": out_of_range_probabilities["prob_greater_upper"],
}
return result


# ------------------ Decorators to check validity of input arguments ------------------
@is_dof_positive_natural_number
@is_ncp_huge
@validate_ncp_confidence_level_arguments
def conf_limits_nct_minimize(
ncp: float,
dof: int,
conf_level: Optional[float] = None,
alpha_lower: Optional[float] = None,
alpha_upper: Optional[float] = None,
tol: Optional[float] = 1e-9,
) -> Dict[str, Union[float, int]]:
"""
Calculate confidence limits for the noncentrality parameter (NCP) of the
noncentral t-distribution using scipy.optimize.minimize.
This function uses the scipy.optimize.minimize method to estimate
the lower and upper confidence limits for the noncentrality
parameter (NCP) given the degrees of freedom, confidence level, and other parameters.
Args:
ncp (float): The observed noncentrality parameter. Can be passed as 't_value'.
dof (int): Degrees of freedom. Must be positive.
conf_level (float, optional): The confidence level for the interval.
alpha_lower (float, optional): The significance level for the lower tail.
alpha_upper (float, optional): The significance level for the upper tail.
tol (float, optional): Tolerance for the optimization algorithms. Default is 1e-9.
Returns:
dict: A dictionary with the following keys:
- lower_limit (float): Lower confidence limit for the NCP.
- prob_less_lower (float): Probability that the NCP is less than the lower limit.
- upper_limit (float): Upper confidence limit for the NCP.
- prob_greater_upper (float): Probability that the NCP is greater than the upper limit.
Example:
.. code:: python
>>> conf_limits_nct_minimize(ncp=2.83, dof=126, conf_level=0.95)
... {
... 'lower_limit': 0.833750253390236,
... 'prob_less_lower': 0.024999999571209908,
... 'upper_limit': 4.815359132565956,
... 'prob_greater_upper': 0.025000000428616057
... }
"""
# ------ Calculates alpha tails of noncentral t parameter confidence interval -----
alpha_tails = _calculate_alpha_tails(conf_level, alpha_lower, alpha_upper)
valid_alpha_lower = alpha_tails["alpha_lower"]
valid_alpha_upper = alpha_tails["alpha_upper"]
# ------------------------- calculate lower_limit for NCP -------------------------
ncp_lower_limit = minimize(
_ci_nct_lower, ncp, tol=tol, args=(valid_alpha_upper, dof, ncp)
).x[0]
# ------------------------- calculate upper_limit for NCP -------------------------
ncp_upper_limit = minimize(
_ci_nct_upper, ncp, tol=tol, args=(valid_alpha_upper, dof, ncp)
).x[0]
# -------------- Calculates the probabilities for out of range values -------------
out_of_range_probabilities = _calculate_out_of_range_probabilities(
ncp,
dof,
ncp_lower_limit,
valid_alpha_lower,
ncp_upper_limit,
valid_alpha_upper,
)
# ----------------------------- preparing the result -----------------------------
result = {
"lower_limit": ncp_lower_limit if valid_alpha_lower != 0 else -np.inf,
"prob_less_lower": out_of_range_probabilities["prob_less_lower"],
"upper_limit": ncp_upper_limit if valid_alpha_upper != 0 else np.inf,
"prob_greater_upper": out_of_range_probabilities["prob_greater_upper"],
}
return result
49 changes: 48 additions & 1 deletion tests/test_noncentralt.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@

import pytest

from pycvcqv.noncentralt import conf_limits_nct_minimize_scalar
from pycvcqv.noncentralt import (
conf_limits_nct_minimize,
conf_limits_nct_minimize_scalar,
)


def test_conf_limits_nct_minimize_scalar_all_none():
Expand Down Expand Up @@ -51,3 +54,47 @@ def test_conf_limits_nct_minimize_scalar_alpha_lower_0_alpha_upper_0_05():
assert result["prob_less_lower"] == 0
assert result["upper_limit"] == pytest.approx(4.495224841782837, rel=1e-9)
assert result["prob_greater_upper"] == pytest.approx(0.04999999999219518, rel=1e-9)


def test_conf_limits_nct_minimize_all_none():
"""Tests the conf_limits_nct_minimize when conf_level and alphas are None."""
result = conf_limits_nct_minimize(ncp=2.83, dof=126)

assert result["lower_limit"] == pytest.approx(0.833750253390236, rel=1e-9)
assert result["prob_less_lower"] == pytest.approx(0.024999999571209908, rel=1e-9)
assert result["upper_limit"] == pytest.approx(4.815359132565956, rel=1e-9)
assert result["prob_greater_upper"] == pytest.approx(0.025000000428616057, rel=1e-9)


def test_conf_limits_nct_minimize_conf_level_95():
"""Tests the conf_limits_nct_minimize when conf_level is set to 0.95."""
result = conf_limits_nct_minimize(ncp=2.83, dof=126, conf_level=0.95)

assert result["lower_limit"] == pytest.approx(0.833750253390236, rel=1e-9)
assert result["prob_less_lower"] == pytest.approx(0.024999999571209908, rel=1e-9)
assert result["upper_limit"] == pytest.approx(4.815359132565956, rel=1e-9)
assert result["prob_greater_upper"] == pytest.approx(0.025000000428616057, rel=1e-9)


def test_conf_limits_nct_minimize_alpha_lower_0_01_alpha_upper_0_04():
"""Tests the conf_limits_nct_minimize when alpha levels are non-zero."""
result = conf_limits_nct_minimize(
ncp=2.83, dof=126, conf_level=None, alpha_lower=0.01, alpha_upper=0.04
)

assert result["lower_limit"] == pytest.approx(1.04627633833502, rel=1e-9)
assert result["prob_less_lower"] == pytest.approx(0.03999999981306357, rel=1e-9)
assert result["upper_limit"] == pytest.approx(4.602743332359321, rel=1e-9)
assert result["prob_greater_upper"] == pytest.approx(0.040000000631974, rel=1e-9)


def test_conf_limits_nct_minimize_alpha_lower_0_alpha_upper_0_05():
"""Tests the conf_limits_nct_minimize when alpha_lower is zero."""
result = conf_limits_nct_minimize(
ncp=2.83, dof=126, conf_level=None, alpha_lower=0, alpha_upper=0.05
)

assert isinf(result["lower_limit"]) and result["lower_limit"] < 0
assert result["prob_less_lower"] == 0
assert result["upper_limit"] == pytest.approx(4.495224834255373, rel=1e-9)
assert result["prob_greater_upper"] == pytest.approx(0.05000000075637537, rel=1e-9)

0 comments on commit 8e81e2c

Please sign in to comment.