from typing import Dict, List, Optional, Tuple
from pyutils import dict_utils
+from pyutils.types.simple import Numeric
class NumericPopulation(object):
- """This object *store* a numerical population in a way that enables relatively
+ """This object *store* a numeric population in a way that enables relatively
fast addition of new numbers (:math:`O(2log_2 n)`) and instant access to the
median value in the population (:math:`O(1)`). It also provides other population
- summary statistics such as the :meth:`mode`, :meth:`get_percentile` and
- :meth:`stdev`.
+ summary statistics such as the :meth:`get_mode`, :meth:`get_percentile` and
+ :meth:`get_stdev`.
.. note::
>>> pop.get_mean()
5.2
>>> round(pop.get_stdev(), 1)
- 1.4
+ 3.1
>>> pop.get_percentile(20)
3
>>> pop.get_percentile(60)
def __init__(self):
self.lowers, self.highers = [], []
self.aggregate = 0.0
- self.sorted_copy: Optional[List[float]] = None
+ self.sorted_copy: Optional[List[Numeric]] = None
self.maximum = None
self.minimum = None
- def add_number(self, number: float):
+ def add_number(self, number: Numeric):
"""Adds a number to the population. Runtime complexity of this
operation is :math:`O(2 log_2 n)`
elif len(self.highers) - len(self.lowers) > 1:
heappush(self.lowers, -heappop(self.highers))
- def get_median(self) -> float:
+ def get_median(self) -> Numeric:
"""
Returns:
The median (p50) of the current population in :math:`O(1)` time.
count = len(self)
return self.aggregate / count
- def get_mode(self) -> Tuple[float, int]:
+ def get_mode(self) -> Tuple[Numeric, int]:
"""
Returns:
The population mode (most common member in the population)
in :math:`O(n)` time.
"""
- count: Dict[float, int] = collections.defaultdict(int)
+ count: Dict[Numeric, int] = collections.defaultdict(int)
for n in self.lowers:
count[-n] += 1
for n in self.highers:
for n in self.highers:
variance += (n - mean) ** 2
count = len(self.lowers) + len(self.highers)
- return math.sqrt(variance) / count
+ return math.sqrt(variance / count)
def _create_sorted_copy_if_needed(self, count: int):
"""Internal helper."""
self.sorted_copy.append(x)
self.sorted_copy = sorted(self.sorted_copy)
- def get_percentile(self, n: float) -> float:
+ def get_percentile(self, n: float) -> Numeric:
"""
Returns: the number at approximately pn% in the population
(i.e. the nth percentile) in :math:`O(n log_2 n)` time (it
Args:
n: the float to truncate
+ decimals: how many decimal places are desired?
>>> truncate_float(3.1415927, 3)
3.141
return True
-if __name__ == '__main__':
+if __name__ == "__main__":
import doctest
doctest.testmod()