Skip to content

Commit 7636488

Browse files
committed
Add more numba functions, add pre-compilation
1 parent cc71e1c commit 7636488

121 files changed

Lines changed: 256 additions & 162 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

dabest/__init__.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,11 @@
44
from ._effsize_objects import TwoGroupsEffectSize, PermutationTest
55
from ._dabest_object import Dabest
66

7-
__version__ = "2024.03.30"
7+
8+
import os
9+
if os.environ.get('SKIP_NUMBA_COMPILE') != '1':
10+
from ._stats_tools.precompile import precompile_all, _NUMBA_COMPILED
11+
if not _NUMBA_COMPILED:
12+
precompile_all()
13+
14+
__version__ = "2024.03.30"

dabest/_api.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""Loading data and relevant groups"""
2+
13
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/API/load.ipynb.
24

35
# %% auto 0

dabest/_dabest_object.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""Main class for estimating statistics and generating plots."""
2+
13
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/API/dabest_object.ipynb.
24

35
# %% auto 0

dabest/_delta_objects.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""Auxiliary delta classes for estimating statistics and generating plots."""
2+
13
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/API/delta_objects.ipynb.
24

35
# %% auto 0

dabest/_effsize_objects.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""The auxiliary classes involved in the computations of bootstrapped effect sizes."""
2+
13
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/API/effsize_objects.ipynb.
24

35
# %% auto 0

