Сообщить об ошибке.

Класс NormalDist() модуля statistics в Python, распределение случайной величины

Создания нормальных распределений случайной величины

NormalDist - это инструмент для создания нормальных распределений случайной величины и управления ими. Это класс, который рассматривает среднее значение и стандартное отклонение измерений данных как единое целое.

Нормальные распределения возникают из центральной предельной теоремы и имеют широкий спектр применений в статистике. Смотрите ПРИМЕРЫ использования.

Синтаксис:

import statistics

# Новое в Python 3.8.
ndist = statistics.NormalDist(mu=0.0, sigma=1.0)

Параметры:

  • mu=0.0 - среднее арифметическое данных,
  • sigma=1.0 - среднее квадратическое отклонение данных.

Возвращаемое значение:

Описание:

Функция 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.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 задает интервал отсечения:

  • по умолчанию установлен, равным 4 для квартилей,
  • для децилей, необходимо установить 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'