Skip to content

Commit

Permalink
several changes, updates to cochrans q test
Browse files Browse the repository at this point in the history
  • Loading branch information
aschleg committed Aug 20, 2020
1 parent bb4f096 commit d5b8451
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 13 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
@@ -1,3 +1,9 @@
## Version 0.3.2

* Cochran's Q Test
* Multiple comparisons are now available by specifying `posthoc=True` when performing the Cochran Q test.
* The test now checks that all passed sample observation vectors are the same length before proceeding to the test.

## Version 0.3.1

This release is a quick fix for McNemar's test in the `contingency` module. There was some misleading literature in one
Expand Down
65 changes: 56 additions & 9 deletions hypothetical/contingency.py
Expand Up @@ -47,6 +47,7 @@
"""

from functools import reduce
from itertools import combinations
import numpy as np
import numpy_indexed as npi
import pandas as pd
Expand Down Expand Up @@ -400,22 +401,31 @@ class CochranQ(object):
Siegel, S. (1956). Nonparametric statistics: For the behavioral sciences.
McGraw-Hill. ISBN 07-057348-4
https://ncss-wpengine.netdna-ssl.com/wp-content/themes/ncss/pdf/Procedures/NCSS/Cochrans_Q_Test.pdf
Wikipedia contributors. (2017, August 8). Cochran's Q test. In Wikipedia, The Free Encyclopedia.
Retrieved 15:05, August 26, 2018,
from https://en.wikipedia.org/w/index.php?title=Cochran%27s_Q_test&oldid=794571272
"""
def __init__(self, *args):
def __init__(self, *args, posthoc=False, names=None):
self.design_matrix = _build_des_mat(*args, group=None)
self.q_statistic, self.degrees_freedom = self._q_test(*args)
self.p_value = self._p_value()

self.test_summary = {
'q-statistic': self.q_statistic,
'p-value': self.p_value,
'degrees of freedom': self.degrees_freedom,
}

@staticmethod
def _q_test(*args):
if posthoc:
self.posthoc = self._multiple_comparisons(*args, names=names)

else:
self.posthoc = 'None'

def _q_test(self, *args):
r"""
Parameters
Expand All @@ -430,13 +440,18 @@ def _q_test(*args):
Tuple containing the computed Q test statistic and the degrees of freedom.
"""
design_matrix = _build_des_mat(*args, group=None)
sample_counts = npi.group_by(design_matrix[:, 0], design_matrix[:, 1], np.sum)
sample_size = design_matrix.shape[0] / len(np.unique(design_matrix[:, 0]))
sample_lengths = []
for i in args:
sample_lengths.append(len(i))

if len(set(sample_lengths)) != 1:
raise ValueError('all sample observation vectors must have the same length.')

sample_counts = npi.group_by(self.design_matrix[:, 0], self.design_matrix[:, 1], np.sum)
sample_size = self.design_matrix.shape[0] / len(np.unique(self.design_matrix[:, 0]))

summary_table = pd.DataFrame(sample_counts, columns=['sample', '1s'])
summary_table['sample_size'] = sample_size
summary_table['0s'] = summary_table['sample_size'] - summary_table['1s']
summary_table['0s'] = sample_size - summary_table['1s']

li2 = np.sum(np.sum(np.vstack([args]), axis=0) ** 2)

Expand All @@ -454,6 +469,38 @@ def _p_value(self):

return pval

def _multiple_comparisons(self, *args, names=None):
if names is not None:
if len(names) != len(np.unique(self.design_matrix[:, 0])):
raise ValueError('group names array must be the same length as the number of sample groups.')

else:
names = np.unique(self.design_matrix[:, 0] + 1)

dat = dict(zip(names, args))

combs = [{j: dat[j] for j in i} for i in combinations(dat, 2)]

group_comb = []
q_stat = []
p_val = []

for comb in combs:
name1, group1 = list(comb.keys())[0], list(comb.values())[0]
name2, group2 = list(comb.keys())[1], list(comb.values())[1]

c = CochranQ(group1, group2, names=[name1, name2])

group_comb.append(str(name1) + ' : ' + str(name2))
q_stat.append(c.q_statistic)
p_val.append(c.p_value)

result_df = pd.DataFrame({'groups': group_comb,
'Q statistic': q_stat,
'p-value': p_val})

return result_df


class McNemarTest(object):
r"""
Expand Down
2 changes: 1 addition & 1 deletion hypothetical/descriptive.py
Expand Up @@ -20,7 +20,7 @@
.. autosummary::
:toctree: generated/
covariance
covar
var
std_dev
Expand Down
6 changes: 6 additions & 0 deletions hypothetical/gof.py
Expand Up @@ -329,3 +329,9 @@ def _p_value(self):
p_value = chi2.sf(self.test_statistic, 2)

return p_value


class KolmogorovSmirnov(object):

def __init__(self):
pass
2 changes: 0 additions & 2 deletions hypothetical/nonparametric.py
Expand Up @@ -1107,8 +1107,6 @@ def __init__(self, *args, ties='below', continuity=True, posthoc=False, names=No
else:
self.posthoc = 'None'

self.test_summary['posthoc'] = self.posthoc

def _cont_table(self):
above = []
below = []
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -4,7 +4,7 @@

setup(
name='hypothetical',
version='0.3.1',
version='0.3.2',
author='Aaron Schlegel',
author_email='aaron@aaronschlegel.me',
description='Hypothesis testing and other testing methods',
Expand Down
6 changes: 6 additions & 0 deletions tests/test_contingency.py
Expand Up @@ -77,6 +77,12 @@ def test_cochranq(self):
assert_almost_equal(c.p_value, 0.00024036947641951404)
assert c.degrees_freedom == 2

def test_cochranq_exceptions(self):
r1, r2, r3 = [0, 1, 1], [1, 1, 0], [0, 0, 1, 1]

with pytest.raises(ValueError):
CochranQ(r1, r2, r3)


class TestMcNemarTest(object):
sample_data = np.array([[59, 6], [16, 80]])
Expand Down

0 comments on commit d5b8451

Please sign in to comment.