Книга: Думай как аналитик. Статистика и данные с примерами на Python. 3-е изд.
Назад: Глава 5. Моделирование распределений
Дальше: Глава 7. Связь между переменными

Глава 6. Функция плотности вероятности

В предыдущей главе мы моделировали данные с помощью теоретических распределений, в том числе биномиального, пуассоновского, экспоненциального и нормального.

Биномиальное распределение и распределение Пуассона являются дискретными, это означает, что их исходы являются отдельными единицами, такими как целое число попаданий или промахов, количество забитых голов. В дискретном распределении каждому исходу соответствует значение вероятности.

Экспоненциальное и нормальное распределения являются непрерывными, это означает, что исходы могут находиться в любой точке диапазона возможных значений. В непрерывном распределении каждому исходу соответствует плотность вероятности. Плотность вероятности — абстрактное понятие, которое поначалу может оказаться трудным для понимания, но мы будем вводить его постепенно, шаг за шагом. Для начала еще раз обратимся к сравнению распределений.

Сравнение распределений

В предыдущей главе, когда мы сравнивали дискретные распределения, то использовали столбчатые диаграммы для отображения их функций вероятности (ФВ). А когда сравнивали непрерывные распределения, то строили линейный график для отображения их интегральных функций распределения (ИФР).

Для дискретных распределений мы также могли бы использовать ИФР. Например, рассмотрим ФВ распределения Пуассона с lam=2.2, хорошо моделирующего распределение размера домохозяйств в данных NSFG.

Для чтения файла данных респондента можно использовать функцию read_fem_resp:

from nsfg import read_fem_resp

 

resp = read_fem_resp()

Теперь выберем значения размера домохозяйства (num_family) для респондентов в возрасте (age) 25 лет и старше (older):

older = resp.query("age >= 25")

num_family = older["numfmhh"]

Создадим объект Pmf, представляющий собой распределение ответов:

from empiricaldist import Pmf

 

pmf_family = Pmf.from_seq(num_family, name="данные")

Также создадим объект Pmf для распределения Пуассона с тем же средним значением:

from thinkstats import poisson_pmf

 

lam = 2.2

ks = np.arange(11)

ps = poisson_pmf(ks, lam)

 

pmf_poisson = Pmf(ps, ks, name="пуассоновская модель")

Посмотрим, как распределение данных соотносится с пуассоновской моделью:

from thinkstats import two_bar_plots

 

two_bar_plots(pmf_family, pmf_poisson)

decorate(xlabel="Количество членов семьи")

Сравнение двух функций вероятности показывает, что модель хорошо согласуется с данными, но есть некоторые расхождения.

Чтобы понять, насколько существенны эти расхождения, полезно сравнить две ИФР. Для построения ИФР данных и модели можно воспользоваться методом make_cdf:

cdf_family = pmf_family.make_cdf()

cdf_poisson = pmf_poisson.make_cdf()

Вот как они выглядят:

from thinkstats import two_cdf_plots

 

two_cdf_plots(cdf_poisson, cdf_family)

decorate(xlabel="Количество членов семьи")

При сравнении двух ИФР расхождения менее заметны, но становится понятно, где и как они различаются. В то время как ФВ обычно подчеркивают небольшие различия, глядя на ИФР, можно понять общую картину.

ИФР также хорошо подходят для непрерывных данных. Для примера еще раз посмотрим на распределение веса новорожденных (birth_weights) из файла данных о беременности NSFG:

from nsfg import read_fem_preg

 

preg = read_fem_preg()

birth_weights = preg["totalwgt_lb"].dropna()

Вот код, который мы использовали в предыдущей главе, чтобы вписать нормальное распределение в данные:

from scipy.stats import trimboth

from thinkstats import make_normal_model

 

trimmed = trimboth(birth_weights, 0.01)

cdf_model = make_normal_model(trimmed)

А вот распределение данных в сравнении с нормальной моделью:

from empiricaldist import Cdf

 

cdf_birth_weight = Cdf.from_seq(birth_weights, name="выборка")

two_cdf_plots(cdf_model, cdf_birth_weight, xlabel="Вес при рождении (фунты)")

Как вы уже видели в предыдущей главе, нормальная модель хорошо соответствует данным, за исключением диапазона самых маленьких весов.

На мой взгляд, ИФР обычно лучше всего подходят для сравнения данных с моделью. Но для тех, кто не знаком с ИФР, есть еще один вариант — функция плотности вероятности.

