NormalDist
- это инструмент для создания нормальных распределений случайной величины и управления ими. Это класс, который рассматривает среднее значение и стандартное отклонение измерений данных как единое целое.
Нормальные распределения возникают из центральной предельной теоремы и имеют широкий спектр применений в статистике. Смотрите ПРИМЕРЫ использования.
import statistics # Новое в Python 3.8. ndist = statistics.NormalDist(mu=0.0, sigma=1.0)
mu=0.0
- среднее арифметическое данных,sigma=1.0
- среднее квадратическое отклонение данных.NormalDist
.Функция NormalDist()
модуля statistics
возвращает новый объект NormalDist
где mu
представляет собой среднее арифметическое данных, а sigma
представляет собой среднее квадратическое отклонение.
Если аргумент sigma
отрицательна, то возникает ошибка StatisticsError
.
Экземпляры statistics.NormalDist()
поддерживают сложение, вычитание, умножение и деление на константу. Эти операции используются для перевода и масштабирования. Например:
>>> import statistics >>> temperature_february = statistics.NormalDist(5, 2.5) # Цельсий >>> temperature_february * (9/5) + 32 # Фаренгейт # NormalDist(mu=41.0, sigma=4.5)
Деление константы экземпляром NormalDist
не поддерживается, поскольку результат не будет нормально распределен.
Поскольку нормальные распределения возникают в результате аддитивного воздействия независимых переменных, можно складывать и вычитать две независимые нормально распределенные случайные величины, представленные как экземпляры NormalDist
. Например:
>>> birth_weights = NormalDist.from_samples([2.5, 3.1, 2.1, 2.4, 2.7, 3.5]) >>> drug_effects = NormalDist(0.4, 0.15) >>> combined = birth_weights + drug_effects >>> round(combined.mean, 1) # 3.1 >>> round(combined.stdev, 1) # 0.5
NormalDist
.ndist.mean
- среднее арифметическое нормального распределения,ndist.median
- медиана нормального распределения,ndist.mode
- наиболее распространенный элемент данных,ndist.stdev
- стандартное отклонение нормального распределения,ndist.variance
- дисперсия нормального распределения,ndist.classmethod
- создает экземпляр нормального распределения,ndist.samples()
- n
случайных выборок для данного среднего и стандартного отклонения,ndist.pdf()
- вычисляет относительную вероятность X
,ndist.cdf()
- вычисляет вероятность X
,ndist.inv_cdf()
- вычисляет обратную кумулятивную функцию распределения,ndist.overlap()
- измеряет соответствие между двумя нормальными распределениями вероятностей,ndist.quantiles()
- делит нормальное распределение на n непрерывных интервалов,ndist.zscore()
- вычисляет стандартную оценку.ndist.mean
:Атрибут ndist.mean
только для чтения - значение среднего арифметического нормального распределения.
ndist.median
:Атрибут ndist.median
только для чтения - значение медианы нормального распределения.
ndist.mode
:Атрибут ndist.mode
только для чтения - наиболее распространенный элемент в дискретных или номинальных данных.
ndist.stdev
:Атрибут ndist.stdev
только для чтения - значение стандартного отклонения нормального распределения.
ndist.variance
:Атрибут ndist.variance
только для чтения - значение дисперсии нормального распределения. Равно квадрату стандартного отклонения
statistics.NormalDist.from_samples(data)
:Метод класса statistics.NormalDist.from_samples()
создает экземпляр нормального распределения с параметрами mu
и sigma
, оцененными по данным с использованием statistics.fmean()
и statistics.stdev()
.
Данные data
могут быть любой последовательностью, поддерживающей итерацию и должны состоять из значений, которые можно преобразовать в тип float
.
Если последовательность числовых данных не содержат по крайней мере двух элементов, то вызывается исключение StatisticsError
. Следовательно, для оценки центрального значения требуется по крайней мере одна точка и по крайней мере две точки для оценки дисперсии.
ndist.samples(n, *, seed=None)
:Метод ndist.samples()
создает n
случайных выборок для данного среднего и стандартного отклонения. Возвращает список значений чисел с плавающей запятой.
Если задан аргумент seed
, то создает новый экземпляр базового генератора случайных чисел. Такое поведение полезно для создания воспроизводимых результатов даже в многопоточном контексте.
ndist.pdf(x)
:Метод ndist.pdf()
используя функцию плотности вероятности, вычисляет относительную вероятность того, что случайная величина X
будет близка к заданному значению x
. Математически это предел отношения P (x <= X < x+dx) / dx
, когда dx
приближается к нулю.
Относительная вероятность вычисляется как вероятность того, что выборка находится в узком диапазоне, деленная на ширину диапазона (отсюда и слово "плотность"). Поскольку вероятность относится к другим точкам, ее значение может быть больше 1.0.
ndist.cdf(x)
:Метод ndist.cdf()
используя кумулятивную функцию распределения, вычисляет вероятность того, что случайная величина X
будет меньше или равна x
. Математически она записывается P(X <= x)
.
ndist.inv_cdf(p)
:Метод ndist.inv_cdf()
вычисляет обратную кумулятивную функцию распределения, также известную как квантильная функция или функция процентной точки. Математически это записывается: x : P(X <= x) = p
.
Находит значение x
случайной величины X
таким, что вероятность того, что переменная будет меньше или равна этому значению, равна заданной вероятности p
.
ndist.overlap(other)
:Метод ndist.overlap()
измеряет соответствие между двумя нормальными распределениями вероятностей. Возвращает значение от 0,0 до 1,0, определяя область перекрытия для двух функций плотности вероятности.
ndist.quantiles(n=4)
:Метод ndist.quantiles()
делит нормальное распределение на n
непрерывных интервалов с равной вероятностью. Возвращает список из (n - 1)
элементов отсечения, разделяющих эти интервалы.
Аргумент n
задает интервал отсечения:
n
равным 10,n
равным 100 групп равного размера.ndist.zscore(x)
:Новое Python 3.9.
Метод ndist.zscore()
вычисляет стандартную оценку, описывающую x
как число стандартных отклонений выше или ниже среднего значения нормального распределения: (x - mean) / stdev
.
statistics.NormalDist()
:С классом statistics.NormalDist()
легко решает классические вероятностные задачи.
Например, учитывая исторические данные по экзаменам, показывающие, что баллы обычно распределяются со средним значением 1060 и стандартным отклонением 195, после округления до ближайшего целого числа, можно определить процент учащихся с результатами тестов от 1100 до 1200:
>>> import statistics >>> sat = statistics.NormalDist(1060, 195) >>> fraction = sat.cdf(1200 + 0.5) - sat.cdf(1100 - 0.5) >>> round(fraction * 100.0, 1) # 18.4
Найдем квартили и децили для результатов экзаменов:
>>> list(map(round, sat.quantiles())) # [928, 1060, 1192] >>> list(map(round, sat.quantiles(n=10))) # [810, 896, 958, 1011, 1060, 1109, 1162, 1224, 1310]
Чтобы оценить распределение для модели, которую нелегко решить аналитически, класс NormalDist()
может генерировать входные выборки для моделирования методом Монте-Карло:
>>> import statistics >>> def model(x, y, z): ... return (3*x + 7*x*y - 5*y) / (11 * z) ... >>> n = 100_000 >>> X = statistics.NormalDist(10, 2.5).samples(n, seed=3652260728) >>> Y = statistics.NormalDist(15, 1.75).samples(n, seed=4582495471) >>> Z = statistics.NormalDist(50, 1.25).samples(n, seed=6582483453) >>> statistics.quantiles(map(model, X, Y, Z)) # [1.4591308524824727, 1.8035946855390597, 2.175091447274739]
Нормальные распределения могут использоваться для аппроксимации биномиальных распределений, когда размер выборки велик и когда вероятность успешного испытания составляет около 50%.
Например, конференция с открытым исходным кодом насчитывает 750 участников и два зала вместимостью 500 человек. Будет проводится доклад о Python и еще один о Ruby. На предыдущих конференциях 65% участников предпочитали слушать выступления Python. Если предположить, что предпочтения населения не изменились, какова вероятность того, что зал с докладчиком о Python останется в пределах своей вместимости?
>>> n = 750 # Размер выборки
>>> p = 0.65 # предпочтение Python
>>> q = 1.0 - p # предпочтение Ruby
>>> k = 500 # Вместимость зала
>>> import statistics
# Аппроксимация с использованием
# кумулятивного нормального распределения
>>> from math import sqrt
>>> round(statistics.NormalDist(mu=n*p, sigma=sqrt(n*p*q)).cdf(k + 0.5), 4)
# 0.8402
# Решение с использованием
# кумулятивного биномиального распределения
>>> from math import comb, fsum
>>> round(fsum(comb(n, r) * p**r * q**(n-r) for r in range(k+1)), 4)
# 0.8402
# Аппроксимация с помощью
# имитационного моделирования
>>> from random import seed, choices
>>> seed(8675309)
>>> def trial():
... return choices(('Python', 'Ruby'), (p, q), k=n).count('Python')
>>> statistics.mean(trial() <= k for i in range(10_000))
# 0.8398
Нормальные распределения обычно возникают в задачах машинного обучения.
В Википедии есть хороший пример наивного байесовского классификатора. Задача состоит в том, чтобы предсказать пол человека по измерениям нормально распределенных признаков, включая рост, вес и размер стопы.
Нам дают обучающий набор данных с измерениями для восьми человек. Предполагается, что измерения распределены нормально, поэтому мы суммируем данные с помощью объекта statistics.NormalDist
:
>>> import statistics >>> height_male = statistics.NormalDist.from_samples([6, 5.92, 5.58, 5.92]) >>> height_female = statistics.NormalDist.from_samples([5, 5.5, 5.42, 5.75]) >>> weight_male = statistics.NormalDist.from_samples([180, 190, 170, 165]) >>> weight_female = statistics.NormalDist.from_samples([100, 150, 130, 150]) >>> foot_size_male = statistics.NormalDist.from_samples([12, 11, 12, 10]) >>> foot_size_female = statistics.NormalDist.from_samples([6, 8, 7, 9])
Далее сталкиваемся с новыми данными, при помощи которых требуется определить пол человеком:
>>> ht = 6.0 # рост >>> wt = 130 # вес >>> fs = 8 # размер ноги
Начиная с 50% априорной вероятности, вычисляем апостериорную как априорное время произведения вероятностей для измерений признаков с учетом пола:
>>> prior_male = 0.5 >>> prior_female = 0.5 >>> posterior_male = (prior_male * height_male.pdf(ht) * ... weight_male.pdf(wt) * foot_size_male.pdf(fs)) >>> posterior_female = (prior_female * height_female.pdf(ht) * ... weight_female.pdf(wt) * foot_size_female.pdf(fs))
Окончательное предсказание относится к самой большой задней части. Это известно как максимальное апостериорное или MAP:
>>> 'male' if posterior_male > posterior_female else 'female' # 'female'