diff --git a/docs/user-guide/stats.rst b/docs/user-guide/stats.rst index 5a8717f3b..55757ef30 100644 --- a/docs/user-guide/stats.rst +++ b/docs/user-guide/stats.rst @@ -463,6 +463,12 @@ We will use :ref:`mann-whitney-u-test` as described above. >>> score_statistic = MannWhitneyStatistic() +.. tip:: + + See :mod:`gpsea.analysis.pscore.stats` module for more statistical tests available + for using with phenotype scores. + + **Final analysis** We will put the final analysis together into :class:`~gpsea.analysis.pscore.PhenotypeScoreAnalysis`. diff --git a/src/gpsea/analysis/pscore/stats/__init__.py b/src/gpsea/analysis/pscore/stats/__init__.py index e46bfb5e4..0d3956fad 100644 --- a/src/gpsea/analysis/pscore/stats/__init__.py +++ b/src/gpsea/analysis/pscore/stats/__init__.py @@ -1,7 +1,7 @@ from ._stats import PhenotypeScoreStatistic -from ._stats import MannWhitneyStatistic +from ._stats import MannWhitneyStatistic, TTestStatistic __all__ = [ 'PhenotypeScoreStatistic', - 'MannWhitneyStatistic', + 'MannWhitneyStatistic', 'TTestStatistic', ] diff --git a/src/gpsea/analysis/pscore/stats/_stats.py b/src/gpsea/analysis/pscore/stats/_stats.py index 01cfa4d92..7a520e84c 100644 --- a/src/gpsea/analysis/pscore/stats/_stats.py +++ b/src/gpsea/analysis/pscore/stats/_stats.py @@ -1,7 +1,7 @@ import abc import typing -from scipy.stats import mannwhitneyu +from scipy.stats import mannwhitneyu, ttest_ind class PhenotypeScoreStatistic(metaclass=abc.ABCMeta): @@ -42,3 +42,25 @@ def compute_pval( ) return pval + + +class TTestStatistic(PhenotypeScoreStatistic): + """ + `TTestStatistic` is a wrapper around SciPy's + :func:`~scipy.stats.ttest_ind` function to apply + T test on 2 phenotype scores. + """ + + def compute_pval( + self, + scores: typing.Collection[typing.Sequence[float]], + ) -> float: + assert len(scores) == 2, 'T test only supports 2 categories at this time' + + x, y = scores + res = ttest_ind( + a=x, b=y, + alternative='two-sided', + ) + + return res.pvalue diff --git a/tests/analysis/pscore/test_stats.py b/tests/analysis/pscore/test_stats.py new file mode 100644 index 000000000..42fdd2ba6 --- /dev/null +++ b/tests/analysis/pscore/test_stats.py @@ -0,0 +1,54 @@ +import typing +import pytest + +from gpsea.analysis.pscore.stats import MannWhitneyStatistic, TTestStatistic + + +class TestMannWhitneyStatistic: + + @pytest.fixture(scope='class') + def statistic(self) -> MannWhitneyStatistic: + return MannWhitneyStatistic() + + @pytest.mark.parametrize( + 'x, y, expected', + [ + ((1., 2., 3., ), (1., 2., 3., ), 1.), + ((11., 15, 8., 12.,), (4., 2., 3., 3.5, 4.,), 0.01945103333136247), + ] + ) + def test_compute_pval( + self, + statistic: MannWhitneyStatistic, + x: typing.Sequence[float], + y: typing.Sequence[float], + expected: float, + ): + actual = statistic.compute_pval((x, y)) + + assert actual == pytest.approx(expected) + + +class TestTTestStatistic: + + @pytest.fixture(scope='class') + def statistic(self) -> TTestStatistic: + return TTestStatistic() + + @pytest.mark.parametrize( + 'x, y, expected', + [ + ((1., 2., 3., ), (1., 2., 3., ), 1.), + ((11., 15, 8., 12.,), (4., 2., 3., 3.5, 4.,), 0.0004749950471148506), + ] + ) + def test_compute_pval( + self, + statistic: TTestStatistic, + x: typing.Sequence[float], + y: typing.Sequence[float], + expected: float, + ): + actual = statistic.compute_pval((x, y)) + + assert actual == pytest.approx(expected)