Плотность вероятности

Вначале рассмотрим функцию плотности вероятности, ФПВ (probability density function, PDF) нормального распределения, которая вычисляет плотность вероятности в точке xs при заданных параметрах mu и sigma:

def normal_pdf(xs, mu, sigma):

    z = (xs - mu) / sigma

    return np.exp(-(z**2) / 2) / sigma / np.sqrt(2 * np.pi)

В качестве mu и sigma используем среднее значение и стандартное отклонение усеченного датасета весов новорожденных:

m, s = np.mean(trimmed), np.std(trimmed)

Теперь подадим массив значений веса (qs) на вход функции normal_pdf:

low = m - 4 * s

high = m + 4 * s

qs = np.linspace(low, high, 201)

ps = normal_pdf(qs, m, s)

Построим график полученного распределения:

plt.plot(qs, ps, label="нормальная модель", ls=":", color="gray")

decorate(xlabel="Вес при рождении (фунты)", ylabel="Плотность вероятности")

Результат выглядит как колоколообразная кривая, что характерно для нормального распределения.

Результатом вычисления значения функции normal_pdf является плотность вероятности. Например, вот величина функции плотности, вычисленная со средним значением в качестве аргумента, то есть там, где плотность наибольшая:

normal_pdf(m, m, s)

0.32093416297880123

Сама по себе плотность вероятности мало что значит, и самое главное — она не является вероятностью. Было бы неверно утверждать, что вероятность того, что случайно выбранный вес новорожденного равен m, составляет 32 %. На самом деле вероятность того, что вес ребенка при рождении действительно в точности равен m или любому другому конкретному значению, равна нулю.

Однако мы можем использовать плотность вероятности для вычисления вероятности того, что исход случайного события попадет в интервал между двумя значениями, вычислив площадь под кривой.

Это можно сделать с помощью функции normal_pdf, но удобнее использовать класс NormalPdf, который определен в модуле thinkstats. Вот как можно создать объект класса NormalPdf для распределения с теми же средним значением и стандартным отклонением, что и вес новорожденных в датасете NSFG:

from thinkstats import NormalPdf

 

pdf_model = NormalPdf(m, s, name="нормальная модель")

pdf_model

NormalPdf(7.280883100022579, 1.2430657948614345, name='нормальная модель')

Если вызвать этот объект как функцию, он вычислит значение ФПВ нормального распределения:

pdf_model(m)

0.32093416297880123

Теперь, чтобы вычислить площадь под графиком ФПВ, можно использовать следующую функцию, которая принимает на входе объект NormalPdf и границы интервала: нижнюю — low и верхнюю — high. Она вычисляет ФПВ в равномерно распределенных точках в интервале между low и high и использует функцию библиотеки SciPy simpson для оценки площади под кривой (название simpson объясняется использованием формулы Симпсона):

from scipy.integrate import simpson

 

def area_under(pdf, low, high):

    qs = np.linspace(low, high, 501)

    ps = pdf(qs)

    return simpson(y=ps, x=qs)

Если вычислить площадь под кривой во всем диапазоне оси абсцисс графика, то результат будет близок к 1:

area_under(pdf_model, 2, 12)

0.9999158086616793

Если мы расширим диапазон до всего множества вещественных чисел от минус бесконечности до плюс бесконечности, то общая площадь будет в точности равна 1.

Если в качестве нижней границы взять 0 (или любое значение, значительно меньше среднего), то можно вычислить долю новорожденных, вес которых меньше или равен 8.5 фунта:

area_under(pdf_model, 0, 8.5)

0.8366380335513807

Возможно, вы помните, что «доля значений, меньше или равных заданному» — это определение ИФР. Поэтому мы могли бы получить тот же результат, используя ИФР нормального распределения:

from scipy.stats import norm

 

norm.cdf(8.5, m, s)

0.8366380358092718

Точно так же можно использовать площадь под кривой плотности для вычисления доли новорожденных с весом от 6 до 8 фунтов:

area_under(pdf_model, 6, 8)

0.5671317752927691

Или получить тот же результат, используя ИФР для вычисления доли значений меньше 8 и затем вычитая из нее долю значений меньше 6:

norm.cdf(8, m, s) - norm.cdf(6, m, s)

0.5671317752921801

Таким образом, ИФР — это площадь под кривой ФПВ. Если вы знакомы с математическим анализом, то, по-другому говоря, ИФР — это интеграл ФПВ. И наоборот: ФПВ — это производная ИФР.

