Skip to content

Commit 7baf502

Browse files
committed
modify notebook, add part for delta_g
1 parent 5b890c1 commit 7baf502

6 files changed

Lines changed: 363 additions & 77 deletions

File tree

dabest/_classes.py

Lines changed: 87 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,9 @@ def __init__(self, data, idx, x, y, paired, id_col, ci,
356356

357357
self.__hedges_g = EffectSizeDataFrame(self, "hedges_g",
358358
**EffectSizeDataFrame_kwargs)
359+
360+
self.__delta_g = EffectSizeDataFrame(self, "delta_g",
361+
**EffectSizeDataFrame_kwargs)
359362

360363
if not paired:
361364
self.__cliffs_delta = EffectSizeDataFrame(self, "cliffs_delta",
@@ -488,6 +491,12 @@ def cliffs_delta(self):
488491
"""
489492
return self.__cliffs_delta
490493

494+
@property
495+
def delta_g(self):
496+
"""
497+
Returns an :py:class:`EffectSizeDataFrame` for deltas' g, its confidence interval, and relevant statistics, for all comparisons as indicated via the `idx` and `paired` argument in `dabest.load()`.
498+
"""
499+
return self.__delta_g
491500

492501
@property
493502
def data(self):
@@ -668,7 +677,7 @@ def _all_plot_groups(self):
668677
"""
669678
return self.__all_plot_groups
670679

671-
# %% ../nbs/API/class.ipynb 25
680+
# %% ../nbs/API/class.ipynb 28
672681
class DeltaDelta(object):
673682
"""
674683
A class to compute and store the delta-delta statistics for experiments with a 2-by-2 arrangement where two independent variables, A and B, each have two categorical values, 1 and 2. The data is divided into two pairs of two groups, and a primary delta is first calculated as the mean difference between each of the pairs:
@@ -685,10 +694,20 @@ class DeltaDelta(object):
685694
686695
687696
$$\Delta_{\Delta} = \Delta_{2} - \Delta_{1}$$
697+
698+
and a deltas' g value is calculated as the mean difference between the two primary deltas divided by
699+
the standard deviation of the delta-delta value, which is calculated from a pooled variance of the 4 samples:
700+
701+
$$\Delta_{g} = \frac{\Delta_{\Delta}}{s_{\Delta_{\Delta}}}$$
702+
703+
$$s_{\Delta_{\Delta}} = \sqrt{\frac{(n_{A_{2}, B_{1}}-1)s_{A_{2}, B_{1}}^2+(n_{A_{1}, B_{1}}-1)s_{A_{1}, B_{1}}^2+(n_{A_{2}, B_{2}}-1)s_{A_{2}, B_{2}}^2+(n_{A_{1}, B_{2}}-1)s_{A_{1}, B_{2}}^2}{(n_{A_{2}, B_{1}} - 1) + (n_{A_{1}, B_{1}} - 1) + (n_{A_{2}, B_{2}} - 1) + (n_{A_{1}, B_{2}} - 1)}}$$
704+
705+
where $s$ is the standard deviation and $n$ is the sample size.
706+
688707
689708
"""
690709

691-
def __init__(self, effectsizedataframe, permutation_count,
710+
def __init__(self, effectsizedataframe, permutation_count,bootstraps_delta_delta,
692711
ci=95):
693712

694713
import numpy as np
@@ -706,22 +725,21 @@ def __init__(self, effectsizedataframe, permutation_count,
706725
self.__dabest_obj = effectsizedataframe.dabest_obj
707726
self.__ci = ci
708727
self.__resamples = effectsizedataframe.resamples
728+
self.__effect_size = effectsizedataframe.effect_size
709729
self.__alpha = ci2g._compute_alpha_from_ci(ci)
710730
self.__permutation_count = permutation_count
711731
self.__bootstraps = np.array(self.__effsizedf["bootstraps"])
712732
self.__control = self.__dabest_obj.experiment_label[0]
713733
self.__test = self.__dabest_obj.experiment_label[1]
714734

715735

716-
# Compute the bootstrap delta-delta and the true dela-delta based on
717-
# the raw data
718-
self.__bootstraps_delta_delta = self.__bootstraps[1] - self.__bootstraps[0]
719-
720-
self.__difference = self.__effsizedf["difference"][1] - self.__effsizedf["difference"][0]
721-
722-
723-
724-
sorted_delta_delta = npsort(self.__bootstraps_delta_delta)
736+
# Compute the bootstrap delta-delta or deltas' g and the true dela-delta based on the raw data
737+
if self.__effect_size == "mean_diff":
738+
self.__bootstraps_delta_delta = bootstraps_delta_delta[2]
739+
self.__difference = self.__effsizedf["difference"][1] - self.__effsizedf["difference"][0]
740+
else:
741+
self.__bootstraps_delta_delta = bootstraps_delta_delta[0]
742+
self.__difference = bootstraps_delta_delta[1]
725743

726744
self.__bias_correction = ci2g.compute_meandiff_bias_correction(
727745
self.__bootstraps_delta_delta, self.__difference)
@@ -811,7 +829,10 @@ def __repr__(self, header=True, sigfig=3):
811829
first_line = {"control" : self.__control,
812830
"test" : self.__test}
813831

814-
out1 = "The delta-delta between {control} and {test} ".format(**first_line)
832+
if self.__effect_size == "mean_diff":
833+
out1 = "The delta-delta between {control} and {test} ".format(**first_line)
834+
else:
835+
out1 = "The deltas' g between {control} and {test} ".format(**first_line)
815836

816837
base_string_fmt = "{:." + str(sigfig) + "}"
817838
if "." in str(self.__ci):
@@ -1027,7 +1048,7 @@ def permutations_delta_delta(self):
10271048

10281049

10291050

1030-
# %% ../nbs/API/class.ipynb 29
1051+
# %% ../nbs/API/class.ipynb 32
10311052
class MiniMetaDelta(object):
10321053
"""
10331054
A class to compute and store the weighted delta.
@@ -1490,7 +1511,7 @@ def permutations_weighted_delta(self):
14901511

14911512

14921513

1493-
# %% ../nbs/API/class.ipynb 34
1514+
# %% ../nbs/API/class.ipynb 37
14941515
class TwoGroupsEffectSize(object):
14951516

14961517
"""
@@ -1577,7 +1598,8 @@ def __init__(self, control, test, effect_size,
15771598
"cohens_d" : "Cohen's d",
15781599
"cohens_h" : "Cohen's h",
15791600
"hedges_g" : "Hedges' g",
1580-
"cliffs_delta" : "Cliff's delta"}
1601+
"cliffs_delta" : "Cliff's delta",
1602+
"delta_g" : "deltas' g"}
15811603

15821604

15831605
kosher_es = [a for a in self.__EFFECT_SIZE_DICT.keys()]
@@ -2177,7 +2199,7 @@ def proportional_difference(self):
21772199
return npnan
21782200

21792201

2180-
# %% ../nbs/API/class.ipynb 38
2202+
# %% ../nbs/API/class.ipynb 41
21812203
class EffectSizeDataFrame(object):
21822204
"""A class that generates and stores the results of bootstrapped effect
21832205
sizes for several comparisons."""
@@ -2213,6 +2235,7 @@ def __init__(self, dabest, effect_size,
22132235
def __pre_calc(self):
22142236
import pandas as pd
22152237
from .misc_tools import print_greeting, get_varname
2238+
from ._stats_tools import confint_2group_diff as ci2g
22162239

22172240
idx = self.__dabest_obj.idx
22182241
dat = self.__dabest_obj._plot_data
@@ -2221,6 +2244,24 @@ def __pre_calc(self):
22212244

22222245
out = []
22232246
reprs = []
2247+
2248+
if self.__delta2==True:
2249+
mixed_data = []
2250+
for j, current_tuple in enumerate(idx):
2251+
if self.__is_paired != "sequential":
2252+
cname = current_tuple[0]
2253+
control = dat[dat[xvar] == cname][yvar].copy()
2254+
2255+
for ix, tname in enumerate(current_tuple[1:]):
2256+
if self.__is_paired == "sequential":
2257+
cname = current_tuple[ix]
2258+
control = dat[dat[xvar] == cname][yvar].copy()
2259+
test = dat[dat[xvar] == tname][yvar].copy()
2260+
mixed_data.append(control)
2261+
mixed_data.append(test)
2262+
bootstraps_delta_delta = ci2g.compute_delta2_bootstrapped_diff(mixed_data[0], mixed_data[1], mixed_data[2], mixed_data[3],
2263+
self.__is_paired, self.__resamples, self.__random_seed)
2264+
22242265

22252266
for j, current_tuple in enumerate(idx):
22262267
if self.__is_paired!="sequential":
@@ -2248,7 +2289,7 @@ def __pre_calc(self):
22482289
r_dict["test_N"] = int(len(test))
22492290
out.append(r_dict)
22502291
if j == len(idx)-1 and ix == len(current_tuple)-2:
2251-
if self.__delta2 and self.__effect_size == "mean_diff":
2292+
if self.__delta2 and self.__effect_size in ["mean_diff","delta_g"]:
22522293
resamp_count = False
22532294
def_pval = False
22542295
elif self.__mini_meta and self.__effect_size == "mean_diff":
@@ -2318,12 +2359,13 @@ def __pre_calc(self):
23182359
self.__results.insert(5, 'is_paired', self.__results.apply(lambda _: None, axis=1))
23192360

23202361
# Create and compute the delta-delta statistics
2321-
if self.__delta2 is True and self.__effect_size == "mean_diff":
2362+
if self.__delta2 is True:
23222363
self.__delta_delta = DeltaDelta(self,
23232364
self.__permutation_count,
2365+
bootstraps_delta_delta,
23242366
self.__ci)
23252367
reprs.append(self.__delta_delta.__repr__(header=False))
2326-
elif self.__delta2 is True and self.__effect_size != "mean_diff":
2368+
elif self.__delta2 is True and self.__effect_size not in ["mean_diff", "delta_g"]:
23272369
self.__delta_delta = "Delta-delta is not supported for {}.".format(self.__effect_size)
23282370
else:
23292371
self.__delta_delta = "`delta2` is False; delta-delta is therefore not calculated."
@@ -2423,8 +2465,8 @@ def plot(self, color_col=None,
24232465

24242466
raw_marker_size=6, es_marker_size=9,
24252467

2426-
swarm_label=None, barchart_label=None, contrast_label=None, delta2_label=None,
2427-
swarm_ylim=None, barchart_ylim=None, contrast_ylim=None, delta2_ylim=None,
2468+
swarm_label=None, contrast_label=None, delta2_label=None,
2469+
swarm_ylim=None, contrast_ylim=None, delta2_ylim=None,
24282470

24292471
custom_palette=None, swarm_desat=0.5, halfviolin_desat=1,
24302472
halfviolin_alpha=0.8,
@@ -2453,7 +2495,10 @@ def plot(self, color_col=None,
24532495
sankey_kwargs=None,
24542496
reflines_kwargs=None,
24552497
group_summary_kwargs=None,
2456-
legend_kwargs=None):
2498+
legend_kwargs=None,
2499+
title=None, fontsize_title = 16,
2500+
fontsize_rawxlabel = 12,fontsize_rawylabel = 12,fontsize_contrastxlabel = 12, fontsize_contrastylabel = 12,
2501+
fontsize_delta2label = 12):
24572502

24582503
"""
24592504
Creates an estimation plot for the effect size of interest.
@@ -2574,6 +2619,24 @@ def plot(self, color_col=None,
25742619
`legend` command here, as a dict. If None, the following keywords
25752620
are passed to matplotlib.Axes.legend : {'loc':'upper left',
25762621
'frameon':False}.
2622+
title : string, default None
2623+
Title for the plot. If None, no title will be displayed. Pass any
2624+
keyword arguments accepted by the matplotlib.pyplot.suptitle `t` command here,
2625+
as a string.
2626+
fontsize_title : float or {'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'}, default 'large'
2627+
Font size for the plot title. If a float, the fontsize in points. The
2628+
string values denote sizes relative to the default font size. Pass any keyword arguments accepted
2629+
by the matplotlib.pyplot.suptitle `fontsize` command here, as a string.
2630+
fontsize_rawxlabel : float, default 12
2631+
Font size for the raw axes xlabel.
2632+
fontsize_rawylabel : float, default 12
2633+
Font size for the raw axes ylabel.
2634+
fontsize_contrastxlabel : float, default 12
2635+
Font size for the contrast axes xlabel.
2636+
fontsize_contrastylabel : float, default 12
2637+
Font size for the contrast axes ylabel.
2638+
fontsize_delta2label : float, default 12
2639+
Font size for the delta-delta axes ylabel.
25772640
25782641
25792642
Returns
@@ -2778,7 +2841,7 @@ def delta_delta(self):
27782841

27792842

27802843

2781-
# %% ../nbs/API/class.ipynb 56
2844+
# %% ../nbs/API/class.ipynb 59
27822845
class PermutationTest:
27832846
"""
27842847
A class to compute and report permutation tests.
@@ -2790,7 +2853,7 @@ class PermutationTest:
27902853
These should be numerical iterables.
27912854
effect_size : string.
27922855
Any one of the following are accepted inputs:
2793-
'mean_diff', 'median_diff', 'cohens_d', 'hedges_g', or 'cliffs_delta'
2856+
'mean_diff', 'median_diff', 'cohens_d', 'hedges_g', 'delta_g" or 'cliffs_delta'
27942857
is_paired : string, default None
27952858
permutation_count : int, default 10000
27962859
The number of permutations (reshuffles) to perform.

dabest/_stats_tools/effsize.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def two_group_difference(control:list|tuple|np.ndarray, #Accepts lists, tuples,
5959
import numpy as np
6060
import warnings
6161

62-
if effect_size == "mean_diff":
62+
if effect_size == "mean_diff" or effect_size=="delta_g":
6363
return func_difference(control, test, np.mean, is_paired)
6464

6565
elif effect_size == "median_diff":
@@ -78,7 +78,7 @@ def two_group_difference(control:list|tuple|np.ndarray, #Accepts lists, tuples,
7878
elif effect_size == "cohens_h":
7979
return cohens_h(control, test)
8080

81-
elif effect_size == "hedges_g":
81+
elif effect_size == "hedges_g" or effect_size == "delta_g":
8282
return hedges_g(control, test, is_paired)
8383

8484
elif effect_size == "cliffs_delta":

0 commit comments

Comments
 (0)