@@ -7072,6 +7072,10 @@ def power_divergence(f_obs, f_exp=None, ddof=0, axis=0, lambda_=None):
7072
7072
(array([ 3.5 , 9.25]), array([ 0.62338763, 0.09949846]))
7073
7073
7074
7074
"""
7075
+ return _power_divergence (f_obs , f_exp = f_exp , ddof = ddof , axis = axis , lambda_ = lambda_ )
7076
+
7077
+
7078
+ def _power_divergence (f_obs , f_exp , ddof , axis , lambda_ , sum_check = True ):
7075
7079
xp = array_namespace (f_obs )
7076
7080
default_float = xp .asarray (1. ).dtype
7077
7081
@@ -7110,21 +7114,23 @@ def warn_masked(arg):
7110
7114
bshape = _broadcast_shapes ((f_obs_float .shape , f_exp .shape ))
7111
7115
f_obs_float = _m_broadcast_to (f_obs_float , bshape , xp = xp )
7112
7116
f_exp = _m_broadcast_to (f_exp , bshape , xp = xp )
7113
- dtype_res = xp .result_type (f_obs .dtype , f_exp .dtype )
7114
- rtol = xp .finfo (dtype_res ).eps ** 0.5 # to pass existing tests
7115
- with np .errstate (invalid = 'ignore' ):
7116
- f_obs_sum = _m_sum (f_obs_float , axis = axis , preserve_mask = False , xp = xp )
7117
- f_exp_sum = _m_sum (f_exp , axis = axis , preserve_mask = False , xp = xp )
7118
- relative_diff = (xp .abs (f_obs_sum - f_exp_sum ) /
7119
- xp .minimum (f_obs_sum , f_exp_sum ))
7120
- diff_gt_tol = xp .any (relative_diff > rtol , axis = None )
7121
- if diff_gt_tol :
7122
- msg = (f"For each axis slice, the sum of the observed "
7123
- f"frequencies must agree with the sum of the "
7124
- f"expected frequencies to a relative tolerance "
7125
- f"of { rtol } , but the percent differences are:\n "
7126
- f"{ relative_diff } " )
7127
- raise ValueError (msg )
7117
+
7118
+ if sum_check :
7119
+ dtype_res = xp .result_type (f_obs .dtype , f_exp .dtype )
7120
+ rtol = xp .finfo (dtype_res ).eps ** 0.5 # to pass existing tests
7121
+ with np .errstate (invalid = 'ignore' ):
7122
+ f_obs_sum = _m_sum (f_obs_float , axis = axis , preserve_mask = False , xp = xp )
7123
+ f_exp_sum = _m_sum (f_exp , axis = axis , preserve_mask = False , xp = xp )
7124
+ relative_diff = (xp .abs (f_obs_sum - f_exp_sum ) /
7125
+ xp .minimum (f_obs_sum , f_exp_sum ))
7126
+ diff_gt_tol = xp .any (relative_diff > rtol , axis = None )
7127
+ if diff_gt_tol :
7128
+ msg = (f"For each axis slice, the sum of the observed "
7129
+ f"frequencies must agree with the sum of the "
7130
+ f"expected frequencies to a relative tolerance "
7131
+ f"of { rtol } , but the percent differences are:\n "
7132
+ f"{ relative_diff } " )
7133
+ raise ValueError (msg )
7128
7134
7129
7135
else :
7130
7136
# Ignore 'invalid' errors so the edge case of a data set with length 0
@@ -7164,29 +7170,36 @@ def warn_masked(arg):
7164
7170
return Power_divergenceResult (stat , pvalue )
7165
7171
7166
7172
7167
- def chisquare (f_obs , f_exp = None , ddof = 0 , axis = 0 ):
7168
- """Calculate a one-way chi-square test.
7173
+ def chisquare (f_obs , f_exp = None , ddof = 0 , axis = 0 , * , sum_check = True ):
7174
+ """Perform Pearson's chi-squared test.
7169
7175
7170
- The chi-square test tests the null hypothesis that the categorical data
7171
- has the given frequencies.
7176
+ Pearson's chi-squared test [1]_ is a goodness-of-fit test for a multinomial
7177
+ distribution with given probabilities; that is, it assesses the null hypothesis
7178
+ that the observed frequencies (counts) are obtained by independent
7179
+ sampling of *N* observations from a categorical distribution with given
7180
+ expected frequencies.
7172
7181
7173
7182
Parameters
7174
7183
----------
7175
7184
f_obs : array_like
7176
7185
Observed frequencies in each category.
7177
7186
f_exp : array_like, optional
7178
- Expected frequencies in each category. By default the categories are
7187
+ Expected frequencies in each category. By default, the categories are
7179
7188
assumed to be equally likely.
7180
7189
ddof : int, optional
7181
7190
"Delta degrees of freedom": adjustment to the degrees of freedom
7182
7191
for the p-value. The p-value is computed using a chi-squared
7183
- distribution with ``k - 1 - ddof`` degrees of freedom, where `k`
7184
- is the number of observed frequencies. The default value of `ddof`
7185
- is 0.
7192
+ distribution with ``k - 1 - ddof`` degrees of freedom, where ``k``
7193
+ is the number of categories. The default value of `ddof` is 0.
7186
7194
axis : int or None, optional
7187
7195
The axis of the broadcast result of `f_obs` and `f_exp` along which to
7188
7196
apply the test. If axis is None, all values in `f_obs` are treated
7189
7197
as a single data set. Default is 0.
7198
+ sum_check : bool, optional
7199
+ Whether to perform a check that ``sum(f_obs) - sum(f_exp) == 0``. If True,
7200
+ (default) raise an error when the relative difference exceeds the square root
7201
+ of the precision of the data type. See Notes for rationale and possible
7202
+ exceptions.
7190
7203
7191
7204
Returns
7192
7205
-------
@@ -7212,15 +7225,11 @@ def chisquare(f_obs, f_exp=None, ddof=0, axis=0):
7212
7225
-----
7213
7226
This test is invalid when the observed or expected frequencies in each
7214
7227
category are too small. A typical rule is that all of the observed
7215
- and expected frequencies should be at least 5. According to [3 ]_, the
7216
- total number of samples is recommended to be greater than 13,
7228
+ and expected frequencies should be at least 5. According to [2 ]_, the
7229
+ total number of observations is recommended to be greater than 13,
7217
7230
otherwise exact tests (such as Barnard's Exact test) should be used
7218
7231
because they do not overreject.
7219
7232
7220
- Also, the sum of the observed and expected frequencies must be the same
7221
- for the test to be valid; `chisquare` raises an error if the sums do not
7222
- agree within a relative tolerance of ``1e-8``.
7223
-
7224
7233
The default degrees of freedom, k-1, are for the case when no parameters
7225
7234
of the distribution are estimated. If p parameters are estimated by
7226
7235
efficient maximum likelihood then the correct degrees of freedom are
@@ -7229,13 +7238,23 @@ def chisquare(f_obs, f_exp=None, ddof=0, axis=0):
7229
7238
the asymptotic distribution is not chi-square, in which case this test
7230
7239
is not appropriate.
7231
7240
7241
+ For Pearson's chi-squared test, the total observed and expected counts must match
7242
+ for the p-value to accurately reflect the probability of observing such an extreme
7243
+ value of the statistic under the null hypothesis.
7244
+ This function may be used to perform other statistical tests that do not require
7245
+ the total counts to be equal. For instance, to test the null hypothesis that
7246
+ ``f_obs[i]`` is Poisson-distributed with expectation ``f_exp[i]``, set ``ddof=-1``
7247
+ and ``sum_check=False``. This test follows from the fact that a Poisson random
7248
+ variable with mean and variance ``f_exp[i]`` is approximately normal with the
7249
+ same mean and variance; the chi-squared statistic standardizes, squares, and sums
7250
+ the observations; and the sum of ``n`` squared standard normal variables follows
7251
+ the chi-squared distribution with ``n`` degrees of freedom.
7252
+
7232
7253
References
7233
7254
----------
7234
- .. [1] Lowry, Richard. "Concepts and Applications of Inferential
7235
- Statistics". Chapter 8.
7236
- https://web.archive.org/web/20171022032306/http://vassarstats.net:80/textbook/ch8pt1.html
7237
- .. [2] "Chi-squared test", https://en.wikipedia.org/wiki/Chi-squared_test
7238
- .. [3] Pearson, Karl. "On the criterion that a given system of deviations from the probable
7255
+ .. [1] "Pearson's chi-squared test".
7256
+ *Wikipedia*. https://en.wikipedia.org/wiki/Pearson%27s_chi-squared_test
7257
+ .. [2] Pearson, Karl. "On the criterion that a given system of deviations from the probable
7239
7258
in the case of a correlated system of variables is such that it can be reasonably
7240
7259
supposed to have arisen from random sampling", Philosophical Magazine. Series 5. 50
7241
7260
(1900), pp. 157-175.
@@ -7295,8 +7314,8 @@ def chisquare(f_obs, f_exp=None, ddof=0, axis=0):
7295
7314
7296
7315
For a more detailed example, see :ref:`hypothesis_chisquare`.
7297
7316
""" # noqa: E501
7298
- return power_divergence (f_obs , f_exp = f_exp , ddof = ddof , axis = axis ,
7299
- lambda_ = "pearson" )
7317
+ return _power_divergence (f_obs , f_exp = f_exp , ddof = ddof , axis = axis ,
7318
+ lambda_ = "pearson" , sum_check = sum_check )
7300
7319
7301
7320
7302
7321
KstestResult = _make_tuple_bunch ('KstestResult' , ['statistic' , 'pvalue' ],
0 commit comments