Экспоненциальная функция плотности вероятности

Для лучшего понимания концепции плотности вероятности полезно рассмотреть еще один пример. В предыдущей главе для моделирования времени первой заброшенной шайбы в хоккейном матче мы применяли экспоненциальное распределение. Для вычисления экспоненциальной ИФР мы использовали такую функцию, в которой lam — результативность в голах за единицу времени:

def exponential_cdf(x, lam):

    return 1 - np.exp(-lam * x)

Тогда ФПВ экспоненциального распределения можно рассчитать следующим образом:

def exponential_pdf(x, lam):

    return lam * np.exp(-lam * x)

В модуле thinkstats реализован объект ExponentialPdf, который задействует эту функцию для расчета экспоненциальной ФПВ. Мы можем использовать этот объект для моделирования экспоненциального распределения с показателем результативности в шесть шайб за игру:

from thinkstats import ExponentialPdf

 

lam = 6

pdf_expo = ExponentialPdf(lam, name="экспоненциальная модель")

pdf_expo

ExponentialPdf(6, name='экспоненциальная модель')

У объекта ExponentialPdf есть метод plot, который можно использовать для построения графика ФПВ. Обратите внимание, что единицей измерения времени здесь являются игры, а не секунды, как в предыдущей главе:

qs = np.linspace(0, 1.5, 201)

pdf_expo.plot(qs, ls=":", color="gray")

decorate(xlabel="Время (игры)", ylabel="Плотность вероятности")

Взглянув на ось y, можно заметить, что плотность вероятности бывает больше 1, что лишний раз напоминает, что плотность вероятности — это не вероятность. В то время как площадь под кривой плотности — это вероятность, поэтому она никогда не должна превышать 1.

Если посчитать площадь под этой кривой в диапазоне от 0 до 1.5 игры, можно убедиться, что результат будет близок к 1:

area_under(pdf_expo, 0, 1.5)

0.999876590779019

Если существенно расширить диапазон, то результат будет немного больше 1, но лишь потому, что мы используем приближенные вычисления площади. Математически это в точности 1, что можно подтвердить при помощи экспоненциальной ИФР:

from thinkstats import exponential_cdf

 

exponential_cdf(7, lam)

1.0

Площадь под графиком плотности можно использовать для вычисления вероятности заброшенной шайбы в любой промежуток времени. Например, вот вероятность того, что шайба будет заброшена на первой минуте 60-минутной игры:

area_under(pdf_expo, 0, 1 / 60)

0.09516258196404043

К такому же результату можно прийти, используя экспоненциальную ИФР:

exponential_cdf(1 / 60, lam)

0.09516258196404048

Подведем итоги. При вычислении ФПВ результатом является плотность вероятности, не являющаяся вероятностью. Однако результатом вычисления площади под ФПВ-кривой будет вероятность того, что величина попадет в соответствующий интервал. Эту же вероятность можно найти, если вычислить ИФР в начале и в конце интервала, а затем посчитать их разницу.

Сравнение функции вероятности и функции плотности вероятности

Распространенной ошибкой является сравнение ФВ некоторой выборки с ФПВ теоретической модели. Например, предположим, что требуется сравнить распределение веса новорожденных с нормальной моделью. Вот объект Pmf, представляющий распределение данных:

pmf_birth_weight = Pmf.from_seq(birth_weights, name="данные")

У нас также имеется объект pdf_model, представляющий ФПВ нормального распределения с теми же средним значением и стандартным отклонением. Вот что произойдет, если мы изобразим их на одном графике:

pdf_model.plot(ls=":", color="gray")

pmf_birth_weight.plot()

 

