Source code for pydash.numerical

"""
Numerical/mathematical related functions.

.. versionadded:: 2.1.0
"""

import math
import operator
import typing as t

import pydash as pyd

from .helpers import UNSET, Unset, iterator, iterator_with_default, iteriteratee
from .types import IterateeObjT, NumberNoDecimalT, NumberT, SupportsMul, SupportsRound


if t.TYPE_CHECKING:
    from decimal import Decimal  # pragma: no cover

    from _typeshed import SupportsAdd, SupportsRichComparisonT, SupportsSub  # pragma: no cover


__all__ = (
    "add",
    "ceil",
    "clamp",
    "divide",
    "floor",
    "max_",
    "max_by",
    "mean",
    "mean_by",
    "median",
    "min_",
    "min_by",
    "moving_mean",
    "multiply",
    "power",
    "round_",
    "scale",
    "slope",
    "std_deviation",
    "sum_",
    "sum_by",
    "subtract",
    "transpose",
    "variance",
    "zscore",
)

T = t.TypeVar("T")
T2 = t.TypeVar("T2")
T3 = t.TypeVar("T3")


INFINITY = float("inf")


@t.overload
def add(a: "SupportsAdd[T, T2]", b: T) -> T2: ...


@t.overload
def add(a: T, b: "SupportsAdd[T, T2]") -> T2: ...


