Генерация случайных чисел по нормальному закону
Добрый день!
Может кто подскажет, как правильно задать интервал, из которого мне нужны случайные числа, заданные именно нормальным законом распределения?
Задаю нормальное распределение как random.normalvariate(mu, sigma), где mu — среднее значение, sigma — стандартное отклонение.
Мне нужно понять как задавать числа из интервала от 1 до 3.
Вообще, думала, что если мне нужны числа от 1 до 3, то mu = 2 (середина интервала) и sigma = 1 (отклонение от середины интервала). Но оказалось, что как-то не так. Потому что в таком случае мне программа выдаёт числа в основном, в этом промежутке, но некоторые генерируются и меньше 1, и больше 3. Какими должны быть mu и sigma?
Лучшие ответы ( 1 )
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:
Генерация случайных чисел по нормальному закону распределения
Как в C++ сгенерировать случайные числа по нормальному закону распределения? Есть ли какие-нибудь.
Генерация случайных величие по нормальному закону.
Подскажите пожалуйста как с помощью rnorm() генерировать 1024 случайных величин в интервале от.
Создание массива [n,m] случайных чисел, распределенных по нормальному закону
Как создать массива случайных чисел, распределенных по нормальному закону с нулевым мат.
Генерация случайных чисел по заданому закону роспределения и построение гистограммы
Помогите разобраться. Чесноговоря все вводил по розпечатке. Материться начинает уже в конце.
17 / 17 / 11
Регистрация: 17.03.2017
Сообщений: 109
Сообщение было отмечено Valenti93 как решение
Решение
я тестировал несколько способов, и один из нормальных является
round(random.normalvariate(2,0.7))
из-за более одинакового количества 1,2,3. Но из за того что я использовал round, нельзя считать это доконца правильным решением.
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
Помогаю со студенческими работами здесь
Генерация случайных чисел по закону Рэлея через мат. ожидание и дисперсию
Здравствуйте. Есть способ генерировать случайные числа по указанному закону через мат. ожидание и.
Генератор чисел распределенных по нормальному закону
Возникла проблема с созданием генератора случайных чисел распределенных по Гауссу, функция RandG.
Генератор случайных чисел подчиняется нормальному распределению, если N=600
Добрый день, постараюсь быть краток, завал с сессией, срочно нужно сделать лабы по вычеслительной.
Задача такое нужно построить случайных величин и генерация случайных чисел(ГСЧ
Народ помогите тут надо. Задание такое нужно построить случайных величин и генерация случайных.
Генерация случайных чисел и тестирование случайных последовательностей
Ребят, всем привет. Вопрос такой: Кто-нибудь может доступно объяснить тесты для случайных.
Сгенерировать последовательности случайных чисел, распределенных по экспоненциальному закону.
Ребят, помогите в делфи решить. Сгенерировать три последовательности по 30 случайных чисел. В.
Python, исследование данных и выборы: часть 2
Пост №2 для начинающих посвящен описательным статистикам, группированию данных и нормальному распределению. Все эти сведения заложат основу для дальнейшего анализа электоральных данных. Предыдущий пост см. здесь.
Описательные статистики
Описательные статистические величины, или статистики, — это числа, которые используются для обобщения и описания данных. В целях демонстрации того, что мы имеем в виду, посмотрим на столбец с данными об электорате Electorate. Он показывает суммарное число зарегистрированных избирателей в каждом избирательном округе:
def ex_1_6(): '''Число значений в поле "Электорат"''' return load_uk_scrubbed()['Electorate'].count()
Мы уже очистили столбец, отфильтровав пустые значения ( nan ) из набора данных, и поэтому предыдущий пример должен вернуть суммарное число избирательных округов.
Описательные статистики, так называемые сводные статистики, представляют собой разные подходы к измерению свойств последовательностей чисел. Они помогают охарактеризовать последовательность и способны выступать в качестве ориентира для дальнейшего анализа. Начнем с двух самых базовых статистик, которые мы можем вычислить из последовательности чисел — ее среднее значение и дисперсию (варианс).
Наиболее распространенный способ усреднить набор данных — взять его среднее значение. Среднее значение на самом деле представляет собой один из нескольких способов измерения центра распределения данных.
Среднее значение числового ряда вычисляется на Python следующим образом:
def mean(xs): '''Среднее значение числового ряда''' return sum(xs) / len(xs)
Мы можем воспользоваться нашей новой функцией mean для вычисления среднего числа избирателей в Великобритании:
def ex_1_7(): '''Вернуть среднее значение поля "Электорат"''' return mean( load_uk_scrubbed()['Electorate'] )
70149.94
На самом деле, библиотека pandas уже содержит функцию mean, которая гораздо эффективнее вычисляет среднее значение последовательности. В нашем случае ее можно применить следующим образом:
load_uk_scrubbed()['Electorate'].mean()
Медиана — это еще одна распространенная описательная статистика для измерения центра распределения последовательности. Если Вы упорядочили все данные от меньшего до наибольшего, то медиана — это значение, которое находится ровно по середине. Если в последовательности число точек данных четное, то медиана определяется, как полусумма двух срединных значений.
def median(xs): '''Медиана числового ряда''' n = len(xs) mid = n // 2 if n % 2 == 1: return sorted(xs)[mid] else: return mean( sorted(xs)[mid-1:][:2] )
Медианное значение электората Великобритании составляет:
def ex_1_8(): '''Вернуть медиану поля "Электорат"''' return median( load_uk_scrubbed()['Electorate'] )
70813.5
Библиотека pandas тоже располагает встроенной функцией для вычисления медианного значения, которая так и называется median .
Среднее арифметическое и медиана являются двумя альтернативными способами описания среднего значения последовательности, но сами по себе они мало что говорят о содержащихся в ней значениях. Например, если известно, что среднее последовательности из девяноста девяти значений равно 50, то мы почти ничего не скажем о том, какого рода значения последовательность содержит.
Она может содержать целые числа от одного до девяноста девяти либо сорок девять нулей и пятьдесят девяносто девяток, а может быть и так, что она девяносто восемь раз содержит отрицательную единицу и одно число 5048, или же вообще все значения могут быть равны 50.
Дисперсия (варианс) последовательности чисел показывает «разброс» данных вокруг среднего значения. К примеру, данные, приведенные выше, имели бы разную дисперсию. На языке математики дисперсия обозначается следующим образом:
где s 2 — это математический символ, который часто используют для обозначения дисперсии.
def variance(xs): '''Дисперсия (варианс) числового ряда, несмещенная дисперсия при n
Для вычисления квадрата выражения используется оператор языка Python возведения в степень ** .
Поскольку мы взяли средний квадрат отклонения, т.е. получили квадрат отклонения и затем его среднее, то единицы измерения дисперсии (варианса) тоже будут в квадрате, т.е. дисперсия электората Великобритании будет измеряться «людьми в квадрате». Несколько неестественно рассуждать об избирателях в таком виде. Единицу измерения можно привести к более естественному виду, снова обозначающему «людей», путем извлечения квадратного корня из дисперсии (варианса). В результате получим так называемое стандартное отклонение, или среднеквадратичное отклонение:
def standard_deviation(xs): '''Стандартное отклонение числового ряда''' return sp.sqrt( variance(xs) ) def ex_1_9(): '''Стандартное отклонение поля "Электорат"''' return standard_deviation( load_uk_scrubbed()['Electorate'] )
7672.77
В библиотеке pandas функции для вычисления дисперсии (варианса) и стандартного отклонения имплементированы соответственно, как var и std . При этом последняя по умолчанию вычисляет несмещенное значение, поэтому, чтобы получить тот же самый результат, нужно применить именованный аргумент ddof=0 , который сообщает, что требуется вычислить смещенное значение стандартного отклонения:
load_uk_scrubbed()['Electorate'].std( ddof=0 )
Медиана представляет собой один из способов вычислить срединное значение из списка, т.е. находящееся ровно по середине, дисперсия же предоставляет способ измерить разброс данных вокруг среднего значения. Если весь разброс данных представить на шкале от 0 до 1, то значение 0.5 будет медианным.
Для примера рассмотрим следующую ниже последовательность чисел:
[10 11 15 21 22.5 28 30]
Отсортированная последовательность состоит из семи чисел, поэтому медианой является число 21 четвертое в ряду. Его также называют 0.5-квантилем. Мы можем получить более полную картину последовательности чисел, взглянув на 0.0 (нулевой), 0.25, 0.5, 0.75 и 1.0 квантили. Все вместе эти цифры не только показывают медиану, но также обобщают диапазон данных и сообщат о характере распределения чисел внутри него. Они иногда упоминаются в связи с пятичисловой сводкой.
Один из способов составления пятичисловой сводки для данных об электорате Великобритании показан ниже. Квантили можно вычислить непосредственно в pandas при помощи функции quantile . Последовательность требующихся квантилей передается в виде списка.
def ex_1_10(): '''Вычислить квантили: возвращает значение в последовательности xs, соответствующее p-ому проценту''' q = [0, 1/4, 1/2, 3/4, 1] return load_uk_scrubbed()['Electorate'].quantile(q=q)
0.00 21780.00 0.25 65929.25 0.50 70813.50 0.75 74948.50 1.00 109922.00 Name: Electorate, dtype: float64
Когда квантили делят диапазон на четыре равных диапазона, как показано выше, то они называются квартилями. Разница между нижним (0.25) и верхним (0.75) квартилями называется межквартильным размахом, или иногда сокращенно МКР. Аналогично дисперсии (варианса) вокруг среднего значения, межквартильный размах измеряет разброс данных вокруг медианы.
Группирование данных в корзины
В целях развития интуитивного понимания в отношении того, что именно все эти расчеты разброса значений измеряют, мы можем применить метод под названием группировка в частотные корзины (binning). Когда данные имеют непрерывный характер, использование специального словаря для подсчета частот Counter (подобно тому, как он использовался при подсчете количества пустых значений в наборе данных об электорате) становится нецелесообразным, поскольку никакие два значения не могут быть одинаковыми. Между тем, общее представление о структуре данных можно все-равно получить, сгруппировав для этого данные в частотные корзины (bins).
Процедура образования корзин заключается в разбиении диапазона значений на ряд последовательных, равноразмерных и меньших интервалов. Каждое значение в исходном ряду попадает строго в одну корзину. Подсчитав количества точек, попадающих в каждую корзину, мы можем получить представление о разбросе данных:

На приведенном выше рисунке показано 15 значений x, разбитых на 5 равноразмерных корзин. Подсчитав количество точек, попадающих в каждую корзину, мы можем четко увидеть, что большинство точек попадают в корзину по середине, а меньшинство — в корзины по краям. Следующая ниже функция Python nbin позволяет добиться того же самого результата:
def nbin(n, xs): '''Разбивка данных на частотные корзины''' min_x, max_x = min(xs), max(xs) range_x = max_x - min_x fn = lambda x: min( int((abs(x) - min_x) / range_x * n), n-1 ) return map(fn, xs)
Например, мы можем разбить диапазон 0-14 на 5 корзин следующим образом:
list( nbin(5, range(15)) )
[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4]
После того, как мы разбили значения на корзины, мы можем в очередной раз воспользоваться словарем Counter , чтобы подсчитать количество точек в каждой корзине. В следующем ниже примере мы воспользуемся этим словарем для разбиения данных об электорате Великобритании на пять корзин:
def ex_1_11(): '''Разбиmь электорат Великобритании на 5 корзин''' series = load_uk_scrubbed()['Electorate'] return Counter( nbin(5, series) )
Counter()
Количество точек в крайних корзинах (0 и 4) значительно ниже, чем в корзинах в середине — количества, судя по всему, растут по направлению к медиане, а затем снова снижаются. В следующем разделе мы займемся визуализацией формы этих количеств.
Гистограммы
Гистограмма — это один из способов визуализации распределения одной последовательности значений. Гистограммы попросту берут непрерывное распределение, разбивают его на корзины, и изображают частоты точек, попадающих в каждую корзину, в виде столбцов. Высота каждого столбца гистограммы показывает количество точек данных, которые содержатся в этой корзине.
Мы уже увидели, каким образом можно выполнить разбиение данных на корзины самостоятельно, однако в библиотеке pandas уже содержится функция hist , которая разбивает данные и визуализирует их в виде гистограммы.
def ex_1_12(): '''Построить гистограмму частотных корзин электората Великобритании''' load_uk_scrubbed()['Electorate'].hist() plt.xlabel('Электорат Великобритании') plt.ylabel('Частота') plt.show()
Приведенный выше пример сгенерирует следующий ниже график:

Число корзин, на которые данные разбиваются, можно сконфигурировать, передав в функцию при построении гистограммы именованный аргумент bins :
def ex_1_13(): '''Построить гистограмму частотных корзин электората Великобритании с 200 корзинами''' load_uk_scrubbed()['Electorate'].hist(bins=200) plt.xlabel('Электорат Великобритании') plt.ylabel('Частота') plt.show()
Приведенный выше график показывает единственный высокий пик, однако он выражает форму данных довольно грубо. Следующий ниже график показывает мелкие детали, но величина столбцов делает неясной форму распределения, в особенности в хвостах:

При выборе количества корзин для представления данных следует найти точку равновесия — с малым количеством корзин форма данных будет представлена лишь приблизительно, а слишком большое их число приведет к тому, что шумовые признаки могут заслонить лежащую в основании структуру.
def ex_1_14(): '''Построить гистограмму частотных корзин электората Великобритании с 20 корзинами''' load_uk_scrubbed()['Electorate'].hist(bins=20) plt.xlabel('Электорат Великобритании') plt.ylabel('Частота') plt.show()
Ниже показана гистограмма теперь уже из 20 корзин:

Окончательный график, состоящий из 20 корзин, судя по всему, пока лучше всего представляет эти данные.
Наряду со средним значением и медианой, есть еще один способ измерить среднюю величину последовательности. Это мода. Мода — это значение, встречающееся в последовательности наиболее часто. Она определена исключительно только для последовательностей, имеющих по меньшей мере одно дублирующее значение; во многих статистических распределениях это не так, и поэтому для них мода не определена. Тем не менее, пик гистограммы часто называют модой, поскольку он соответствует наиболее распространенной корзине.
Из графика ясно видно, что распределение вполне симметрично относительно моды, и его значения резко падают по обе стороны от нее вдоль тонких хвостов. Эти данные приближенно подчиняются нормальному распределению.
Нормальное распределение
Гистограмма дает приблизительное представление о том, каким образом данные распределены по всему диапазону, и является визуальным средством, которое позволяет квалифицировать данные как относящиеся к одному из немногих популярных распределений. В анализе данных многие распределения встречаются часто, но ни одно не встречается также часто, как нормальное распределение, именуемое также гауссовым распределением.
Распределение названо нормальным распределением из-за того, что оно очень часто встречается в природе. Галилей заметил, что ошибки в его астрономических измерениях подчинялись распределению, где малые отклонения от среднего значения встречались чаще, чем большие. Вклад великого математика Гаусса в описание математической формы этих ошибок привел к тому, что это распределение стали называть в его честь распределением Гаусса.
Любое распределение похоже на алгоритм сжатия: оно позволяет очень эффективно резюмировать потенциально большой объем данных. Нормальное распределение требует только два параметра, исходя из которых можно аппроксимировать остальные данные. Это среднее значение и стандартное отклонение.
Центральная предельная теорема
Высокая встречаемость нормального распределения отчасти объясняется центральной предельной теоремой. Дело в том, что значения, полученные из разнообразных статистических распределений, при определенных обстоятельствах имеют тенденцию сходиться к нормальному распределению, и мы это покажем далее.
В программировании типичным распределением является равномерное распределение. Оно представлено распределением чисел, генерируемых функцией библиотеки scipy stats.uniform.rvs : в справедливом генераторе случайных чисел все числа имеют равные шансы быть сгенерированными. Мы можем увидеть это на гистограмме, многократно генерируя серию случайных чисел между 0 и 1 и затем построив график с результатами.
def ex_1_15(): '''Показать гистограмму равномерного распределения синтетического набора данных''' xs = stats.uniform.rvs(0, 1, 10000) pd.Series(xs).hist(bins=20) plt.xlabel('Равномерное распределение') plt.ylabel('Частота') plt.show()
Обратите внимание, что в этом примере мы впервые использовали тип Series библиотеки pandas для числового ряда данных.
Приведенный выше пример создаст следующую гистограмму:

Каждый столбец гистограммы имеет примерно одинаковую высоту, что соответствует равновероятности генерирования числа, которое попадает в каждую корзину. Столбцы имеют не совсем одинаковую высоту, потому что равномерное распределение описывает теоретический результат, который наша случайная выборка не может отразить в точности. Раздел инференциальной статистики, посвященный проверке статистических гипотез, изучает способы точной количественной оценки расхождения между теорией и практикой, чтобы определить, являются ли расхождения достаточно большими, чтобы обратить на это внимание. В данном случае они таковыми не являются.
Если напротив сгенерировать гистограмму средних значений последовательностей чисел, то в результате получится распределение, которое выглядит совсем непохоже.
def bootstrap(xs, n, replace=True): '''Вернуть список массивов меньших размеров по n элементов каждый''' return np.random.choice(xs, (len(xs), n), replace=replace) def ex_1_16(): '''Построить гистограмму средних значений''' xs = stats.uniform.rvs(loc=0, scale=1, size=10000) pd.Series( map(sp.mean, bootstrap(xs, 10)) ).hist(bins=20) plt.xlabel('Распределение средних значений') plt.ylabel('Частота') plt.show()
Приведенный выше пример сгенерирует результат, аналогичный следующей ниже гистограмме:

Хотя величина среднего значения близкая к 0 или 1 не является невозможной, она является чрезвычайно невероятной и становится менее вероятной по мере роста числа усредненных чисел и числа выборочных средних. Фактически, на выходе получается результат очень близкий к нормальному распределению.
Этот результат, когда средний эффект множества мелких случайных колебаний в итоге приводит к нормальному распределению, называется центральной предельной теоремой, иногда сокращенно ЦПТ, и играет важную роль для объяснения, почему нормальное распределение встречается так часто в природных явлениях.
До 20-ого века самого термина еще не существовало, хотя этот эффект был зафиксирован еще в 1733 г. французским математиком Абрахамом де Mуавром, который использовал нормальное распределение, чтобы аппроксимировать число орлов в результате бросания уравновешенной монеты. Исход бросков монеты лучше всего моделировать при помощи биномиального распределения. В отличие от центральной предельной теоремы, которая позволяет получать выборки из приближенно нормального распределения, библиотека scipy содержит функции для эффективного генерирования выборок из самых разнообразных статистических распределений, включая нормальное:
def ex_1_17(): '''Показать гистограмму нормального распределения синтетического набора данных''' xs = stats.norm.rvs(loc=0, scale=1, size=10000) pd.Series(xs).hist(bins=20) plt.xlabel('Нормальное распределение') plt.ylabel('Частота') plt.show()
Отметим, что в функции sp.random.normal параметр loc – это среднее значение, scale – дисперсия и size – размер выборки. Приведенный выше пример сгенерирует следующую гистограмму нормального распределения:

По умолчанию среднее значение и стандартное отклонение для получения нормального распределения равны соответственно 0 и 1.
Примеры исходного кода для этого поста находятся в моем репо на Github. Все исходные данные взяты в репозитории автора книги.
Следующая часть, часть 3, серии постов «Python, исследование данных и выборы» посвящена генерированию распределений, их свойствам, а также графикам для их сопоставительного анализа
Python, исследование данных и выборы: часть 3
Пост №3 для начинающих посвящен генерированию распределений, их свойствам, а также графикам для их сопоставительного анализа. Предыдущий пост см. здесь.
Булочник и Пуанкаре
Существует легенда, почти наверняка апокрифическая, которая дает возможность детальнее рассмотреть вопрос о том, каким образом центральная предельная теорема позволяет рассуждать о принципе формирования статистических распределений. Она касается прославленного французского эрудита XIX-ого века Анри Пуанкаре, который, как гласит легенда, в течение одного года каждый день занимался тем, что взвешивал свежую буханку хлеба.
В те времена хлебопекарное ремесло регламентировалось государством, и Пуанкаре обнаружил, что, хотя результаты взвешивания буханок хлеба подчинялись нормальному распределению, пик находился не на публично афишируемом 1 кг, а на 950 г. Он сообщил властям о булочнике, у которого он регулярно покупал хлеб, и тот был оштрафован. Такова легенда ;-).
В следующем году Пуанкаре продолжил взвешивать буханки хлеба того же булочника. Он обнаружил, что среднее значение теперь было равно 1 кг, но это распределение больше не было симметричным вокруг среднего значения. Теперь оно было смещено вправо. А это соответствовало тому, что булочник теперь давал Пуанкаре только самые тяжелые из своих буханок хлеба. Пуанкаре снова сообщил о булочнике властям, и булочник был оштрафован во второй раз.
Было ли это на самом деле или нет здесь не суть важно; этот пример всего лишь служит для того, чтобы проиллюстрировать ключевой момент — статистическое распределение последовательности чисел может сообщить нам нечто важное о процессе, который ее создал.
Генерирование распределений
В целях развития нашего интуитивного понимания относительно нормального распределения и дисперсии, давайте смоделируем честного и нечестного булочников, и для этого воспользуемся функцией генерирования нормально распределенных случайных величин stats.norm.rvs. (rvs от англ. normal variates, т.е. нормально-распределенные случайные величины). Честного булочника можно смоделировать в виде нормального распределения со средним значением 1000, что соответствует справедливой буханке хлеба весом 1 кг. При этом мы допустим наличие дисперсии в процессе выпекания, которая приводит к стандартному отклонению в 30г.
def honest_baker(mu, sigma): '''Модель честного булочника''' return pd.Series( stats.norm.rvs(loc, scale, size=10000) ) def ex_1_18(): '''Смоделировать честного булочника на гистограмме''' honest_baker(1000, 30).hist(bins=25) plt.xlabel('Честный булочник') plt.ylabel('Частота') plt.show()
Приведенный выше пример построит гистограмму, аналогичную следующей:

Теперь смоделируем булочника, который продает только самые тяжелые буханки хлеба. Мы разобьем последовательность на группы по тринадцать элементов (на «чертовы дюжины») и отберем максимальное значение в каждой:
def dishonest_baker(mu, sigma): '''Модель нечестного булочника''' xs = stats.norm.rvs(loc, scale, size=10000) return pd.Series( map(max, bootstrap(xs, 13)) ) def ex_1_19(): '''Смоделировать нечестного булочника на гистограмме''' dishonest_baker(950, 30).hist(bins=25) plt.xlabel('Нечестный булочник') plt.ylabel('Частота') plt.show()
Приведенный выше пример создаст гистограмму, аналогичную следующей:

Совершенно очевидно, что эта гистограмма выглядит не совсем так, как другие, которые мы видели. Среднее значение по-прежнему равно 1 кг, но разброс значений вокруг среднего больше не является симметричным. Мы говорим, что эта гистограмма показывает смещенное нормальное распределение.
Асимметрия
Асимметрией называется смещение распределения относительно ее моды. Отрицательная асимметрия, или левое смещение кривой, указывает на то, что площадь под графиком больше на левой стороне моды. Положительная асимметрия, или правое смещение кривой, указывает на то, что площадь под графиком больше на правой стороне моды.

Библиотека pandas располагает функцией skew для измерения асимметрии:
def ex_1_20(): '''Получить коэффициент асимметрии нормального распределения''' s = dishonest_baker(950, 30) return
Приведенный выше пример показывает, что коэффициент асимметрии в выпечке от нечестного булочника составляет порядка 0.4. Этот коэффициент количественно определяет степень скошенности, которая видна на гистограмме.
Графики нормального распределения
Ранее в этой серии постов мы познакомились с квантилями как средством описания статистического распределения данных. Напомним, что функция quantile принимает число между 0 и 1 и возвращает значение последовательности в этой точке. 0.5-квантиль соответствует значению медианы.
Изображение квантилей данных относительно квантилей нормального распределения позволяет увидеть, каким образом наши измеренные данные соотносятся с теоретическим распределением. Подобные графики называются квантильными графиками, или диаграммами квантиль-квантиль, графиками Q-Q, от англ. Q-Q plot. Они предоставляют быстрый и интуитивно понятный способ определить степень нормальности статистического распределения. Для данных, которые близки к нормальному распределению, квантильный график покажет прямую линию. Отклонения от прямой линии показывают, каким образом данные отклоняются от идеализированного нормального распределения.
Теперь построим квантильные графики для честного и нечестного булочников. Функция qqplot принимает список точек данных и формирует график выборочных квантилей, отображаемых относительно квантилей из теоретического нормального распределения:
def qqplot( xs ): '''Квантильный график (график квантиль-квантиль, Q-Q plot)''' d = <0:sorted(stats.norm.rvs(loc=0, scale=1, size=len(xs))), 1:sorted(xs)>pd.DataFrame(d).plot.scatter(0, 1, s=5, grid=True) df.plot.scatter(0, 1, s=5, grid=True) plt.xlabel('Квантили теоретического нормального распределения') plt.ylabel('Квантили данных') plt.title ('Квантильный график', fontweight='semibold') def ex_1_21(): '''Показать квантильные графики для честного и нечестного булочников''' qqplot( honest_baker(1000, 30) ) plt.show() qqplot( dishonest_baker(950, 30) ) plt.show()
Приведенный выше пример создаст следующие ниже графики:


Выше показан квантильный график для честного булочника. Далее идет квантильный график для нечестного булочника:
Тот факт, что линия имеет изогнутую форму, показывает, что данные положительно асимметричны; наклон в другую сторону будет означать отрицательную асимметрию. Квантильный график в сущности позволяет легко различить целый ряд отклонений от стандартного нормального распределения, как показано на следующем ниже рисунке:

Надписи: нормально распределенные, тяжелые хвосты, легкие хвосты, скошенность влево, скошенность вправо, раздельные кластеры
Квантильные графики сопоставляют статистическое распределение честного и нечестного булочника с теоретическим нормальным распределением. В следующем разделе мы сравним несколько альтернативных способов визуального сопоставления двух (или более) измеренных последовательностей значений.
Технические приемы сопоставительной визуализации
Квантильные графики дают замечательную возможность сопоставить измеренное эмпирическое (выборочное) распределение с теоретическим нормальным распределением. Однако если мы хотим сопоставить друг другу два или более эмпирических распределения, то графики нормального распределения для этого не подойдут. Впрочем, у нас есть несколько других вариантов, как показано в следующих двух разделах.
Коробчатые диаграммы
Коробчатые диаграммы, или диаграммы типа «ящик с усами», — это способ визуализации таких описательных статистик, как медиана и дисперсия. Мы можем сгенерировать их с помощью следующего исходного кода:
def ex_1_22(): '''Показать коробчатую диаграмму с данными честного и нечестного булочников''' d = pd.DataFrame(d).boxplot(sym='o', whis=1.95, showmeans=True) plt.ylabel('Вес буханки (гр.)') plt.show()
Этот пример создаст следующую диаграмму:

Ящики в центре диаграммы представляют интерквартильный размах. Линия поперек ящика — это медиана. Большая точка — это среднее. Для честного булочника линия медианы проходит через центр окружности, показывая, что среднее и медиана примерно одинаковые. Для нечестного булочника среднее отодвинуто от медианы, что указывает на смещение.
Усы показывают на диапазон данных. Выбросы представлены полыми кругами. Всего одна диаграмма позволяет яснее увидеть расхождение между двумя статистическими распределениями, чем рассматривать их отдельно на гистограмме или квантильном графике.
Интегральные функции распределения
Интегральные функции распределения (ИФР), также именуемые кумулятивными функциями распределения, от англ. Cumulative Distribution Function (CDF), описывают вероятность, что значение, взятое из распределения, будет меньше x. Как и все распределения вероятностей, их значения лежат в диапазоне между 0 и 1, где 0 — это невозможность, а 1 — полная определенность. Например, представьте, что я собираюсь бросить шестигранный кубик. Какова вероятность, что выпадет значение меньше 6?
Для уравновешенного кубика вероятность выпадения пятерки или меньшего значения равна 5/6. И наоборот, вероятность, что выпадет единица, равна всего 1/6. Тройка или меньше соответствуют равным шансам — то есть вероятности 50%.
ИФР выпадения чисел на кубике следует той же схеме, что и все ИФР — для чисел на нижнем краю диапазона ИФР близка к нулю, что соответствует низкой вероятности выбора чисел в этом диапазоне или ниже. На верхнем краю диапазона ИФР близка к единице, поскольку большинство значений, взятых из последовательности, будет ниже.
ИФР и квантили тесно друг с другом связаны — ИФР является инверсией квантильной функции. Если 0.5-квантиль соответствует значению 1000, тогда ИФР для 1000 составляет 0.5.
Подобно тому, как функция pandas quantile позволяет нам отбирать значения из распределения в конкретных точках, эмпирическая ИФР empirical_cdf позволяет нам внести значение из последовательности и вернуть значение в диапазоне между 0 и 1. Это функция более высокого порядка, т.е. она принимает значение (в данном случае последовательность значений) и возвращает функцию, которую потом можно вызывать, сколько угодно, с различными значениями на входе, и возвращая ИФР для каждого из них.
Функции более высокого порядка — это функции, которые принимают или возвращают функции.
Построим график ИФР одновременно для честного и нечестного булочников. Для этих целей можно воспользоваться функцией библиотеки pandas построения двумерного графика plot для визуализации ИФР, изобразив на графике исходные данные — то есть выборки из распределений честного и нечестного булочников — в сопоставлении с вероятностями, вычисленными относительно эмпирической ИФР. Функция plot ожидает, что значения x и значения y будут переданы в виде двух раздельных последовательностей значений. Для этих целей мы воспользуемся конструктором кадра данных pandas DataFrame .
Чтобы изобразить оба распределения на одном графике, мы должны передать функции plot несколько серий. Для многих своих графиков pandas предоставляет функции, которые позволяют добавлять дополнительные серии. В случае с функцией plot мы можем присвоить указатель на создаваемый график, присвоив временной переменной ( ax ) результат первого вызова функции plot , и затем при повторных вызовах указывать эту переменную в именованном аргументе функции ( ax=ax ). Можно также передать необязательную метку серии. Мы выполним это в следующем ниже примере, чтобы на готовом графике отличить две серии друг от друга. Сначала определим универсальную функцию построения эмпирической ИФР против теоретической, которая получает на вход кортеж из двух серий ( tp[1] и tp[3] ) и их названий и метки осей, и затем вызовем ее:
def empirical_cdf(x): '''Вернуть эмпирическую ИФР для x''' sx = sorted(x) return pd.DataFrame( ) def ex_1_23(): '''Показать графики эмпирической ИФР честного булочника в сопоставлении с нечестным''' df = empirical_cdf(honest_baker(1000, 30)) df2 = empirical_cdf(dishonest_baker(950, 30)) ax = df.plot(0, 1, label='Честный булочник') df2.plot(0, 1, label='Нечестный булочник', grid=True, ax=ax) plt.xlabel('Вес буханки') plt.ylabel('Вероятность') plt.legend(loc='best') plt.show()
Приведенный выше пример сгенерирует следующий график:

Несмотря на то, что этот график выглядит совсем по-другому, он в сущности показывает ту же самую информацию, что и коробчатая диаграмма. Мы видим, что две линии пересекаются примерно в медиане 0.5, соответствующей 1000 гр. Линия нечестного булочника обрезается в нижнем хвосте и удлиняется на верхнем хвосте, что соответствует асимметричному распределению.
Примеры исходного кода для этого поста находятся в моем репо на Github. Все исходные данные взяты в репозитории автора книги.
Следующая часть, часть 4, серии постов «Python, исследование данных и выборы» посвящена техническим приемам визуализации данных.
Нормальное распределение
Вот так можно сгенерировать выборку из нормально распределённой случайной величины с параметрами $\mu=2.0$ и $\sigma=0.5$:
In [2]:mu = 2.0 sigma = 0.5 # зададим нормально распределенную случайную величину norm_rv = sts.norm(loc=mu, scale=sigma) # сгенерируем 10 значений norm_rv.rvs(size=10)Out[2]:array([ 2.42471807, 2.89001427, 1.5406754 , 2.218372 , 2.48622369, 2.82460422, 2.06469003, 2.46941758, 1.7389734 , 1.17062459])Параметр loc задаёт $\mu$, scale — среднеквадратичное отклонение $\sigma$, size — размер выборки. Имя параметра size при вызове функции rvs можно не писать.
Следующая функция возвращает значение функции распределения нормальной случайной величины в точке, соответствующей её аргументу:
In [3]:norm_rv.cdf(3)Out[3]:0.97724986805182079Построим график функции распределения:
In [4]:x = np.linspace(0,4,100) cdf = norm_rv.cdf(x) # функция может принимать и вектор (x) plt.plot(x, cdf) plt.ylabel('$F(x)$') plt.xlabel('$x$')Out[4]:А так можно вычислить значение функции плотности вероятности нормального распределения в заданной точке:
In [5]:norm_rv.pdf(3)Out[5]:0.10798193302637613Построим график функции плотности вероятности:
In [6]:x = np.linspace(0,4,100) pdf = norm_rv.pdf(x) plt.plot(x, pdf) plt.ylabel('$f(x)$') plt.xlabel('$x$')Out[6]:Равномерное распределение на отрезке
Вот так можно сгенерировать выборку из случайной величины, имеющей равномерное распределение на отрезке $[a,b]$:
In [7]:a = 1 b = 4 # обратите внимание, что в этой функции задается левая граница и масштаб, а не левая и правая границы: uniform_rv = sts.uniform(a, b-a) uniform_rv.rvs(10)Out[7]:array([ 2.90068986, 1.30900927, 2.61667386, 1.82853085, 1.11278354, 1.67101276, 1.48848226, 1.74478797, 1.5155652 , 2.54059151])А так — вычислять значения функций распределения и плотностей:
In [8]:x = np.linspace(0,5,100) cdf = uniform_rv.cdf(x) plt.plot(x, cdf) plt.ylabel('$F(x)$') plt.xlabel('$x$')Out[8]:In [9]:x = np.linspace(0,5,1000) pdf = uniform_rv.pdf(x) plt.plot(x, pdf) plt.ylabel('$f(x)$') plt.xlabel('$x$')Out[9]:Распределение Бернулли
Генерация выборок из распределения Бернулли с заданным параметром $p$:
In [10]:bernoulli_rv = sts.bernoulli(0.7) bernoulli_rv.rvs(10)Out[10]:array([1, 1, 1, 1, 0, 0, 1, 1, 1, 1])Биномиальное распределение
Генерация выборок из биномиального распределения:
In [11]:binomial_rv = sts.binom(20, 0.7) binomial_rv.rvs(10)Out[11]:array([13, 11, 13, 15, 13, 14, 12, 16, 14, 16])Первый аргумент функции binom — значение параметра $n$, второй — параметра $p$.
In [12]:x = np.linspace(0,20,21) cdf = binomial_rv.cdf(x) plt.step(x, cdf) plt.ylabel('$F(x)$') plt.xlabel('$x$')Out[12]:Функция вероятности pmf для дискретных случайных величин заменяет функцию плотности pdf :
In [13]:x = np.linspace(0,20,21) pmf = binomial_rv.pmf(x) plt.plot(x, pmf, 'o') plt.ylabel('$P(X=x)$') plt.xlabel('$x$')Out[13]:Посмотрим, как ведут себя биномиально распределенные величины при разных значениях параметров:
In [14]:x = np.linspace(0,45,46) for N in [20, 30]: for p in [0.2, 0.7]: rv = sts.binom(N, p) cdf = rv.cdf(x) plt.step(x, cdf, label="$N=%s, p=%s$" % (N,p)) plt.legend() plt.title("CDF (binomial)") plt.ylabel('$F(X)$') plt.xlabel('$x$')Out[14]:In [15]:x = np.linspace(0,45,46) symbols = iter(['o', 's', '^', '+']) for N in [20, 30]: for p in [0.2, 0.8]: rv = sts.binom(N, p) pmf = rv.pmf(x) plt.plot(x, pmf, next(symbols), label="$N=%s, p=%s$" % (N,p)) plt.legend() plt.title("PMF (binomial)") plt.ylabel('$P(X=x)$') plt.xlabel('$x$')Out[15]:Распределение Пуассона
Генерация выборок из распределения Пуассона с параметром $\lambda$:
In [16]:poisson_rv = sts.poisson(5) poisson_rv.rvs(10)Out[16]:array([ 6, 10, 4, 4, 4, 3, 8, 4, 3, 6])In [17]:x = np.linspace(0,30,31) for l in [1, 5, 10, 15]: rv = sts.poisson(l) cdf = rv.cdf(x) plt.step(x, cdf, label="$\lambda=%s$" % l) plt.legend() plt.title("CDF (poisson)") plt.ylabel('$F(x)$') plt.xlabel('$x$')Out[17]:In [18]:x = np.linspace(0,30,31) symbols = iter(['o', 's', '^', '+']) for l in [1, 5, 10, 15]: rv = sts.poisson(l) pmf = rv.pmf(x) plt.plot(x, pmf, next(symbols), label="$\lambda=%s$" % l) plt.legend() plt.title("PMF (poisson)") plt.ylabel('$P(X=x)$') plt.xlabel('$x$')Out[18]:Дискретное распределение общего вида
Чтобы сгенерировать дискретную случайную величину общего вида, нужно задать множество её значений и соответствующих вероятностей и использовать функцию numpy.random.choice :
In [19]:elements = np.array([1, 5, 12]) probabilities = [0.05, 0.7, 0.25] np.random.choice(elements, 10, p=probabilities)Out[19]:array([ 5, 12, 12, 12, 5, 12, 5, 5, 5, 5])Другие распределения
Существует большое количество других стандартных семейств распределений, многие из которых также можно генерировать в Питоне. Например, распределение хи-квадрат $\chi^2_k$, имеющее наутральный параметр $k$, который называется числом степеней свободы:
In [20]:x = np.linspace(0,30,100) for k in [1, 2, 3, 4, 6, 9]: rv = sts.chi2(k) cdf = rv.cdf(x) plt.plot(x, cdf, label="$k=%s$" % k) plt.legend() plt.title("CDF ($\chi^2_k$)")Out[20]:Предыдущая запись