decorate(xlabel="Вес при рождении (фунты)", ylabel="Вероятность?

Плотность вероятности?")

Так делать не стоит. Хотя бы по причине того, что эти распределения имеют разные единицы измерения. ФВ содержит значения вероятности, а PDF — плотности вероятности, поэтому нельзя сравнивать их и строить их графики в одних и тех же осях координат.

Один из способов решить эту проблему — создать объект Pmf, аппроксимирующий нормальное распределение путем вычисления ФПВ на дискретном наборе точек. В классе NormalPdf есть метод make_pmf, который это делает:

pmf_model = pdf_model.make_pmf()

Результатом является нормированный объект Pmf, содержащий вероятностные меры. Поэтому можно по крайней мере построить его график в тех же осях, что и ФВ данных:

pmf_model.plot(ls=":", color="gray")

pmf_birth_weight.plot()

 

decorate(xlabel="Вес при рождении (фунты)", ylabel="Вероятность")

Но это все еще плохой способ сравнения распределений. Одна из проблем заключается в том, что в этих двух объектах Pmf содержится разное количество величин, к тому же в pmf_birth_weight они распределены неравномерно. По этой причине вероятностные меры этих распределений едва ли сопоставимы:

len(pmf_model), len(pmf_birth_weight)

(201, 184)

Другим препятствием является зашумленность Pmf-данных. Поэтому поищем другое решение.

Ядерная оценка плотности

Вместо создания ФВ с помощью модельного распределения можно использовать данные для конструирования ФПВ. Чтобы посмотреть, как это работает, начнем с небольшой выборки из нашего датасета:

n = 10

sample = birth_weights.sample(n)

ФВ этой выборки выглядит следующим образом:

for weight in sample:

    pmf = Pmf.from_seq([weight]) / n

    pmf.bar(width=0.08, alpha=0.5)

 

xlim = [1.5, 12.5]

decorate(xlabel="Вес при рождении (фунты)", ylabel="Вероятность", xlim=xlim)

При таком способе представления распределения данные рассматриваются так, как если бы они были дискретными, поэтому каждая вероятностная мера концентрируется в одной точке. Но вес новорожденных на самом деле непрерывен, поэтому в промежутках между элементами выборки также могут присутствовать данные. Учесть эту возможность можно, заменив каждую дискретную вероятностную меру непрерывной плотностью вероятности, как показано ниже:

qs = np.linspace(2, 12, 201)

 

for weight in sample:

    ps = NormalPdf(weight, 0.75)(qs) / n

    plt.plot(qs, ps, alpha=0.5)

 

decorate(xlabel="Вес при рождении (фунты)", ylabel="Плотность вероятности",

xlim=xlim)

Для каждого значения веса в выборке создадим NormalPdf, у которого наблюдаемый вес служит средним значением, а затем сложим их:

low_ps = np.zeros_like(qs)

 

for weight in sample:

    ps = NormalPdf(weight, 0.75)(qs) / n

    high_ps = low_ps + ps

    plt.fill_between(qs, low_ps, high_ps, alpha=0.5, lw=1, ec="white")

    low_ps = high_ps

 

decorate(xlabel="Вес при рождении (фунты)", ylabel="Плотность вероятности",

xlim=xlim)

Когда мы складываем плотности вероятности в каждой точке данных, результатом является оценка плотности вероятности для всей выборки. Этот процесс называется ядерной оценкой плотности, ЯОП (kernel density estimation, KDE). В данном контексте «ядро» — это одна из тех элементарных функций плотности, которые мы суммировали. Поскольку ядра, которые мы использовали, являются нормальными распределениями, также известными как гауссовы, можно конкретизировать, что мы вычислили гауссову ЯОП.

В библиотеке SciPy определен класс gaussian_kde, который реализует этот алгоритм. Вот как можно его использовать для оценки распределения веса новорожденных:

from scipy.stats import gaussian_kde

 

kde = gaussian_kde(birth_weights)

Результатом является объект, представляющий оцениваемую ФПВ. Последнюю можно вычислить, если вызвать объект как функцию:

ps = kde(qs)

Вот как выглядит полученное распределение:

plt.plot(qs, ps)

 

decorate(xlabel="Вес при рождении (фунты)", ylabel="Плотность вероятности")

В модуле thinkstats определен объект Pdf, при создании которого передается результат выполнения gaussian_kde и интервал значений (domain), на котором необходимо вычислить оценку плотности. Вот как его можно создать:

from thinkstats import Pdf

 

domain = np.min(birth_weights), np.max(birth_weights)

kde_birth_weights = Pdf(kde, domain, name="данные")

В Pdf реализован метод отображения plot, который можно использовать для сравнения оценки плотности выборки и ФПВ нормального распределения:

pdf_model.plot(ls=":", color="gray")

kde_birth_weights.plot()

 

decorate(xlabel="Вес при рождении (фунты)", ylabel="Плотность вероятности")

Ядерная оценка плотности позволяет сравнить распределение данных с теоретической моделью. В некоторых сценариях такой способ визуального представления сравнения может подойти. Но тем, кто знаком с ИФР, лучше использовать их: сравнение двух ИФР, как правило, более эффективно.

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

Итак, у нас есть полный набор способов представления распределений: ФВ, ИФР и ФПВ. На следующей схеме указаны все эти способы и переходы между ними. Например, если у нас есть ФВ, то для вычисления накопленной суммы вероятностей можно использовать функцию cumsum, что дает нам ИФР того же распределения:

Чтобы продемонстрировать эти переходы, воспользуемся новым датасетом, который, согласно описанию, «содержит время рождения, пол и вес при рождении для каждого из 44 младенцев, родившихся за один промежуток времени в 24 часа в больнице австралийского города Брисбен». Инструкции по загрузке данных приведены в Jupyter-блокноте для этой главы.

Данные можно считать следующим образом:

from thinkstats import read_baby_boom

 

boom = read_baby_boom()

boom.head()

time (время)

sex (пол)

weight_g (вес_г)

minutes (минуты)

0

5

1

3837

5

1

104

1

3334

64

2

118

2

3554

78

3

155

2

3838

115

4

257

2

3625

177

В столбце minutes указано «количество минут, прошедших с начала суток до каждого рождения». Таким образом, для вычисления интервала между двумя последовательными рождениями можно использовать метод diff:

diffs = boom["minutes"].diff().dropna()

Если роды происходят с одинаковой вероятностью в любую минуту дня, стоит ожидать, что эти интервалы будут распределены по экспоненте. На самом деле это не совсем так, но экспоненциальная модель все же может неплохо подойти для этих данных.

Чтобы убедиться в этом, начнем с создания объекта Pmf, представляющего распределение интервалов:

pmf_diffs = Pmf.from_seq(diffs, name="данные")

pmf_diffs.bar(width=1)

 

decorate(xlabel="Интервал (минуты)", ylabel="Вероятность")

Теперь для вычисления интегрального распределения вероятности и создания объекта Cdf воспользуемся методом make_cdf:

cdf_diffs = pmf_diffs.make_cdf()

cdf_diffs.step()

 

decorate(xlabel="Интервал (минуты)", ylabel="ИФР")

Объекты Pmf и Cdf эквивалентны с той точки зрения, что если известен один из них, то можно вычислить второй. Для примера воспользуемся методом make_pmf, который вычисляет разность между последовательными значениями интегральной вероятности в объекте Cdf и возвращает объект Pmf:

pmf_diffs2 = cdf_diffs.make_pmf()

Результат должен быть идентичен исходному Pmf, но могут быть небольшие отличия из-за погрешности арифметики с плавающей точкой. Чтобы проверить, что результат близок к исходному Pmf, можно вызвать функцию allclose:

np.allclose(pmf_diffs, pmf_diffs2)

True

Ответ положительный.

Если имеется объект Pmf, то оценку функции плотности можно получить путем вызова gaussian_kde, указывая вероятности из Pmf в качестве весов (weights):

kde = gaussian_kde(pmf_diffs.qs, weights=pmf_diffs.ps)

Чтобы отобразить результаты, можно из объекта gaussian_kde создать объект класса Pdf и у последнего вызвать метод plot:

domain = np.min(pmf_diffs.qs), np.max(pmf_diffs.qs)

kde_diffs = Pdf(kde, domain=domain, name="оценка плотности")

 

kde_diffs.plot(ls=":", color="gray")

decorate(xlabel="Интервал (минуты)", ylabel="Плотность вероятности")

Чтобы проверить, соответствует ли оценка плотности экспоненциальной модели, можно создать объект ExponentialCdf с тем же средним значением, что и данные:

from thinkstats import ExponentialCdf

 

m = diffs.mean()

lam = 1 / m

cdf_model = ExponentialCdf(lam, name="экспоненциальная ИФР")

Вот как экспоненциальная ИФР выглядит в сравнении с ИФР данных:

cdf_model.plot(ls=":", color="gray")

cdf_diffs.step()

 

decorate(xlabel="Интервал (минуты)", ylabel="ИФР")

Экспоненциальная модель хорошо соответствует ИФР данных.

У объекта ExponentialCdf можно вызвать метод make_cdf для дискретизации ИФР, то есть для получения дискретной аппроксимации путем вычисления ИФР для последовательности равномерно распределенных величин:

discrete_cdf_model = cdf_model.make_cdf(qs)

discrete_cdf_model.step()

 

decorate(xlabel="Интервал (минуты)", ylabel="ИФР")

Чтобы перейти от дискретной ИФР к непрерывной ИФР, можно выполнить интерполяцию между шагами. Именно это происходит, когда мы используем метод plot вместо метода step:

discrete_cdf_model.plot(color="gray")

 

decorate(xlabel="Интервал (минуты)", ylabel="ИФР")

Наконец, ФПВ — это производная непрерывной ИФР, а ИФР — это интеграл ФПВ.

На этом примере вы узнали, как для работы с ФВ, ИФР и ФПВ можно использовать объекты классов Pmf, Cdf и Pdf соответственно, а также преобразовывать одни в другие.

Глоссарий

Непрерывный (continuous)

Величина является непрерывной, если она может принимать любое значение в некотором диапазоне на числовой оси. Большинство измеряемых нами физических величин, таких как вес, расстояние и время, являются непрерывными.

Дискретный (discrete)

Величина является дискретной, если она может принимать ограниченный набор значений, например целых чисел или категорий. Точные значения являются дискретными, так же как категориальные переменные.

Функция плотности вероятности, ФПВ (probability density function, PDF)

Функция, которая показывает, как плотность вероятности (не вероятность) распределена по значениям непрерывной переменной. Площадь под графиком ФПВ в некотором интервале значений дает вероятность того, что случайная величина попадет в этот интервал.

Плотность вероятности (probability density)

Значение ФПВ в некоторой точке; само по себе оно не является вероятностью, но его можно использовать для вычисления вероятности.

Ядерная оценка плотности, ЯОП (kernel density estimation, KDE)

Метод оценки ФПВ на основе выборки.

Дискретизация (discretization)

Аппроксимация непрерывной величины путем деления ее диапазона на дискретные уровни или категории.

Упражнения

Упражнение 6.1

Предположим, что время до первого забитого гола в матче чемпионата мира по футболу хорошо моделируется экспоненциальным распределением с коэффициентом результативности lam=2.5 гола за игру. Создайте объект ExponentialPdf, представляющий это распределение, и используйте метод area_under для вычисления вероятности того, что время до первого гола составит меньше половины матча. Затем используйте объект ExponentialCdf, чтобы вычислить ту же вероятность и проверить согласованность обоих результатов.

Используйте объект ExponentialPdf для вычисления вероятности того, что первый гол будет забит во второй половине матча. Затем используйте объект ExponentialCdf для вычисления той же вероятности и проверьте соответствие результатов.

Упражнение 6.2

Чтобы стать членом Blue Man Group, вы должны быть мужчиной ростом от 5 футов и 10 дюймов до 6 футов и 1 дюйма, то есть примерно от 178 до 185 см. Узнаем, какая часть взрослого мужского населения Соединенных Штатов соответствует этому требованию.

Рост (heights) участников исследования BRFSS мужского пола (male) хорошо моделируется с помощью нормального распределения: среднее значение составляет 178 см, а стандартное отклонение — 7 см:

from thinkstats import read_brfss

 

brfss = read_brfss()

male = brfss.query("sex == 1")

heights = male["htm3"].dropna()

from scipy.stats import trimboth

 

trimmed = trimboth(heights, 0.01)

m, s = np.mean(trimmed), np.std(trimmed)

m, s

(178.10278947124948, 7.017054887136004)

Вот объект NormalCdf, который представляет нормальное распределение с теми же средним значением и стандартным отклонением, что и усеченные данные:

from thinkstats import NormalCdf

 

cdf_normal_model = NormalCdf(m, s, name='нормальная модель')

И вот как оно соотносится с ИФР данных:

cdf_height = Cdf.from_seq(heights, name="данные")

cdf_normal_model.plot(ls=":", color="gray")

cdf_height.step()

 

xlim = [140, 210]

decorate(xlabel="Рост (см)", ylabel="ИФР", xlim=xlim)

Используйте функцию gaussian_kde для создания объекта Pdf, аппроксимирующего ФПВ роста мужчин. Подсказка: изучите аргумент bw_method, предназначенный для настройки гладкости оценки плотности. Постройте график оценки плотности и сравните его с нормальным распределением NormalPdf со средним значением m и стандартным отклонением s.

С помощью объекта NormalPdf и метода area_under вычислите долю людей ростом от 178 до 185 см в рамках нормальной модели. Используйте объект класса NormalCdf для вычисления той же доли и убедитесь, что результаты не противоречат друг другу. Наконец, используйте объект Cdf эмпирических данных, чтобы определить, какая доля людей, описанных в датасете, находится в том же диапазоне.

Назад: Глава 5. Моделирование распределений
Дальше: Глава 7. Связь между переменными