dabest/_modidx.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,14 @@
4747
'dabest/_stats_tools/confint_2group_diff.py'),
4848
'dabest._stats_tools.confint_2group_diff.delta2_bootstrap_loop': ( 'API/confint_2group_diff.html#delta2_bootstrap_loop',
4949
'dabest/_stats_tools/confint_2group_diff.py')},
50-
'dabest._stats_tools.effsize': { 'dabest._stats_tools.effsize._compute_hedges_correction_factor': ( 'API/effsize.html#_compute_hedges_correction_factor',
50+
'dabest._stats_tools.effsize': { 'dabest._stats_tools.effsize._cliffs_delta_core': ( 'API/effsize.html#_cliffs_delta_core',
51+
'dabest/_stats_tools/effsize.py'),
52+
'dabest._stats_tools.effsize._compute_hedges_correction_factor': ( 'API/effsize.html#_compute_hedges_correction_factor',
5153
'dabest/_stats_tools/effsize.py'),
5254
'dabest._stats_tools.effsize._compute_standardizers': ( 'API/effsize.html#_compute_standardizers',
5355
'dabest/_stats_tools/effsize.py'),
56+
'dabest._stats_tools.effsize._mann_whitney_u': ( 'API/effsize.html#_mann_whitney_u',
57+
'dabest/_stats_tools/effsize.py'),
5458
'dabest._stats_tools.effsize.cliffs_delta': ( 'API/effsize.html#cliffs_delta',
5559
'dabest/_stats_tools/effsize.py'),
5660
'dabest._stats_tools.effsize.cohens_d': ( 'API/effsize.html#cohens_d',
@@ -65,6 +69,8 @@
6569
'dabest/_stats_tools/effsize.py'),
6670
'dabest._stats_tools.effsize.weighted_delta': ( 'API/effsize.html#weighted_delta',
6771
'dabest/_stats_tools/effsize.py')},
72+
'dabest._stats_tools.precompile': { 'dabest._stats_tools.precompile.precompile_all': ( 'API/precompile.html#precompile_all',
73+
'dabest/_stats_tools/precompile.py')},
6874
'dabest.forest_plot': { 'dabest.forest_plot.extract_plot_data': ( 'API/forest_plot.html#extract_plot_data',
6975
'dabest/forest_plot.py'),
7076
'dabest.forest_plot.forest_plot': ('API/forest_plot.html#forest_plot', 'dabest/forest_plot.py'),

dabest/_stats_tools/confint_1group.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""A range of functions to compute bootstraps for a single sample."""
2+
13
# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbs/API/confint_1group.ipynb.
24

35
# %% auto 0

dabest/_stats_tools/confint_2group_diff.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""A range of functions to compute bootstraps for the mean difference"""
2+
13
# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbs/API/confint_2group_diff.ipynb.
24

35
# %% auto 0
@@ -268,7 +270,7 @@ def _compute_alpha_from_ci(ci):
268270
return (100.0 - ci) / 100.0
269271

270272

271-
# @njit(cache=True)
273+
@njit(cache=True)
272274
def _compute_quantile(z, bias, acceleration):
273275
numer = bias + z
274276
denom = 1 - (acceleration * numer)
@@ -319,5 +321,4 @@ def calculate_weighted_delta(group_var, differences):
319321
num = 0.0
320322
for i in range(len(weight)):
321323
num += weight[i] * differences[i]
322-
323324
return num / denom

dabest/_stats_tools/effsize.py

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""A range of functions to compute various effect sizes."""
2+
13
# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbs/API/effsize.ipynb.
24

35
# %% ../../nbs/API/effsize.ipynb 4
@@ -270,26 +272,39 @@ def hedges_g(control:list|tuple|np.ndarray,
270272
return correction_factor * d
271273

272274
# %% ../../nbs/API/effsize.ipynb 10
275+
@njit(cache=True)
276+
def _mann_whitney_u(x, y):
277+
"""Numba-optimized Mann-Whitney U calculation"""
278+
n1, n2 = len(x), len(y)
279+
combined = np.concatenate((x, y))
280+
281+
# Use numpy broadcasting for comparison
282+
less_than = (combined.reshape(-1, 1) > combined).sum(axis=1)
283+
equal_to = (combined.reshape(-1, 1) == combined).sum(axis=1)
284+
285+
# Calculate ranks directly
286+
ranks = less_than + (equal_to + 1) / 2
287+
288+
R1 = np.sum(ranks[:n1])
289+
U1 = R1 - (n1 * (n1 + 1)) / 2
290+
return U1
291+
292+
@njit(cache=True)
293+
def _cliffs_delta_core(control, test):
294+
"""Numba-optimized Cliff's delta calculation"""
295+
U = _mann_whitney_u(test, control)
296+
return ((2 * U) / (len(control) * len(test))) - 1
297+
273298
def cliffs_delta(control:list|tuple|np.ndarray,
274299
test:list|tuple|np.ndarray
275300
)->float:
276301
"""
277302
Computes Cliff's delta for 2 samples.
278303
See [here](https://en.wikipedia.org/wiki/Effect_size#Effect_size_for_ordinal_data)
279304
"""
280-
281-
282305
c = control[~np.isnan(control)]
283306
t = test[~np.isnan(test)]
284-
285-
control_n = len(c)
286-
test_n = len(t)
287-
288-
# Note the order of the control and test arrays.
289-
U, _ = mannwhitneyu(t, c, alternative='two-sided') # Not supported by numba.
290-
cliffs_delta = ((2 * U) / (control_n * test_n)) - 1
291-
292-
return cliffs_delta
307+
return _cliffs_delta_core(c, t)
293308

294309

295310
# %% ../../nbs/API/effsize.ipynb 11

dabest/_stats_tools/precompile.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"""A tool to pre-compile Numba functions for speeding up DABEST bootstrapping"""
2+
3+
# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbs/API/precompile.ipynb.
4+
5+
# %% auto 0
6+
__all__ = ['precompile_all']
7+
8+
# %% ../../nbs/API/precompile.ipynb 4
9+
import numpy as np
10+
from tqdm import tqdm
11+
from . import effsize
12+
from . import confint_2group_diff
13+
14+
# %% ../../nbs/API/precompile.ipynb 5
15+
_NUMBA_COMPILED = False
16+
17+
def precompile_all():
18+
"""Pre-compile all numba functions with dummy data"""
19+
global _NUMBA_COMPILED
20+
21+
if _NUMBA_COMPILED:
22+
return
23+
24+
print("Pre-compiling numba functions for DABEST...")
25+
26+
# Create dummy data
27+
dummy_control = np.array([1.0, 2.0, 3.0])
28+
dummy_test = np.array([4.0, 5.0, 6.0])
29+
30+
funcs = [
31+
# effsize.py functions
32+
(effsize.cohens_d, (dummy_control, dummy_test)),
33+
(effsize._mann_whitney_u, (dummy_control, dummy_test)),
34+
(effsize._cliffs_delta_core, (dummy_control, dummy_test)),
35+
(effsize._compute_standardizers, (dummy_control, dummy_test)),
36+
(effsize.weighted_delta, (np.array([1.0, 2.0]), np.array([0.1, 0.2]))),
37+
38+
# confint_2group_diff.py functions
39+
(confint_2group_diff.create_jackknife_indexes, (dummy_control,)),
40+
(confint_2group_diff.create_repeated_indexes, (dummy_control,)),
41+
(confint_2group_diff.bootstrap_indices, (True, 3, 3, 10, 12345)),
42+
(confint_2group_diff.delta2_bootstrap_loop,
43+
(dummy_control, dummy_test, dummy_control, dummy_test, 10, 1.0, 12345, False)),
44+
(confint_2group_diff._compute_quantile, (0.5, 0.1, 0.1)),
45+
(confint_2group_diff.calculate_group_var, (1.0, 3, 1.0, 3))
46+
]
47+
48+
for func, args in tqdm(funcs, desc="Compiling numba functions"):
49+
func(*args)
50+
51+
_NUMBA_COMPILED = True
52+
53+
print("Numba compilation complete!")

0 commit comments

Comments
 (0)