[docs] def add(a, b): """ Adds two numbers. Args: a: First number to add. b: Second number to add. Returns: number Example: >>> add(10, 5) 15 .. versionadded:: 2.1.0 .. versionchanged:: 3.3.0 Support adding two numbers when passed as positional arguments. .. versionchanged:: 4.0.0 Only support two argument addition. """ return a + b
@t.overload def sum_(collection: t.Mapping[t.Any, "SupportsAdd[int, T]"]) -> T: ... @t.overload def sum_(collection: t.Iterable["SupportsAdd[int, T]"]) -> T: ...
[docs] def sum_(collection): """ Sum each element in `collection`. Args: collection: Collection to process or first number to add. Returns: Result of summation. Example: >>> sum_([1, 2, 3, 4]) 10 .. versionadded:: 2.1.0 .. versionchanged:: 3.3.0 Support adding two numbers when passed as positional arguments. .. versionchanged:: 4.0.0 Move iteratee support to :func:`sum_by`. Move two argument addition to :func:`add`. """ return sum_by(collection)
@t.overload def sum_by( collection: t.Mapping[T, T2], iteratee: t.Callable[[T2, T, t.Dict[T, T2]], "SupportsAdd[int, T3]"], ) -> T3: ... @t.overload def sum_by( collection: t.Mapping[T, T2], iteratee: t.Callable[[T2, T], "SupportsAdd[int, T3]"] ) -> T3: ... @t.overload def sum_by( collection: t.Mapping[t.Any, T2], iteratee: t.Callable[[T2], "SupportsAdd[int, T3]"] ) -> T3: ... @t.overload def sum_by( collection: t.Iterable[T], iteratee: t.Callable[[T, int, t.List[T]], "SupportsAdd[int, T2]"] ) -> T2: ... @t.overload def sum_by( collection: t.Iterable[T], iteratee: t.Callable[[T, int], "SupportsAdd[int, T2]"] ) -> T2: ... @t.overload def sum_by(collection: t.Iterable[T], iteratee: t.Callable[[T], "SupportsAdd[int, T2]"]) -> T2: ... @t.overload def sum_by(collection: t.Mapping[t.Any, "SupportsAdd[int, T]"], iteratee: None = None) -> T: ... @t.overload def sum_by(collection: t.Iterable["SupportsAdd[int, T]"], iteratee: None = None) -> T: ...
[docs] def sum_by(collection, iteratee=None): """ Sum each element in `collection`. If iteratee is passed, each element of `collection` is passed through an iteratee before the summation is computed. Args: collection: Collection to process or first number to add. iteratee: Iteratee applied per iteration or second number to add. Returns: Result of summation. Example: >>> sum_by([1, 2, 3, 4], lambda x: x**2) 30 .. versionadded:: 4.0.0 """ return sum(result[0] for result in iteriteratee(collection, iteratee))
@t.overload def mean(collection: t.Mapping[t.Any, "SupportsAdd[int, t.Any]"]) -> float: ... @t.overload def mean(collection: t.Iterable["SupportsAdd[int, t.Any]"]) -> float: ...
[docs] def mean(collection): """ Calculate arithmetic mean of each element in `collection`. Args: collection: Collection to process. Returns: Result of mean. Example: >>> mean([1, 2, 3, 4]) 2.5 .. versionadded:: 2.1.0 .. versionchanged:: 4.0.0 - Removed ``average`` and ``avg`` aliases. - Moved iteratee functionality to :func:`mean_by`. """ return mean_by(collection)
@t.overload def mean_by( collection: t.Mapping[T, T2], iteratee: t.Callable[[T2, T, t.Dict[T, T2]], "SupportsAdd[int, t.Any]"], ) -> float: ... @t.overload def mean_by( collection: t.Mapping[T, T2], iteratee: t.Callable[[T2, T], "SupportsAdd[int, t.Any]"] ) -> float: ... @t.overload def mean_by( collection: t.Mapping[t.Any, T2], iteratee: t.Callable[[T2], "SupportsAdd[int, t.Any]"] ) -> float: ... @t.overload def mean_by( collection: t.Iterable[T], iteratee: t.Callable[[T, int, t.List[T]], "SupportsAdd[int, t.Any]"] ) -> float: ... @t.overload def mean_by( collection: t.Iterable[T], iteratee: t.Callable[[T, int], "SupportsAdd[int, t.Any]"] ) -> float: ... @t.overload def mean_by( collection: t.Iterable[T], iteratee: t.Callable[[T], "SupportsAdd[int, t.Any]"] ) -> float: ... @t.overload def mean_by( collection: t.Mapping[t.Any, "SupportsAdd[int, t.Any]"], iteratee: None = None ) -> float: ... @t.overload def mean_by(collection: t.Iterable["SupportsAdd[int, t.Any]"], iteratee: None = None) -> float: ...
[docs] def mean_by(collection, iteratee=None): """ Calculate arithmetic mean of each element in `collection`. If iteratee is passed, each element of `collection` is passed through an iteratee before the mean is computed. Args: collection: Collection to process. iteratee: Iteratee applied per iteration. Returns: Result of mean. Example: >>> mean_by([1, 2, 3, 4], lambda x: x**2) 7.5 .. versionadded:: 4.0.0 """ return sum_by(collection, iteratee) / len(collection)
[docs] def ceil(x: NumberT, precision: int = 0) -> float: """ Round number up to precision. Args: x: Number to round up. precision: Rounding precision. Defaults to ``0``. Returns: Number rounded up. Example: >>> ceil(3.275) == 4.0 True >>> ceil(3.215, 1) == 3.3 True >>> ceil(6.004, 2) == 6.01 True .. versionadded:: 3.3.0 """ return rounder(math.ceil, x, precision)
NumT = t.TypeVar("NumT", int, float, "Decimal") NumT2 = t.TypeVar("NumT2", int, float, "Decimal") NumT3 = t.TypeVar("NumT3", int, float, "Decimal")
[docs] def clamp(x: NumT, lower: NumT2, upper: t.Union[NumT3, None] = None) -> t.Union[NumT, NumT2, NumT3]: """ Clamps number within the inclusive lower and upper bounds. Args: x: Number to clamp. lower: Lower bound. upper: Upper bound Returns: number Example: >>> clamp(-10, -5, 5) -5 >>> clamp(10, -5, 5) 5 >>> clamp(10, 5) 5 >>> clamp(-10, 5) -10 .. versionadded:: 4.0.0 """ if upper is None: upper = lower # type: ignore lower = x # type: ignore if x < lower: x = lower # type: ignore elif x > upper: # type: ignore x = upper # type: ignore return x
[docs] def divide(dividend: t.Union[NumberT, None], divisor: t.Union[NumberT, None]) -> float: """ Divide two numbers. Args: dividend: The first number in a division. divisor: The second number in a division. Returns: Returns the quotient. Example: >>> divide(20, 5) 4.0 >>> divide(1.5, 3) 0.5 >>> divide(None, None) 1.0 >>> divide(5, None) 5.0 .. versionadded:: 4.0.0 """ return call_math_operator(dividend, divisor, operator.truediv, 1)
[docs] def floor(x: NumberT, precision: int = 0) -> float: """ Round number down to precision. Args: x: Number to round down. precision: Rounding precision. Defaults to ``0``. Returns: Number rounded down. Example: >>> floor(3.75) == 3.0 True >>> floor(3.215, 1) == 3.2 True >>> floor(0.046, 2) == 0.04 True .. versionadded:: 3.3.0 """ return rounder(math.floor, x, precision)
@t.overload def max_( collection: t.Mapping[t.Any, "SupportsRichComparisonT"], default: Unset = UNSET ) -> "SupportsRichComparisonT": ... @t.overload def max_( collection: t.Mapping[t.Any, "SupportsRichComparisonT"], default: T ) -> t.Union["SupportsRichComparisonT", T]: ... @t.overload def max_( collection: t.Iterable["SupportsRichComparisonT"], default: Unset = UNSET ) -> "SupportsRichComparisonT": ... @t.overload def max_( collection: t.Iterable["SupportsRichComparisonT"], default: T ) -> t.Union["SupportsRichComparisonT", T]: ...
[docs] def max_(collection, default=UNSET): """ Retrieves the maximum value of a `collection`. Args: collection: Collection to iterate over. default: Value to return if `collection` is empty. Returns: Maximum value. Example: >>> max_([1, 2, 3, 4]) 4 >>> max_([], default=-1) -1 .. versionadded:: 1.0.0 .. versionchanged:: 4.0.0 Moved iteratee iteratee support to :func:`max_by`. """ return max_by(collection, default=default)
@t.overload def max_by( collection: t.Mapping[t.Any, "SupportsRichComparisonT"], iteratee: None = None, default: Unset = UNSET, ) -> "SupportsRichComparisonT": ... @t.overload def max_by( collection: t.Mapping[t.Any, T2], iteratee: t.Callable[[T2], "SupportsRichComparisonT"], default: Unset = UNSET, ) -> T2: ... @t.overload def max_by( collection: t.Mapping[t.Any, T2], iteratee: t.Callable[[T2], "SupportsRichComparisonT"], *, default: T, ) -> t.Union[T2, T]: ... @t.overload def max_by( collection: t.Mapping[t.Any, "SupportsRichComparisonT"], iteratee: None = None, *, default: T ) -> t.Union["SupportsRichComparisonT", T]: ... @t.overload def max_by( collection: t.Iterable["SupportsRichComparisonT"], iteratee: None = None, default: Unset = UNSET ) -> "SupportsRichComparisonT": ... @t.overload def max_by( collection: t.Iterable[T2], iteratee: t.Callable[[T2], "SupportsRichComparisonT"], default: Unset = UNSET, ) -> T2: ... @t.overload def max_by( collection: t.Iterable[T2], iteratee: t.Callable[[T2], "SupportsRichComparisonT"], *, default: T ) -> t.Union[T2, T]: ... @t.overload def max_by( collection: t.Iterable["SupportsRichComparisonT"], iteratee: None = None, *, default: T ) -> t.Union["SupportsRichComparisonT", T]: ... @t.overload def max_by(collection: t.Iterable[T], iteratee: IterateeObjT, default: Unset = UNSET) -> T: ... @t.overload def max_by(collection: t.Iterable[T], iteratee: IterateeObjT, default: T2) -> t.Union[T, T2]: ...
[docs] def max_by(collection, iteratee=None, default=UNSET): """ Retrieves the maximum value of a `collection`. Args: collection: Collection to iterate over. iteratee: Iteratee applied per iteration. default: Value to return if `collection` is empty. Returns: Maximum value. Example: >>> max_by([1.0, 1.5, 1.8], math.floor) 1.0 >>> max_by([{"a": 1}, {"a": 2}, {"a": 3}], "a") {'a': 3} >>> max_by([], default=-1) -1 .. versionadded:: 4.0.0 """ if isinstance(collection, dict): collection = collection.values() return max(iterator_with_default(collection, default), key=pyd.iteratee(iteratee))
@t.overload def median( collection: t.Mapping[T, T2], iteratee: t.Callable[[T2, T, t.Dict[T, T2]], NumberT] ) -> t.Union[float, int]: ... @t.overload def median( collection: t.Mapping[T, T2], iteratee: t.Callable[[T2, T], NumberT] ) -> t.Union[float, int]: ... @t.overload def median( collection: t.Mapping[t.Any, T2], iteratee: t.Callable[[T2], NumberT] ) -> t.Union[float, int]: ... @t.overload def median( collection: t.Iterable[T], iteratee: t.Callable[[T, int, t.List[T]], NumberT] ) -> t.Union[float, int]: ... @t.overload def median( collection: t.Iterable[T], iteratee: t.Callable[[T, int], NumberT] ) -> t.Union[float, int]: ... @t.overload def median( collection: t.Iterable[T], iteratee: t.Callable[[T], NumberT] ) -> t.Union[float, int]: ... @t.overload def median(collection: t.Iterable[NumberT], iteratee: None = None) -> t.Union[float, int]: ...
[docs] def median(collection, iteratee=None): """ Calculate median of each element in `collection`. If iteratee is passed, each element of `collection` is passed through an iteratee before the median is computed. Args: collection: Collection to process. iteratee: Iteratee applied per iteration. Returns: Result of median. Example: >>> median([1, 2, 3, 4, 5]) 3 >>> median([1, 2, 3, 4]) 2.5 .. versionadded:: 2.1.0 """ length = len(collection) middle = (length + 1) / 2 collection = sorted(ret[0] for ret in iteriteratee(collection, iteratee)) if pyd.is_odd(length): result = collection[int(middle - 1)] else: left = int(middle - 1.5) right = int(middle - 0.5) result = (collection[left] + collection[right]) / 2 return result
@t.overload def min_( collection: t.Mapping[t.Any, "SupportsRichComparisonT"], default: Unset = UNSET ) -> "SupportsRichComparisonT": ... @t.overload def min_( collection: t.Mapping[t.Any, "SupportsRichComparisonT"], default: T ) -> t.Union["SupportsRichComparisonT", T]: ... @t.overload def min_( collection: t.Iterable["SupportsRichComparisonT"], default: Unset = UNSET ) -> "SupportsRichComparisonT": ... @t.overload def min_( collection: t.Iterable["SupportsRichComparisonT"], default: T ) -> t.Union["SupportsRichComparisonT", T]: ...
[docs] def min_(collection, default=UNSET): """ Retrieves the minimum value of a `collection`. Args: collection: Collection to iterate over. default: Value to return if `collection` is empty. Returns: Minimum value. Example: >>> min_([1, 2, 3, 4]) 1 >>> min_([], default=100) 100 .. versionadded:: 1.0.0 .. versionchanged:: 4.0.0 Moved iteratee iteratee support to :func:`min_by`. """ return min_by(collection, default=default)
@t.overload def min_by( collection: t.Mapping[t.Any, "SupportsRichComparisonT"], iteratee: None = None, default: Unset = UNSET, ) -> "SupportsRichComparisonT": ... @t.overload def min_by( collection: t.Mapping[t.Any, T2], iteratee: t.Callable[[T2], "SupportsRichComparisonT"], default: Unset = UNSET, ) -> T2: ... @t.overload def min_by( collection: t.Mapping[t.Any, T2], iteratee: t.Callable[[T2], "SupportsRichComparisonT"], *, default: T, ) -> t.Union[T2, T]: ... @t.overload def min_by( collection: t.Mapping[t.Any, "SupportsRichComparisonT"], iteratee: None = None, *, default: T ) -> t.Union["SupportsRichComparisonT", T]: ... @t.overload def min_by( collection: t.Iterable["SupportsRichComparisonT"], iteratee: None = None, default: Unset = UNSET ) -> "SupportsRichComparisonT": ... @t.overload def min_by( collection: t.Iterable[T2], iteratee: t.Callable[[T2], "SupportsRichComparisonT"], default: Unset = UNSET, ) -> T2: ... @t.overload def min_by( collection: t.Iterable[T2], iteratee: t.Callable[[T2], "SupportsRichComparisonT"], *, default: T ) -> t.Union[T2, T]: ... @t.overload def min_by( collection: t.Iterable["SupportsRichComparisonT"], iteratee: None = None, *, default: T ) -> t.Union["SupportsRichComparisonT", T]: ... @t.overload def min_by(collection: t.Iterable[T], iteratee: IterateeObjT, default: Unset = UNSET) -> T: ... @t.overload def min_by(collection: t.Iterable[T], iteratee: IterateeObjT, default: T2) -> t.Union[T, T2]: ...
[docs] def min_by(collection, iteratee=None, default=UNSET): """ Retrieves the minimum value of a `collection`. Args: collection: Collection to iterate over. iteratee: Iteratee applied per iteration. default: Value to return if `collection` is empty. Returns: Minimum value. Example: >>> min_by([1.8, 1.5, 1.0], math.floor) 1.8 >>> min_by([{"a": 1}, {"a": 2}, {"a": 3}], "a") {'a': 1} >>> min_by([], default=100) 100 .. versionadded:: 4.0.0 """ if isinstance(collection, dict): collection = collection.values() return min(iterator_with_default(collection, default), key=pyd.iteratee(iteratee))
[docs] def moving_mean(array: t.Sequence["SupportsAdd[int, t.Any]"], size: t.SupportsInt) -> t.List[float]: """ Calculate moving mean of each element of `array`. Args: array: List to process. size: Window size. Returns: Result of moving average. Example: >>> moving_mean(range(10), 1) [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0] >>> moving_mean(range(10), 5) [2.0, 3.0, 4.0, 5.0, 6.0, 7.0] >>> moving_mean(range(10), 10) [4.5] .. versionadded:: 2.1.0 .. versionchanged:: 4.0.0 Rename to ``moving_mean`` and remove ``moving_average`` and ``moving_avg`` aliases. """ result = [] size = int(size) for i in range(size - 1, len(array) + 1): window = array[i - size : i] if len(window) == size: result.append(mean(window)) return result
@t.overload def multiply(multiplier: SupportsMul[int, T2], multiplicand: None) -> T2: ... @t.overload def multiply(multiplier: None, multiplicand: SupportsMul[int, T2]) -> T2: ... @t.overload def multiply(multiplier: None, multiplicand: None) -> int: ... @t.overload def multiply(multiplier: SupportsMul[T, T2], multiplicand: T) -> T2: ... @t.overload def multiply(multiplier: T, multiplicand: SupportsMul[T, T2]) -> T2: ...
[docs] def multiply(multiplier, multiplicand): """ Multiply two numbers. Args: multiplier: The first number in a multiplication. multiplicand: The second number in a multiplication. Returns: Returns the product. Example: >>> multiply(4, 5) 20 >>> multiply(10, 4) 40 >>> multiply(None, 10) 10 >>> multiply(None, None) 1 .. versionadded:: 4.0.0 """ return call_math_operator(multiplier, multiplicand, operator.mul, 1)
@t.overload def power(x: int, n: int) -> t.Union[int, float]: ... @t.overload def power(x: float, n: t.Union[int, float]) -> float: ... @t.overload def power(x: t.List[int], n: int) -> t.List[t.Union[int, float]]: ... @t.overload def power(x: t.List[float], n: t.List[t.Union[int, float]]) -> t.List[float]: ...
[docs] def power(x, n): """ Calculate exponentiation of `x` raised to the `n` power. Args: x: Base number. n: Exponent. Returns: Result of calculation. Example: >>> power(5, 2) 25 >>> power(12.5, 3) 1953.125 .. versionadded:: 2.1.0 .. versionchanged:: 4.0.0 Removed alias ``pow_``. """ if pyd.is_number(x): result = pow(x, n) elif pyd.is_list(x): result = [pow(item, n) for item in x] else: result = None return result
@t.overload def round_(x: t.List[SupportsRound[NumberT]], precision: int = 0) -> t.List[float]: ... @t.overload def round_(x: SupportsRound[NumberT], precision: int = 0) -> float: ...
[docs] def round_(x, precision=0): """ Round number to precision. Args: x: Number to round. precision: Rounding precision. Defaults to ``0``. Returns: Rounded number. Example: >>> round_(3.275) == 3.0 True >>> round_(3.275, 1) == 3.3 True .. versionadded:: 2.1.0 .. versionchanged:: 4.0.0 Remove alias ``curve``. """ return rounder(round, x, precision)
@t.overload def scale(array: t.Iterable["Decimal"], maximum: "Decimal") -> t.List["Decimal"]: ... @t.overload def scale(array: t.Iterable[NumberNoDecimalT], maximum: NumberNoDecimalT) -> t.List[float]: ... @t.overload def scale(array: t.Iterable[NumberT], maximum: int = 1) -> t.List[float]: ...
[docs] def scale(array, maximum: NumberT = 1): """ Scale list of value to a maximum number. Args: array: Numbers to scale. maximum: Maximum scale value. Returns: Scaled numbers. Example: >>> scale([1, 2, 3, 4]) [0.25, 0.5, 0.75, 1.0] >>> scale([1, 2, 3, 4], 1) [0.25, 0.5, 0.75, 1.0] >>> scale([1, 2, 3, 4], 4) [1.0, 2.0, 3.0, 4.0] >>> scale([1, 2, 3, 4], 2) [0.5, 1.0, 1.5, 2.0] .. versionadded:: 2.1.0 """ array_max = max(array) factor = maximum / array_max return [item * factor for item in array]
@t.overload def slope( point1: t.Union[t.Tuple["Decimal", "Decimal"], t.List["Decimal"]], point2: t.Union[t.Tuple["Decimal", "Decimal"], t.List["Decimal"]], ) -> "Decimal": ... @t.overload def slope( point1: t.Union[t.Tuple[NumberNoDecimalT, NumberNoDecimalT], t.List[NumberNoDecimalT]], point2: t.Union[t.Tuple[NumberNoDecimalT, NumberNoDecimalT], t.List[NumberNoDecimalT]], ) -> float: ...
[docs] def slope(point1, point2): """ Calculate the slope between two points. Args: point1: X and Y coordinates of first point. point2: X and Y cooredinates of second point. Returns: Calculated slope. Example: >>> slope((1, 2), (4, 8)) 2.0 .. versionadded:: 2.1.0 """ x1, y1 = point1[0], point1[1] x2, y2 = point2[0], point2[1] if x1 == x2: result = INFINITY else: result = (y2 - y1) / (x2 - x1) return result
[docs] def std_deviation(array: t.List[NumberT]) -> float: """ Calculate standard deviation of list of numbers. Args: array: List to process. Returns: Calculated standard deviation. Example: >>> round(std_deviation([1, 18, 20, 4]), 2) == 8.35 True .. versionadded:: 2.1.0 .. versionchanged:: 4.0.0 Remove alias ``sigma``. """ return math.sqrt(variance(array))
@t.overload def subtract(minuend: "SupportsSub[T, T2]", subtrahend: T) -> T2: ... @t.overload def subtract(minuend: T, subtrahend: "SupportsSub[T, T2]") -> T2: ...
[docs] def subtract(minuend, subtrahend): """ Subtracts two numbers. Args: minuend: Value passed in by the user. subtrahend: Value passed in by the user. Returns: Result of the difference from the given values. Example: >>> subtract(10, 5) 5 >>> subtract(-10, 4) -14 >>> subtract(2, 0.5) 1.5 .. versionadded:: 4.0.0 """ return call_math_operator(minuend, subtrahend, operator.sub, 0)
[docs] def transpose(array: t.Iterable[t.Iterable[T]]) -> t.List[t.List[T]]: """ Transpose the elements of `array`. Args: array: List to process. Returns: Transposed list. Example: >>> transpose([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) [[1, 4, 7], [2, 5, 8], [3, 6, 9]] .. versionadded:: 2.1.0 """ trans: t.List[t.List[T]] = [] for y, row in iterator(array): for x, col in iterator(row): trans = pyd.set_(trans, [x, y], col) return trans
@t.overload def variance(array: t.Mapping[t.Any, "SupportsAdd[int, t.Any]"]) -> float: ... @t.overload def variance(array: t.Iterable["SupportsAdd[int, t.Any]"]) -> float: ...
[docs] def variance(array): """ Calculate the variance of the elements in `array`. Args: array: List to process. Returns: Calculated variance. Example: >>> variance([1, 18, 20, 4]) 69.6875 .. versionadded:: 2.1.0 """ avg = mean(array) def var(x): return power(x - avg, 2) return pyd._(array).map_(var).mean().value()
@t.overload def zscore( collection: t.Mapping[T, T2], iteratee: t.Callable[[T2, T, t.Dict[T, T2]], NumberT] ) -> t.List[float]: ... @t.overload def zscore( collection: t.Mapping[T, T2], iteratee: t.Callable[[T2, T], NumberT] ) -> t.List[float]: ... @t.overload def zscore( collection: t.Mapping[t.Any, T2], iteratee: t.Callable[[T2], NumberT] ) -> t.List[float]: ... @t.overload def zscore( collection: t.Iterable[T], iteratee: t.Callable[[T, int, t.List[T]], NumberT] ) -> t.List[float]: ... @t.overload def zscore(collection: t.Iterable[T], iteratee: t.Callable[[T, int], NumberT]) -> t.List[float]: ... @t.overload def zscore(collection: t.Iterable[T], iteratee: t.Callable[[T], NumberT]) -> t.List[float]: ... @t.overload def zscore(collection: t.Iterable[NumberT], iteratee: None = None) -> t.List[float]: ...
[docs] def zscore(collection, iteratee=None): """ Calculate the standard score assuming normal distribution. If iteratee is passed, each element of `collection` is passed through an iteratee before the standard score is computed. Args: collection: Collection to process. iteratee: Iteratee applied per iteration. Returns: Calculated standard score. Example: >>> results = zscore([1, 2, 3]) # [-1.224744871391589, 0.0, 1.224744871391589] .. versionadded:: 2.1.0 """ array = pyd.map_(collection, iteratee) avg = mean(array) sig = std_deviation(array) return [(item - avg) / sig for item in array]
# # Utility methods not a part of the main API # def call_math_operator(value1, value2, op, default): """Return the result of the math operation on the given values.""" if value1 is None: value1 = default if value2 is None: value2 = default if not pyd.is_number(value1): try: value1 = float(value1) except Exception: pass if not pyd.is_number(value2): try: value2 = float(value2) except Exception: pass return op(value1, value2) def rounder(func, x, precision): precision = pow(10, precision) def rounder_func(item): return func(item * precision) / precision result = None if pyd.is_number(x): result = rounder_func(x) elif pyd.is_iterable(x): try: result = [rounder_func(item) for item in x] except TypeError: pass return result