Это связано с тем, что пакет statistics
пытается дать вам согласованные выходные данные в зависимости от типа numeri c, который вы передаете, поэтому он обрабатывает int
, float
, decimal.Decimal
, fractions.Fraction
как вы бы надеялись. К сожалению, типы numpy
плохо работают с иерархией типов python numeri c. Итак, мы можем взглянуть на исходный код (это версия Python, ваша среда выполнения, вероятно, использует быструю версию C, но они должны работать эквивалентно ...):
def mean(data):
"""Return the sample arithmetic mean of data.
>>> mean([1, 2, 3, 4, 4])
2.8
>>> from fractions import Fraction as F
>>> mean([F(3, 7), F(1, 21), F(5, 3), F(1, 3)])
Fraction(13, 21)
>>> from decimal import Decimal as D
>>> mean([D("0.5"), D("0.75"), D("0.625"), D("0.375")])
Decimal('0.5625')
If ``data`` is empty, StatisticsError will be raised.
"""
if iter(data) is data:
data = list(data)
n = len(data)
if n < 1:
raise StatisticsError('mean requires at least one data point')
T, total, count = _sum(data)
assert count == n
return _convert(total/n, T)
Итак, по сути, он использует sum
с распознаванием типов, которое возвращает тип, общее количество и количество. По сути, total/count
приводится к T
. Примечание:
In [28]: T, total, count = statistics._sum(np.array([1,2,3]))
In [29]: T, total, count
Out[29]: (numpy.int64, Fraction(6, 1), 3)
In [30]: total / count
Out[30]: Fraction(2, 1)
In [31]: T(total / count)
Out[31]: 2
Обратите внимание, все целые числа объектов, которые вы видите здесь, на самом деле являются numpy.int64
, а не ванильными int
объектами. Но почему этого не происходит, когда мы делаем statistics.mean([1,2,3,4])
? Ну, поскольку библиотека была построена с использованием обычных типов python numeri c, взглянув на функцию _convert
:
def _convert(value, T):
"""Convert value to given numeric type T."""
if type(value) is T:
# This covers the cases where T is Fraction, or where value is
# a NAN or INF (Decimal or float).
return value
if issubclass(T, int) and value.denominator != 1:
T = float
try:
# FIXME: what do we do if this overflows?
return T(value)
except TypeError:
if issubclass(T, Decimal):
return T(value.numerator)/T(value.denominator)
else:
raise
Вы заметите, это особые случаи: if issubclass(T, int) and value.denominator != 1
, т.е. у вас есть int
, а знаменатель не один, поэтому вам нужно число с плавающей запятой:
T = float
ОДНАКО:
In [36]: issubclass(np.int64, int)
Out[36]: False
Итак, T
это просто np.int64
, и:
In [37]: total / count
Out[37]: Fraction(2, 1)
In [38]: np.int64(total / count)
Out[38]: 2