dockcert 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
dockcert/__init__.py ADDED
@@ -0,0 +1,46 @@
1
+ """
2
+ DockCert: Automated Statistical Validation, Enrichment Metrics, and Reproducibility
3
+ Assessment for Molecular Docking and Virtual Screening Studies.
4
+ """
5
+
6
+ __version__ = "1.0.0"
7
+ __author__ = "Andre Monreal-Hernández"
8
+ __license__ = "MIT"
9
+
10
+ from dockcert.core.enrichment import (
11
+ calculate_roc_auc,
12
+ calculate_pr_auc,
13
+ calculate_bedroc,
14
+ calculate_rie,
15
+ calculate_enrichment_factor,
16
+ calculate_log_auc,
17
+ calculate_optimal_mcc,
18
+ evaluate_all_enrichment_metrics
19
+ )
20
+ from dockcert.core.rmsd import (
21
+ calculate_heavy_atom_rmsd,
22
+ calculate_symmetry_corrected_rmsd,
23
+ evaluate_redocking_success
24
+ )
25
+ from dockcert.core.bias import evaluate_decoy_bias
26
+ from dockcert.core.bootstrap import bootstrap_enrichment_ci
27
+ from dockcert.core.scoring import assess_docking_quality, DockingValidationReport
28
+
29
+ __all__ = [
30
+ "__version__",
31
+ "calculate_roc_auc",
32
+ "calculate_pr_auc",
33
+ "calculate_bedroc",
34
+ "calculate_rie",
35
+ "calculate_enrichment_factor",
36
+ "calculate_log_auc",
37
+ "calculate_optimal_mcc",
38
+ "evaluate_all_enrichment_metrics",
39
+ "calculate_heavy_atom_rmsd",
40
+ "calculate_symmetry_corrected_rmsd",
41
+ "evaluate_redocking_success",
42
+ "evaluate_decoy_bias",
43
+ "bootstrap_enrichment_ci",
44
+ "assess_docking_quality",
45
+ "DockingValidationReport"
46
+ ]
dockcert/cli.py ADDED
@@ -0,0 +1,241 @@
1
+ """
2
+ Command Line Interface (CLI) for DockCert.
3
+ """
4
+
5
+ import sys
6
+ import os
7
+ import argparse
8
+ import numpy as np
9
+
10
+ from dockcert import __version__
11
+ from dockcert.parsers.generic_csv import load_docking_csv
12
+ from dockcert.parsers.structure_io import load_molecule_coordinates
13
+ from dockcert.core.rmsd import calculate_heavy_atom_rmsd, calculate_symmetry_corrected_rmsd
14
+ from dockcert.core.scoring import assess_docking_quality
15
+ from dockcert.reporters.plot_generator import generate_docking_figures
16
+ from dockcert.reporters.manuscript_prep import generate_docking_manuscript_assets
17
+ from dockcert.reporters.html_report import generate_docking_html_report
18
+
19
+
20
+ def print_banner():
21
+ banner = rf"""
22
+ _____ _ _____ _
23
+ | __ \ | | / ____| | |
24
+ | | | | ___ ___| | _| | ___ _ __| |_
25
+ | | | |/ _ \ / __| |/ / | / _ \ '__| __|
26
+ | |__| | (_) | (__| <| |___| __/ | | |_
27
+ |_____/ \___/ \___|_|\_\\_____\___|_| \__| v{__version__}
28
+
29
+ Molecular Docking Validation & Statistical Quality Toolkit
30
+ Monreal-Hernández et al., 2026
31
+ """
32
+ print(banner)
33
+
34
+
35
+ def run_demo(output_dir: str = "dockcert_demo_output"):
36
+ """
37
+ Generates a realistic DUD-E-like benchmark dataset (100 actives, 2000 property-matched decoys,
38
+ redocking RMSD = 1.43 A) and executes the full validation pipeline.
39
+ """
40
+ print(f"\n[DockCert] Running demonstration mode...")
41
+ os.makedirs(output_dir, exist_ok=True)
42
+
43
+ n_actives = 100
44
+ n_decoys = 2000
45
+
46
+ rng = np.random.default_rng(42)
47
+
48
+ # Active scores: N(-9.4 kcal/mol, 1.1)
49
+ active_scores = rng.normal(-9.4, 1.1, size=n_actives)
50
+ # Decoy scores: N(-6.8 kcal/mol, 1.2)
51
+ decoy_scores = rng.normal(-6.8, 1.2, size=n_decoys)
52
+
53
+ labels = np.concatenate([np.ones(n_actives, dtype=int), np.zeros(n_decoys, dtype=int)])
54
+ scores = np.concatenate([active_scores, decoy_scores])
55
+
56
+ # Redocking poses: Best RMSD = 1.43 A, ensemble of 9 poses
57
+ redocking_rmsds = [1.43, 1.78, 2.15, 2.40, 2.89, 3.10, 3.45, 4.12, 4.55]
58
+
59
+ # Physicochemical properties for bias audit (MW & LogP)
60
+ active_mw = rng.normal(380.0, 45.0, size=n_actives)
61
+ decoy_mw = rng.normal(375.0, 50.0, size=n_decoys)
62
+
63
+ active_logp = rng.normal(2.8, 0.7, size=n_actives)
64
+ decoy_logp = rng.normal(2.7, 0.8, size=n_decoys)
65
+
66
+ active_props = {"MolecularWeight": active_mw, "LogP": active_logp}
67
+ decoy_props = {"MolecularWeight": decoy_mw, "LogP": decoy_logp}
68
+
69
+ print(" -> Calculating ROC-AUC, PR-AUC, BEDROC (alpha=20.0), EF1%, EF5%, logAUC, and Bootstrap 95% CIs...")
70
+ report = assess_docking_quality(
71
+ labels=labels,
72
+ scores=scores,
73
+ rmsd_values=redocking_rmsds,
74
+ active_properties=active_props,
75
+ decoy_properties=decoy_props,
76
+ lower_is_better=True
77
+ )
78
+
79
+ print(" -> Generating publication-quality vector charts (ROC, PR, Score distributions, RMSD)...")
80
+ generate_docking_figures(labels, scores, report, output_dir, lower_is_better=True, rmsd_values=redocking_rmsds)
81
+
82
+ print(" -> Drafting manuscript Methods text snippet, summary LaTeX tables, and BibTeX citations...")
83
+ assets = generate_docking_manuscript_assets(report, output_dir)
84
+
85
+ with open(assets["methods_text"], "r", encoding="utf-8") as f:
86
+ methods_txt = f.read()
87
+ with open(assets["citation_bib"], "r", encoding="utf-8") as f:
88
+ bib_txt = f.read()
89
+
90
+ html_p = os.path.join(output_dir, "report.html")
91
+ print(f" -> Writing interactive dashboard to {html_p}...")
92
+ generate_docking_html_report(report, html_p, methods_text=methods_txt, citation_bib=bib_txt)
93
+
94
+ print("\n" + "="*70)
95
+ print(f" [RESULT] Overall Docking Certification: {report.overall_status}")
96
+ print(f" [SCORE] {report.validation_score}")
97
+ print("="*70)
98
+ if report.redocking_result:
99
+ rr = report.redocking_result
100
+ print(f" * Redocking RMSD : Best = {rr['min_rmsd']:.2f} A | Success Rate (<=2A) = {rr['success_rate_2a']:.1f}% | Status: {rr['status']}")
101
+ for k, item in report.enrichment_metrics.items():
102
+ ci_s = f"[{item.ci_lower_95:.2f}, {item.ci_upper_95:.2f}]" if item.ci_lower_95 is not None else ""
103
+ print(f" * {item.name:18s}: Value = {item.value:6.3f} {ci_s:14s} | Threshold = {item.threshold_pass:4.2f} | Status: {item.status}")
104
+ if report.decoy_bias_result:
105
+ print(f" * Decoy Bias Risk : Level = {report.decoy_bias_result['risk_level']} | Status: {report.decoy_bias_result['status']}")
106
+ print("="*70)
107
+ print(f"\nAll outputs successfully saved to: {os.path.abspath(output_dir)}/")
108
+ print(f"Open {os.path.abspath(html_p)} in your browser to inspect the full report.\n")
109
+
110
+
111
+ def run_assess(args):
112
+ """
113
+ Evaluates user-provided CSV and optional structure files.
114
+ """
115
+ output_dir = args.output
116
+ os.makedirs(output_dir, exist_ok=True)
117
+
118
+ csv_file = args.input
119
+ if not csv_file:
120
+ print("[Error] Please specify a results CSV file with --input.", file=sys.stderr)
121
+ sys.exit(1)
122
+
123
+ print(f"\n[DockCert] Loading docking screening dataset from {csv_file}...")
124
+ labels, scores, props_dict, meta = load_docking_csv(
125
+ csv_file,
126
+ score_column=args.score_col,
127
+ label_column=args.label_col
128
+ )
129
+ print(f" -> Identified {meta['n_total']} entries: {meta['n_actives']} actives, {meta['n_decoys']} decoys.")
130
+
131
+ # RMSD from structures if provided
132
+ rmsd_values = None
133
+ if args.ref_ligand and args.docked_pose:
134
+ print(" -> Calculating heavy-atom RMSD between reference and docked pose...")
135
+ c_ref, el_ref = load_molecule_coordinates(args.ref_ligand)
136
+ c_dock, el_dock = load_molecule_coordinates(args.docked_pose)
137
+ rmsd_val = calculate_symmetry_corrected_rmsd(c_ref, c_dock, elements=el_ref)
138
+ rmsd_values = [rmsd_val]
139
+ print(f" -> Calculated Redocking RMSD: {rmsd_val:.2f} A")
140
+
141
+ print(" -> Performing statistical validation and enrichment analysis...")
142
+ report = assess_docking_quality(
143
+ labels=labels,
144
+ scores=scores,
145
+ rmsd_values=rmsd_values,
146
+ lower_is_better=not args.higher_is_better
147
+ )
148
+
149
+ print(" -> Generating publication charts...")
150
+ generate_docking_figures(labels, scores, report, output_dir, lower_is_better=not args.higher_is_better, rmsd_values=rmsd_values)
151
+
152
+ print(" -> Generating manuscript text, LaTeX summary table, and BibTeX citations...")
153
+ assets = generate_docking_manuscript_assets(report, output_dir)
154
+
155
+ with open(assets["methods_text"], "r", encoding="utf-8") as f:
156
+ methods_txt = f.read()
157
+ with open(assets["citation_bib"], "r", encoding="utf-8") as f:
158
+ bib_txt = f.read()
159
+
160
+ html_p = os.path.join(output_dir, "report.html")
161
+ print(f" -> Writing HTML quality report to {html_p}...")
162
+ generate_docking_html_report(report, html_p, methods_text=methods_txt, citation_bib=bib_txt)
163
+
164
+ print("\n" + "="*70)
165
+ print(f" [RESULT] Overall Docking Certification: {report.overall_status}")
166
+ print(f" [SCORE] {report.validation_score}")
167
+ print("="*70)
168
+ for k, item in report.enrichment_metrics.items():
169
+ print(f" * {item.name:18s}: {item.value:6.3f} | Status: {item.status}")
170
+ if report.redocking_result:
171
+ print(f" * Redocking RMSD : {report.redocking_result['min_rmsd']:.2f} A | Status: {report.redocking_result['status']}")
172
+ print("="*70)
173
+ print(f"\nReport ready at: {os.path.abspath(html_p)}\n")
174
+
175
+
176
+ def print_citation():
177
+ bib = """@software{monreal2026dockcert,
178
+ author = {Monreal-Hern\\'andez, Andre},
179
+ title = {{DockCert: An Open-Source Toolkit for Statistical Validation, Enrichment Metrics, and Reproducibility Assessment of Molecular Docking Studies}},
180
+ year = {2026},
181
+ version = {1.0.0},
182
+ publisher = {Zenodo},
183
+ url = {https://github.com/sircalch/dockcert}
184
+ }"""
185
+ print("\nIf you use DockCert in your publications, please cite:\n")
186
+ print("APA Style:")
187
+ print("Monreal-Hernández, A. (2026). DockCert: An Open-Source Toolkit for Statistical Validation, Enrichment Metrics, and Reproducibility Assessment of Molecular Docking Studies (v1.0.0). Zenodo. https://github.com/sircalch/dockcert\n")
188
+ print("BibTeX:")
189
+ print(bib)
190
+ print()
191
+
192
+
193
+ def main():
194
+ parser = argparse.ArgumentParser(
195
+ prog="dockcert",
196
+ description="DockCert: Automated Statistical Validation, Enrichment Metrics, and Reproducibility Toolkit for Molecular Docking."
197
+ )
198
+ parser.add_argument("-v", "--version", action="version", version=f"dockcert {__version__}")
199
+
200
+ subparsers = parser.add_subparsers(dest="command", help="Available subcommands")
201
+
202
+ # Assess command
203
+ assess_parser = subparsers.add_parser("assess", help="Assess virtual screening enrichment and docking accuracy")
204
+ assess_parser.add_argument("-i", "--input", required=True, help="Virtual screening results file (.csv, .tsv, .txt)")
205
+ assess_parser.add_argument("--score-col", help="Column name containing docking scores/affinities")
206
+ assess_parser.add_argument("--label-col", help="Column name containing active/decoy labels")
207
+ assess_parser.add_argument("--ref-ligand", help="Reference crystallographic ligand structure (.sdf, .pdb, .pdbqt)")
208
+ assess_parser.add_argument("--docked-pose", help="Docked pose structure (.sdf, .pdb, .pdbqt)")
209
+ assess_parser.add_argument("--higher-is-better", action="store_true", help="Set if higher score values indicate better affinity")
210
+ assess_parser.add_argument("-o", "--output", default="dockcert_output", help="Directory for output report and assets (default: dockcert_output)")
211
+
212
+ # Demo command
213
+ demo_parser = subparsers.add_parser("demo", help="Run DockCert on a benchmark DUD-E-like simulation dataset")
214
+ demo_parser.add_argument("-o", "--output", default="dockcert_demo_output", help="Output directory (default: dockcert_demo_output)")
215
+
216
+ # Cite command
217
+ subparsers.add_parser("cite", help="Display BibTeX and APA citation details")
218
+
219
+ if len(sys.argv) == 1:
220
+ print_banner()
221
+ parser.print_help()
222
+ sys.exit(0)
223
+
224
+ args = parser.parse_args()
225
+
226
+ if args.command == "assess":
227
+ print_banner()
228
+ run_assess(args)
229
+ elif args.command == "demo":
230
+ print_banner()
231
+ run_demo(args.output)
232
+ elif args.command == "cite":
233
+ print_banner()
234
+ print_citation()
235
+ else:
236
+ parser.print_help()
237
+
238
+
239
+ if __name__ == "__main__":
240
+ main()
241
+
@@ -0,0 +1,40 @@
1
+ """
2
+ Core mathematical and validation algorithms for DockCert.
3
+ """
4
+
5
+ from dockcert.core.enrichment import (
6
+ calculate_roc_auc,
7
+ calculate_pr_auc,
8
+ calculate_bedroc,
9
+ calculate_rie,
10
+ calculate_enrichment_factor,
11
+ calculate_log_auc,
12
+ calculate_optimal_mcc,
13
+ evaluate_all_enrichment_metrics
14
+ )
15
+ from dockcert.core.rmsd import (
16
+ calculate_heavy_atom_rmsd,
17
+ calculate_symmetry_corrected_rmsd,
18
+ evaluate_redocking_success
19
+ )
20
+ from dockcert.core.bias import evaluate_decoy_bias
21
+ from dockcert.core.bootstrap import bootstrap_enrichment_ci
22
+ from dockcert.core.scoring import assess_docking_quality, DockingValidationReport
23
+
24
+ __all__ = [
25
+ "calculate_roc_auc",
26
+ "calculate_pr_auc",
27
+ "calculate_bedroc",
28
+ "calculate_rie",
29
+ "calculate_enrichment_factor",
30
+ "calculate_log_auc",
31
+ "calculate_optimal_mcc",
32
+ "evaluate_all_enrichment_metrics",
33
+ "calculate_heavy_atom_rmsd",
34
+ "calculate_symmetry_corrected_rmsd",
35
+ "evaluate_redocking_success",
36
+ "evaluate_decoy_bias",
37
+ "bootstrap_enrichment_ci",
38
+ "assess_docking_quality",
39
+ "DockingValidationReport"
40
+ ]
dockcert/core/bias.py ADDED
@@ -0,0 +1,85 @@
1
+ """
2
+ Decoy bias and physicochemical property distribution diagnostics.
3
+ """
4
+
5
+ from typing import Dict, Any, Optional
6
+ import numpy as np
7
+ from scipy import stats
8
+
9
+
10
+ def evaluate_decoy_bias(
11
+ active_properties: Dict[str, np.ndarray],
12
+ decoy_properties: Dict[str, np.ndarray]
13
+ ) -> Dict[str, Any]:
14
+ """
15
+ Evaluates potential artificial enrichment bias by comparing property distributions
16
+ (e.g., MW, LogP, HBD, HBA, Rotatable Bonds) between actives and decoys.
17
+
18
+ Parameters
19
+ ----------
20
+ active_properties : dict
21
+ Mapping of property name -> 1D array for active molecules.
22
+ decoy_properties : dict
23
+ Mapping of property name -> 1D array for decoy molecules.
24
+
25
+ Returns
26
+ -------
27
+ result : dict
28
+ Property-by-property Kolmogorov-Smirnov and Wasserstein statistics,
29
+ bias risk classification (LOW / MODERATE / HIGH), and recommendations.
30
+ """
31
+ common_props = set(active_properties.keys()).intersection(set(decoy_properties.keys()))
32
+ if not common_props:
33
+ return {
34
+ "status": "PASS",
35
+ "risk_level": "LOW",
36
+ "properties_evaluated": 0,
37
+ "property_metrics": {},
38
+ "recommendation": "No property metadata provided for decoy bias auditing. Ensure decoys are property-matched."
39
+ }
40
+
41
+ property_metrics = {}
42
+ ks_pvalues = []
43
+
44
+ for prop in common_props:
45
+ a_vals = np.asarray(active_properties[prop], dtype=float)
46
+ d_vals = np.asarray(decoy_properties[prop], dtype=float)
47
+
48
+ if len(a_vals) < 2 or len(d_vals) < 2:
49
+ continue
50
+
51
+ ks_res = stats.ks_2samp(a_vals, d_vals)
52
+ w_dist = stats.wasserstein_distance(a_vals, d_vals)
53
+
54
+ property_metrics[prop] = {
55
+ "active_mean": float(np.mean(a_vals)),
56
+ "decoy_mean": float(np.mean(d_vals)),
57
+ "ks_statistic": float(ks_res.statistic),
58
+ "ks_pvalue": float(ks_res.pvalue),
59
+ "wasserstein_distance": float(w_dist)
60
+ }
61
+ ks_pvalues.append(ks_res.pvalue)
62
+
63
+ # If KS p-value is extremely low (< 1e-4) across multiple physical properties, decoys are poorly matched
64
+ significant_biases = sum(1 for p in ks_pvalues if p < 0.001)
65
+
66
+ if significant_biases == 0:
67
+ risk_level = "LOW"
68
+ status = "PASS"
69
+ recommendation = "Decoys and actives are well property-matched. Low risk of artificial enrichment bias."
70
+ elif significant_biases <= 2:
71
+ risk_level = "MODERATE"
72
+ status = "WARNING"
73
+ recommendation = "Moderate distributional discrepancy observed in physicochemical properties between actives and decoys."
74
+ else:
75
+ risk_level = "HIGH"
76
+ status = "WARNING"
77
+ recommendation = "High risk of decoy bias: actives and decoys differ significantly in physical properties (e.g. MW, LogP). Enrichment may be artificially inflated."
78
+
79
+ return {
80
+ "status": status,
81
+ "risk_level": risk_level,
82
+ "properties_evaluated": len(property_metrics),
83
+ "property_metrics": property_metrics,
84
+ "recommendation": recommendation
85
+ }
@@ -0,0 +1,111 @@
1
+ """
2
+ Stratified bootstrap confidence interval estimation for virtual screening metrics.
3
+ """
4
+
5
+ from typing import Dict, Any, Tuple, Optional
6
+ import numpy as np
7
+ from dockcert.core.enrichment import (
8
+ calculate_roc_auc,
9
+ calculate_pr_auc,
10
+ calculate_bedroc,
11
+ calculate_enrichment_factor
12
+ )
13
+
14
+
15
+ def bootstrap_enrichment_ci(
16
+ labels: np.ndarray,
17
+ scores: np.ndarray,
18
+ n_resamples: int = 1000,
19
+ confidence_level: float = 0.95,
20
+ lower_is_better: bool = True,
21
+ random_state: Optional[int] = 42
22
+ ) -> Dict[str, Tuple[float, float, float]]:
23
+ """
24
+ Computes stratified non-parametric bootstrap 95% Confidence Intervals for all key metrics.
25
+
26
+ Parameters
27
+ ----------
28
+ labels : np.ndarray
29
+ Binary label array (1 = Active, 0 = Decoy).
30
+ scores : np.ndarray
31
+ Docking scores.
32
+ n_resamples : int, default 1000
33
+ Number of bootstrap iterations.
34
+ confidence_level : float, default 0.95
35
+ Confidence level.
36
+ lower_is_better : bool
37
+ Sorting direction.
38
+ random_state : int, optional
39
+ Seed for reproducibility.
40
+
41
+ Returns
42
+ -------
43
+ ci_dict : dict
44
+ Mapping metric_name -> (point_estimate, ci_lower, ci_upper).
45
+ """
46
+ y_true = np.asarray(labels, dtype=int)
47
+ y_scores = np.asarray(scores, dtype=float)
48
+
49
+ active_idx = np.where(y_true == 1)[0]
50
+ decoy_idx = np.where(y_true == 0)[0]
51
+
52
+ n_act = len(active_idx)
53
+ n_dec = len(decoy_idx)
54
+
55
+ if n_act == 0 or n_dec == 0:
56
+ return {}
57
+
58
+ rng = np.random.default_rng(random_state)
59
+
60
+ # Point estimates
61
+ pe_roc = calculate_roc_auc(y_true, y_scores, lower_is_better)
62
+ pe_pr = calculate_pr_auc(y_true, y_scores, lower_is_better)
63
+ pe_bedroc20 = calculate_bedroc(y_true, y_scores, alpha=20.0, lower_is_better=lower_is_better)
64
+ pe_bedroc80 = calculate_bedroc(y_true, y_scores, alpha=80.5, lower_is_better=lower_is_better)
65
+ pe_ef1, _ = calculate_enrichment_factor(y_true, y_scores, fraction=0.01, lower_is_better=lower_is_better)
66
+ pe_ef5, _ = calculate_enrichment_factor(y_true, y_scores, fraction=0.05, lower_is_better=lower_is_better)
67
+ pe_ef10, _ = calculate_enrichment_factor(y_true, y_scores, fraction=0.10, lower_is_better=lower_is_better)
68
+
69
+ boot_roc = np.empty(n_resamples, dtype=float)
70
+ boot_pr = np.empty(n_resamples, dtype=float)
71
+ boot_bedroc20 = np.empty(n_resamples, dtype=float)
72
+ boot_bedroc80 = np.empty(n_resamples, dtype=float)
73
+ boot_ef1 = np.empty(n_resamples, dtype=float)
74
+ boot_ef5 = np.empty(n_resamples, dtype=float)
75
+ boot_ef10 = np.empty(n_resamples, dtype=float)
76
+
77
+ for b in range(n_resamples):
78
+ sample_act = rng.choice(active_idx, size=n_act, replace=True)
79
+ sample_dec = rng.choice(decoy_idx, size=n_dec, replace=True)
80
+
81
+ sample_idx = np.concatenate([sample_act, sample_dec])
82
+ b_labels = y_true[sample_idx]
83
+ b_scores = y_scores[sample_idx]
84
+
85
+ boot_roc[b] = calculate_roc_auc(b_labels, b_scores, lower_is_better)
86
+ boot_pr[b] = calculate_pr_auc(b_labels, b_scores, lower_is_better)
87
+ boot_bedroc20[b] = calculate_bedroc(b_labels, b_scores, alpha=20.0, lower_is_better=lower_is_better)
88
+ boot_bedroc80[b] = calculate_bedroc(b_labels, b_scores, alpha=80.5, lower_is_better=lower_is_better)
89
+ ef1, _ = calculate_enrichment_factor(b_labels, b_scores, fraction=0.01, lower_is_better=lower_is_better)
90
+ ef5, _ = calculate_enrichment_factor(b_labels, b_scores, fraction=0.05, lower_is_better=lower_is_better)
91
+ ef10, _ = calculate_enrichment_factor(b_labels, b_scores, fraction=0.10, lower_is_better=lower_is_better)
92
+ boot_ef1[b] = ef1
93
+ boot_ef5[b] = ef5
94
+ boot_ef10[b] = ef10
95
+
96
+ alpha_ci = (1.0 - confidence_level) / 2.0
97
+
98
+ def get_ci(point_est, boot_arr):
99
+ low = float(np.percentile(boot_arr, 100.0 * alpha_ci))
100
+ high = float(np.percentile(boot_arr, 100.0 * (1.0 - alpha_ci)))
101
+ return float(point_est), low, high
102
+
103
+ return {
104
+ "roc_auc": get_ci(pe_roc, boot_roc),
105
+ "pr_auc": get_ci(pe_pr, boot_pr),
106
+ "bedroc_20": get_ci(pe_bedroc20, boot_bedroc20),
107
+ "bedroc_80": get_ci(pe_bedroc80, boot_bedroc80),
108
+ "ef_1pct": get_ci(pe_ef1, boot_ef1),
109
+ "ef_5pct": get_ci(pe_ef5, boot_ef5),
110
+ "ef_10pct": get_ci(pe_ef10, boot_ef10)
111
+ }