Repository: scipy/scipy

Issue:
BUG: scipy.stats.brunnermunzel incorrectly returns nan for undocumented reason
### Describe your issue.

```python

x = np.array([1,2,3])
y = np.array([5,6,7,8,9])

scipy.stats.brunnermunzel(x,y)

```

returns:

```
BrunnerMunzelResult(statistic=inf, pvalue=nan)
```

### Reproducing Code Example

```python
x = np.array([1,2,3])
y = np.array([5,6,7,8,9])

scipy.stats.brunnermunzel(x,y)
```


### Error message

```shell
None.
```


### SciPy/NumPy/Python version information

1.8.0 1.21.5 sys.version_info(major=3, minor=8, micro=12, releaselevel='final', serial=0)
BUG: scipy.stats.brunnermunzel incorrectly returns nan for undocumented reason
### Describe your issue.

```python

x = np.array([1,2,3])
y = np.array([5,6,7,8,9])

scipy.stats.brunnermunzel(x,y)

```

returns:

```
BrunnerMunzelResult(statistic=inf, pvalue=nan)
```

### Reproducing Code Example

```python
x = np.array([1,2,3])
y = np.array([5,6,7,8,9])

scipy.stats.brunnermunzel(x,y)
```


### Error message

```shell
None.
```


### SciPy/NumPy/Python version information

1.8.0 1.21.5 sys.version_info(major=3, minor=8, micro=12, releaselevel='final', serial=0)


Discussion:
I haven't investigated carefully, but it does not have to do with the sample sizes being unequal:
```python3
x1 = [1,2,3,4,5]
x2 = [5,6]
w, p_value = scipy.stats.brunnermunzel(x1, x2)  # OK
```
or simply that the total sample size is too small. It looks to me like it depends on the particular values. This should be assessed for correctness and, if it is correct, it might help to document it in the notes section. 

@sg-s, I'd suggest that you take a look at the definition of the `brunnermunzel` statistic and determining whether `inf` is indeed the appropriate value. This is not necessarily an implementation bug but an issue with the test statistic. (If the p-value is to be calculated with a normal or t approximation, we probably could return a p-value of `0` or `1`, whichever is appropriate. But the p-value of an exact permutation test would certainly not be `0` or `1`, so an argument might be made for NaN rather than suggesting an extreme p-value like this.) 

hi @mdhaber your counterexample is interesting. it's an issue that happens when you have small sizes and unequal sample sizes.

i should mention that it also throws this cryptic warning:

```
/Users/srinivas/opt/anaconda3/envs/longo/lib/python3.8/site-packages/scipy/stats/_stats_py.py:8055: RuntimeWarning:

divide by zero encountered in double_scalars

/Users/srinivas/opt/anaconda3/envs/longo/lib/python3.8/site-packages/scipy/stats/_stats_py.py:8061: RuntimeWarning:

invalid value encountered in double_scalars
```

meanwhile, this works:

```python
x = np.arange(0,12)
y = np.arange(5,20)

scipy.stats.brunnermunzel(x,y)
```

i suspect that when effect sizes are very large, (when statistic is inf) the pvalue should be 0, but it's being reported as `nan`

and so does this:


```python
x = np.arange(0,3)
y = x + 1

scipy.stats.brunnermunzel(x,y)
```

but this doesn't:


```python
x = np.arange(0,3)
y = x + 3

scipy.stats.brunnermunzel(x,y)
```





I haven't investigated carefully, but it does not have to do with the sample sizes being unequal:
```python3
x1 = [1,2,3,4,5]
x2 = [5,6]
w, p_value = scipy.stats.brunnermunzel(x1, x2)  # OK
```
or simply that the total sample size is too small. It looks to me like it depends on the particular values. This should be assessed for correctness and, if it is correct, it might help to document it in the notes section. 

@sg-s, I'd suggest that you take a look at the definition of the `brunnermunzel` statistic and determining whether `inf` is indeed the appropriate value. This is not necessarily an implementation bug but an issue with the test statistic. (If the p-value is to be calculated with a normal or t approximation, we probably could return a p-value of `0` or `1`, whichever is appropriate. But the p-value of an exact permutation test would certainly not be `0` or `1`, so an argument might be made for NaN rather than suggesting an extreme p-value like this.) 

hi @mdhaber your counterexample is interesting. it's an issue that happens when you have small sizes and unequal sample sizes.

i should mention that it also throws this cryptic warning:

```
/Users/srinivas/opt/anaconda3/envs/longo/lib/python3.8/site-packages/scipy/stats/_stats_py.py:8055: RuntimeWarning:

divide by zero encountered in double_scalars

/Users/srinivas/opt/anaconda3/envs/longo/lib/python3.8/site-packages/scipy/stats/_stats_py.py:8061: RuntimeWarning:

invalid value encountered in double_scalars
```

meanwhile, this works:

```python
x = np.arange(0,12)
y = np.arange(5,20)

scipy.stats.brunnermunzel(x,y)
```

i suspect that when effect sizes are very large, (when statistic is inf) the pvalue should be 0, but it's being reported as `nan`

and so does this:


```python
x = np.arange(0,3)
y = x + 1

scipy.stats.brunnermunzel(x,y)
```

but this doesn't:


```python
x = np.arange(0,3)
y = x + 3

scipy.stats.brunnermunzel(x,y)
```






Resolving patch:
diff --git a/scipy/stats/_stats_py.py b/scipy/stats/_stats_py.py
--- a/scipy/stats/_stats_py.py
+++ b/scipy/stats/_stats_py.py
@@ -8232,6 +8232,13 @@ def brunnermunzel(x, y, alternative="two-sided", distribution="t",
         df_denom = np.power(nx * Sx, 2.0) / (nx - 1)
         df_denom += np.power(ny * Sy, 2.0) / (ny - 1)
         df = df_numer / df_denom
+
+        if (df_numer == 0) and (df_denom == 0):
+            message = ("p-value cannot be estimated with `distribution='t' "
+                       "because degrees of freedom parameter is undefined "
+                       "(0/0). Try using `distribution='normal'")
+            warnings.warn(message, RuntimeWarning)
+
         p = distributions.t.cdf(wbfn, df)
     elif distribution == "normal":
         p = distributions.norm.cdf(wbfn)


Test patch:
diff --git a/scipy/stats/tests/test_stats.py b/scipy/stats/tests/test_stats.py
--- a/scipy/stats/tests/test_stats.py
+++ b/scipy/stats/tests/test_stats.py
@@ -6980,6 +6980,27 @@ def test_brunnermunzel_nan_input_omit(self):
         assert_approx_equal(p1, 0.0057862086661515377,
                             significant=self.significant)
 
+    def test_brunnermunzel_return_nan(self):
+        """ tests that a warning is emitted when p is nan
+        p-value with t-distributions can be nan (0/0) (see gh-15843)
+        """
+        x = [1, 2, 3]
+        y = [5, 6, 7, 8, 9]
+
+        with pytest.warns(RuntimeWarning, match='p-value cannot be estimated'):
+            stats.brunnermunzel(x, y, distribution="t")
+
+    def test_brunnermunzel_normal_dist(self):
+        """ tests that a p is 0 for datasets that cause p->nan
+        when t-distribution is used (see gh-15843)
+        """
+        x = [1, 2, 3]
+        y = [5, 6, 7, 8, 9]
+
+        with pytest.warns(RuntimeWarning, match='divide by zero'):
+            _, p = stats.brunnermunzel(x, y, distribution="normal")
+        assert_equal(p, 0)
+
 
 class TestRatioUniforms:
     """ Tests for rvs_ratio_uniforms.