summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorRaymond Hettinger <rhettinger@users.noreply.github.com>2022-05-09 07:08:41 (GMT)
committerGitHub <noreply@github.com>2022-05-09 07:08:41 (GMT)
commite01eeb7b4b8d00b9f5c6acb48957f46ac4e252c0 (patch)
treeddbd5234dd8bc3083003567836c2699c3696b19a /Lib
parent5bc2390229bbcb4f13359e867fd8a140a1d5496b (diff)
downloadcpython-e01eeb7b4b8d00b9f5c6acb48957f46ac4e252c0.zip
cpython-e01eeb7b4b8d00b9f5c6acb48957f46ac4e252c0.tar.gz
cpython-e01eeb7b4b8d00b9f5c6acb48957f46ac4e252c0.tar.bz2
Fix inconsistent return type for statistics median_grouped() gh-92531 (#92533)
Diffstat (limited to 'Lib')
-rw-r--r--Lib/statistics.py27
-rw-r--r--Lib/test/test_statistics.py6
2 files changed, 19 insertions, 14 deletions
diff --git a/Lib/statistics.py b/Lib/statistics.py
index 54f4e13..2d66b05 100644
--- a/Lib/statistics.py
+++ b/Lib/statistics.py
@@ -611,7 +611,7 @@ def median_high(data):
return data[n // 2]
-def median_grouped(data, interval=1):
+def median_grouped(data, interval=1.0):
"""Estimates the median for numeric data binned around the midpoints
of consecutive, fixed-width intervals.
@@ -650,35 +650,34 @@ def median_grouped(data, interval=1):
by exact multiples of *interval*. This is essential for getting a
correct result. The function does not check this precondition.
+ Inputs may be any numeric type that can be coerced to a float during
+ the interpolation step.
+
"""
data = sorted(data)
n = len(data)
- if n == 0:
+ if not n:
raise StatisticsError("no median for empty data")
- elif n == 1:
- return data[0]
# Find the value at the midpoint. Remember this corresponds to the
# midpoint of the class interval.
x = data[n // 2]
- # Generate a clear error message for non-numeric data
- for obj in (x, interval):
- if isinstance(obj, (str, bytes)):
- raise TypeError(f'expected a number but got {obj!r}')
-
# Using O(log n) bisection, find where all the x values occur in the data.
# All x will lie within data[i:j].
i = bisect_left(data, x)
j = bisect_right(data, x, lo=i)
+ # Coerce to floats, raising a TypeError if not possible
+ try:
+ interval = float(interval)
+ x = float(x)
+ except ValueError:
+ raise TypeError(f'Value cannot be converted to a float')
+
# Interpolate the median using the formula found at:
# https://www.cuemath.com/data/median-of-grouped-data/
- try:
- L = x - interval / 2 # The lower limit of the median interval.
- except TypeError:
- # Coerce mixed types to float.
- L = float(x) - float(interval) / 2
+ L = x - interval / 2.0 # Lower limit of the median interval
cf = i # Cumulative frequency of the preceding interval
f = j - i # Number of elements in the median internal
return L + interval * (n / 2 - cf) / f
diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py
index ed6021d..6de9824 100644
--- a/Lib/test/test_statistics.py
+++ b/Lib/test/test_statistics.py
@@ -1742,6 +1742,12 @@ class TestMedianGrouped(TestMedian):
data = [x]*count
self.assertEqual(self.func(data), float(x))
+ def test_single_value(self):
+ # Override method from AverageMixin.
+ # Average of a single value is the value as a float.
+ for x in (23, 42.5, 1.3e15, Fraction(15, 19), Decimal('0.28')):
+ self.assertEqual(self.func([x]), float(x))
+
def test_odd_fractions(self):
# Test median_grouped works with an odd number of Fractions.
F = Fraction