Скачать ipynb
07_random

Python для анализа данных

Работа со случайными величинами (numpy.random и scipy.stats)

Полное описание для scipy.stats доступно по ссылке. По ссылке можно прочитать полную документацию по работе с непрерывными (Continuous), дискретными (Discrete) и многомерными (Multivariate) распределениями. Пакет также предоставляет некоторое количество статистических методов, которые рассматриваются в курсах статистики. А описание для numpy.random находится по следующей ссылке.

In [1]:
import scipy.stats as sps
import numpy as np
import ipywidgets as widgets
import matplotlib.pyplot as plt
from numpy import random
import seaborn as sns

sns.set(palette='Set2', style='whitegrid', font_scale=1.3)

1. Работа с библиотекой numpy.random.

Базовые функции

  • randint(low[, high, size, dtype]) — случайное число в диапазоне;

  • choice(a[, size, replace, p]) — Генерирует случайную выборку из заданного одномерного массива;

  • shuffle(x) — Премешивает выходные значения массива;

  • permutation(x) — Перемешивает значения самого массива и возвращает его перемешанным.


Создание простого случайного массива

Сгенерируем 5 случайных чисел из равномерного распределения [0, 1):

In [2]:
np.random.rand(5)
Out[2]:
array([0.53404185, 0.33336281, 0.74879742, 0.18810245, 0.33417001])

Создание случайных целых чисел:

Создадим случайный целочисленный массив размером 5x5 в диапазоне от 10 (включительно) до 20 (включительно)

In [3]:
np.random.randint(10, 20, (5, 5))
Out[3]:
array([[18, 11, 10, 19, 19],
       [14, 15, 10, 15, 19],
       [11, 12, 15, 17, 17],
       [13, 11, 17, 17, 19],
       [16, 14, 19, 17, 18]])

Также возможна генерация случайных чисел из конкретных распределений:

  • beta(a, b[, size]) — бета-распределение;
  • binomial(n, p[, size]) — биномиальное распределение;
  • exponential([scale, size]) — экспоненциальное распределение;
  • gamma(shape[, scale, size]) — гамма-распределение;
  • geometric(p[, size]) — геометрическое распределение;
  • normal([loc, scale, size]) — нормальное распределение;
  • poisson([lam, size]) — пуассоновское распределение;
  • uniform([low, high, size]) — равномерное распределение.

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

In [4]:
np.random.normal(size=5)
Out[4]:
array([ 0.5770148 , -1.68602927,  0.21022454,  0.57520789, -0.32360461])

Укажем параметры распределения

In [5]:
np.random.normal(70, 10, 5)
Out[5]:
array([73.68257501, 56.80081027, 63.90140038, 81.41057287, 62.30318935])

Генерация из пуассоновского распределения

In [6]:
np.random.poisson(lam=2.5, size=5)
Out[6]:
array([5, 2, 6, 2, 4])

Многомерное нормальное распределение:

Генерация случайных выборок из многомерного нормального распределения выполняется с помощью функции multivariate_normal(mean, cov[, size, ...]).

Сгенерируем 800 векторов из двумерного нормального распределения со средним [0, 0] и ковариационной матрицей [[6, -3], [-3, 3.5]].

In [7]:
mean = (1, 2)
cov = [[1, 0], [0, 1]]

x = np.random.multivariate_normal(mean, cov, (3, 3))
cov = np.array([[6, -3], [-3, 3.5]])
pts = np.random.multivariate_normal([0, 0], cov, size=800)

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

In [8]:
plt.figure(figsize=(6, 6))
plt.plot(pts[:, 0], pts[:, 1], '.', alpha = 0.5)
plt.axis('equal')
plt.show()

2. Работа с библиотекой scipy.stats.

Общий принцип:

Пусть $X$ — класс, реализующий некоторое распределение. Конкретное распределение с параметрами params можно получить как X(params). У него доступны следующие методы:

  • X(params).rvs(size=N) — генерация выборки размера $N$ (Random VariateS). Возвращает numpy.array;
  • X(params).cdf(x) — значение функции распределения в точке $x$ (Cumulative Distribution Function);
  • X(params).logcdf(x) — значение логарифма функции распределения в точке $x$;
  • X(params).ppf(q) — $q$-квантиль (Percent Point Function);
  • X(params).mean() — математическое ожидание;
  • X(params).median() — медиана ($1/2$-квантиль);
  • X(params).var() — дисперсия (Variance);
  • X(params).std() — стандартное отклонение = корень из дисперсии (Standard Deviation).

Кроме того для непрерывных распределений определены функции

  • X(params).pdf(x) — значение плотности в точке $x$ (Probability Density Function);
  • X(params).logpdf(x) — значение логарифма плотности в точке $x$.

А для дискретных

  • X(params).pmf(k) — значение дискретной плотности в точке $k$ (Probability Mass Function);
  • X(params).logpdf(k) — значение логарифма дискретной плотности в точке $k$.

Все перечисленные выше методы применимы как к конкретному распределению X(params), так и к самому классу X. Во втором случае параметры передаются в сам метод. Например, вызов X.rvs(size=N, params) эквивалентен X(params).rvs(size=N).

Параметры могут быть следующими:

  • loc — параметр сдвига;
  • scale — параметр масштаба;
  • и другие параметры (например, $n$ и $p$ для биномиального).

Для примера сгенерируем выборку размера $N = 200$ из распределения $\mathcal{N}(1, 9)$ и посчитаем некоторые статистики. В терминах выше описанных функций у нас $X$ = sps.norm, а params = (loc=1, scale=3).

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

In [9]:
sample = sps.norm(loc=1, scale=3).rvs(size=200)
print('Первые 10 значений выборки:\n', sample[:10])
print('Выборочное среденее: %.3f' % sample.mean())
print('Выборочная дисперсия: %.3f' % sample.var())
Первые 10 значений выборки:
 [-4.77722498  0.38477431 -0.39011306  3.35800245 -1.63958325 -0.65691616
  0.7098962  -0.9834454   1.89568372  2.81589159]
Выборочное среденее: 0.938
Выборочная дисперсия: 9.002

Вероятностные характеристики

In [10]:
print('Плотность:\t\t', sps.norm(loc=1, scale=3).pdf([-1, 0, 1, 2, 3]))
print('Функция распределения:\t', sps.norm(loc=1, scale=3).cdf([-1, 0, 1, 2, 3]))
Плотность:		 [0.10648267 0.12579441 0.13298076 0.12579441 0.10648267]
Функция распределения:	 [0.25249254 0.36944134 0.5        0.63055866 0.74750746]

$p$-квантиль распределения с функцией распределения $F$ — это число $min\{x: F(x) \geqslant p\}$.

In [11]:
print('Квантили:', sps.norm(loc=1, scale=3).ppf([0.05, 0.1, 0.5, 0.9, 0.95]))
Квантили: [-3.93456088 -2.8446547   1.          4.8446547   5.93456088]

Cгенерируем выборку размера $N = 200$ из распределения $Bin(10, 0.6)$ и посчитаем некоторые статистики. В терминах выше описанных функций у нас $X$ = sps.binom, а params = (n=10, p=0.6).

In [12]:
sample = sps.binom(n=10, p=0.6).rvs(size=200)
print('Первые 10 значений выборки:\n', sample[:10])
print('Выборочное среденее: %.3f' % sample.mean())
print('Выборочная дисперсия: %.3f' % sample.var())
Первые 10 значений выборки:
 [9 4 5 8 7 5 7 8 6 7]
Выборочное среденее: 5.815
Выборочная дисперсия: 2.511
In [13]:
print('Дискретная плотность:\t', sps.binom(n=10, p=0.6).pmf([-1, 0, 5, 5.5, 10]))
print('Функция распределения:\t', sps.binom(n=10, p=0.6).cdf([-1, 0, 5, 5.5, 10]))
Дискретная плотность:	 [0.00000000e+00 1.04857600e-04 2.00658125e-01 0.00000000e+00
 6.04661760e-03]
Функция распределения:	 [0.00000000e+00 1.04857600e-04 3.66896742e-01 3.66896742e-01
 1.00000000e+00]
In [14]:
print('Квантили:', sps.binom(n=10, p=0.6).ppf([0.05, 0.1, 0.5, 0.9, 0.95]))
Квантили: [3. 4. 6. 8. 8.]

Отдельно есть класс для многомерного нормального распределения. Для примера сгенерируем выборку размера $N=200$ из распределения $\mathcal{N} \left( \begin{pmatrix} 1 \\ 1 \end{pmatrix}, \begin{pmatrix} 2 & 1 \\ 1 & 2 \end{pmatrix} \right)$.

In [15]:
sample = sps.multivariate_normal(
    mean=[1, 1], cov=[[2, 1], [1, 2]]
).rvs(size=200)

print('Первые 10 значений выборки:\n', sample[:10])
print('Выборочное среденее:', sample.mean(axis=0))
print('Выборочная матрица ковариаций:\n', np.cov(sample.T))
Первые 10 значений выборки:
 [[ 0.85484709  2.77930705]
 [ 2.08602217  2.47692174]
 [-1.36896172 -2.80735273]
 [ 0.15274979 -0.10392857]
 [ 2.12666431  2.54083453]
 [ 0.65826516  2.39020483]
 [-0.13879247 -0.10071583]
 [-0.82272378  1.12570173]
 [ 2.17156211  2.44109516]
 [ 0.8552283   2.99134069]]
Выборочное среденее: [1.1563024  1.21146554]
Выборочная матрица ковариаций:
 [[2.14874013 1.10612854]
 [1.10612854 2.03850564]]

Некоторая хитрость :)

In [16]:
sample = sps.norm(loc=np.arange(10), scale=0.1).rvs(size=10)
print(sample)
[-3.71478133e-03  9.25683322e-01  2.01936398e+00  3.04612388e+00
  3.91695761e+00  5.01249749e+00  5.83371327e+00  7.10138435e+00
  8.00572921e+00  9.08765149e+00]

Бывает так, что надо сгенерировать выборку из распределения, которого нет в `scipy.stats`. Для этого надо создать класс, который будет наследоваться от класса rv_continuous для непрерывных случайных величин и от класса rv_discrete для дискретных случайных величин. Пример из документации.

Для примера сгенерируем выборку из распределения с плотностью $f(x) = \frac{4}{15} x^3 I\{x \in [1, 2] = [a, b]\}$.

In [17]:
class cubic_gen(sps.rv_continuous):
    def _pdf(self, x):
        return 4 * x ** 3 / 15
cubic = cubic_gen(a=1, b=2, name='cubic')

sample = cubic.rvs(size=200)

print('Первые 10 значений выборки:\n', sample[:10])
print('Выборочное среденее: %.3f' % sample.mean())
print('Выборочная дисперсия: %.3f' % sample.var())
Первые 10 значений выборки:
 [1.91569466 1.6333686  1.71335385 1.98595286 1.39090471 1.13319513
 1.18916208 1.93276106 1.62536501 1.99435283]
Выборочное среденее: 1.641
Выборочная дисперсия: 0.079

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

In [18]:
some_distribution = sps.rv_discrete(
    name='some_distribution', 
    values=([1, 2, 3], [0.6, 0.1, 0.3])  # значения и вероятности
)

sample = some_distribution.rvs(size=200)

print('Первые 10 значений выборки:\n', sample[:10])
print('Выборочное среденее: %.3f' % sample.mean())
print('Частота значений по выборке:', 
      (sample == 1).mean(), (sample == 2).mean(), (sample == 3).mean())
Первые 10 значений выборки:
 [1 3 1 3 2 1 1 1 3 1]
Выборочное среденее: 1.695
Частота значений по выборке: 0.59 0.125 0.285

3. Как генерируются случайные числа

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

  • BitGenerator управляет состоянием и предоставляет функции для создания случайных бинарных последовательностей.

  • Генератор случайных чисел Generator принимает набор из генератора битов, и преобразует их целевые распределения, например, нормальное распределение.

Генератор — пользовательский объект, который почти идентичен устаревшему RandomState . Он принимает экземпляр генератора битов в качестве аргумента. В настоящее время по умолчанию используется PCG64.

Можно воспользоваться функцие default_rng

In [19]:
rng = np.random.default_rng(12345)
print(rng)
Generator(PCG64)
In [20]:
print(rng.random())
0.22733602246716966

Можно также создать экземпляр генератора напрямую с помощью экземпляра BitGenerator.

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

In [21]:
rng = np.random.Generator(np.random.PCG64(12345))
print(rng) 
Generator(PCG64)

Аналогично использованию более старого генератора бит MT19937 (не рекомендуется), можно создать его экземпляр напрямую и передать его генератору:

In [22]:
rng = np.random.Generator(np.random.MT19937(12345))
print(rng) 
Generator(MT19937)

Random.seed:

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

random.seed(svalue, version)

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

Если вы дважды используете одно и то же начальное значение, вы получите один и тот же результат

In [23]:
np.random.seed(10)
print(random.random())

np.random.seed(10)
print(random.random())
0.771320643266746
0.771320643266746

Другой пример, в котором мы генерируем одно и то же случайное число много раз

In [24]:
for i in range(5):
    # устанавливаем опцию генератора
    np.random.seed(11)

    # генерируем число от 1 до 1000.
    print(np.random.randint(1, 1000))
922
922
922
922
922

4. Производительность

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

In [25]:
size = 1000

Сравним время генерации 1000 случайных чисел двумя библиотеками

In [26]:
%timeit x = np.random.uniform(size=size, high=2)
10.8 µs ± 249 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [27]:
%timeit x = sps.uniform.rvs(size=size, scale=2)
54.1 µs ± 1.63 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Как видим, numpy генерирует в 5 раз быстрее.

Если же мы будем иначе передавать параметры распределения в scipy, то будет еще дольше

In [28]:
%timeit x = sps.uniform(scale=2).rvs(size=size)
618 µs ± 34.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Это объясняется тем, что код sps.uniform(scale=2) создает объект распределения, на что тратится достаточно много времени

In [29]:
%timeit x = sps.uniform(scale=2)
495 µs ± 17.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Посмотрим также примеры с нормальным распределением

In [30]:
%timeit x = np.random.normal(size=size, loc=2, scale=5)
28.2 µs ± 1.19 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [31]:
%timeit x = sps.norm.rvs(size=size, loc=2, scale=5)
68.4 µs ± 1.68 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [32]:
%timeit x = sps.norm(loc=2, scale=5).rvs(size=size)
672 µs ± 29.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

5. Свойства абсолютно непрерывных распределений

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

In [33]:
def show_pdf(pdf,  xmin, xmax, ymax, grid_size, distr_name, **kwargs):
    """
    Рисует график плотности непрерывного распределения
    
    pdf - плотность
    xmin, xmax - границы графика по оси x
    ymax - граница графика по оси y
    grid_size - размер сетки, по которой рисуется график
    distr_name - название распределения
    kwargs - параметры плотности
    """
    
    grid = np.linspace(xmin, xmax, grid_size)  
    plt.figure(figsize=(10, 5))
    plt.plot(grid, pdf(grid, **kwargs), lw=5)
    plt.grid(ls=':')
    plt.xlabel('Значение', fontsize=18)
    plt.ylabel('Плотность', fontsize=18)
    plt.xlim((xmin, xmax))
    plt.ylim((None, ymax))
    title = 'Плотность {}'.format(distr_name)
    plt.title(title.format(**kwargs), fontsize=20)
    plt.show()

2.1 Нормальное распределение

$\mathcal{N}(a, \sigma^2)$ — нормальное распределение.

Параметры в scipy.stats:

  • loc = $a$,
  • scale = $\sigma$.

Свойства распределения:

  • математическое ожидание: $a$,
  • дисперсия: $\sigma^2$.

Посмотрим, как выглядит плотность нормального стандартного распределения $\mathcal{N}(0, 1)$:

In [34]:
show_pdf(
    pdf=sps.norm.pdf, xmin=-3, xmax=3, ymax=0.5, grid_size=100, 
    distr_name=r'$N({loc}, {scale})$', loc=0, scale=1
)

Сгенерируем значения из нормального стандартного распределения и сравним гистограмму с плотностью:

In [35]:
sample = sps.norm.rvs(size=1000)  # выборка размера 1000
grid = np.linspace(-3, 3, 1000)  # сетка для построения графика

plt.figure(figsize=(12, 5))
plt.hist(sample, bins=30, density=True, 
         alpha=0.6, label='Гистограмма выборки') 
plt.plot(grid, sps.norm.pdf(grid), color='red', 
         lw=5, label='Плотность случайной величины') 
plt.title(r'Случайная величина $\xi \sim \mathcal{N}$(0, 1)', fontsize=20)
plt.legend(fontsize=14, loc=1)
plt.show()

Исследуем, как меняется плотность распределения в зависимости от параметров.

In [36]:
# создать виджет, но не отображать его
ip = widgets.interactive(show_pdf,
    pdf=widgets.fixed(sps.norm.pdf),
    grid_size=widgets.IntSlider(min=25, max=300, step=25, value=100),
    xmin=widgets.FloatSlider(min=-10, max=0, step=0.1, value=-5),
    xmax=widgets.FloatSlider(min=0, max=10, step=0.1, value=5),
    ymax=widgets.FloatSlider(min=0, max=2, step=0.1, value=1),
    loc = widgets.FloatSlider(min=-10, max=10, step=0.1, value=0),
    scale = widgets.FloatSlider(min=0.01, max=2, step=0.01, value=1),
    distr_name = r'$N$({loc}, {scale})'
);

# отображаем слайдеры группами
display(widgets.HBox(ip.children[:2]))
display(widgets.HBox(ip.children[2:4]))
display(widgets.HBox(ip.children[5:7]))

# отображаем вывод функции
display(ip.children[-1])
ip.update() # чтобы функция запустилась до первого изменения слайдеров

Показательный пример с разными значениями параметров распределения:

In [37]:
grid = np.linspace(-7, 7, 1000)  # сетка для построения графика
loc_values = [0, 3, 0]  # набор значений параметра a
sigma_values = [1, 1, 2]  # набор значений параметра sigma

plt.figure(figsize=(12, 6))

for i, (a, sigma) in enumerate(zip(loc_values, sigma_values)):
    plt.plot(grid, sps.norm(a, sigma).pdf(grid), lw=5, 
             label='$\mathcal{N}' + '({}, {})$'.format(a, sigma))

plt.legend(fontsize=16)
plt.title('Плотности нормального распределения', fontsize=20)
plt.xlabel('Значение', fontsize=18)
plt.ylabel('Плотность', fontsize=18)
plt.show()

Значения параметров определяют положение и форму кривой на графике распределения, каждой комбинации параметров соответствует уникальное распределение.

Для нормального распределения:

  • Параметр $loc = a$ отвечает за смещение кривой вдоль $\mathcal{Ox}$, тем самым определяя положение вертикальной оси симметрии плотности распределения. Вероятность того, что значение случайной величины $x$ попадет в отрезок $\mathcal{[m; n]}$, равна площади участка, зажатого кривой плотности, $\mathcal{Ox}$ и вертикальными прямыми ${x = m}$, ${x = n}$. В точке $a$ значение плотности распределения наибольшее, соответственно вероятность того, что значение случайной величины, имеющей нормальное распределение, попадет в окрестность точки $а$ — наибольшая.
  • параметр ${scale = \sigma}$ отвечает за смещение экстремума вдоль $\mathcal{Oy}$ и "прижимание" кривой к вертикальной прямой ${x = a}$, тем самым увеличивая площадь под кривой плотности в окрестности точки $а$. Другими словами, этот параметр отвечает за дисперсию — меру разброса значений случайной величины. При уменьшении параметра $\sigma$ увеличивается вероятность того, что нормально распределенная случайная величина будет равна $a$. Это соответствует мере разброса значений случайной величины относительно её математического ожидания, то есть дисперсии $\sigma^2$.

Проверим несколько полезных свойств нормального распределения.

Пусть $\xi_1 \sim \mathcal{N}(a_1, \sigma_1^2)$ и $\xi_2 \sim \mathcal{N}(a_2, \sigma_2^2)$ — независимые случайные величины. Тогда $\xi_3 = \xi_1 + \xi_1 \sim \mathcal{N}(a_1 + a_2, \sigma_1^2 + \sigma_2^2)$

In [38]:
sample1 = sps.norm(loc=-1, scale=3).rvs(size=1000)
sample2 = sps.norm(loc=1, scale=4).rvs(size=1000)
sample3 = sample1 + sample2

grid = np.linspace(-15, 15, 1000)

plt.figure(figsize=(12, 5))
plt.hist(sample3, density=True, bins=30, alpha=0.6, 
         label=r'Гистограмма суммы $\xi_3 = \xi_1 + \xi_1$')
plt.plot(grid, sps.norm(-1 + 1, np.sqrt(3*3 + 4*4)).pdf(grid), 
         color='red', lw=5, label=r'Плотность $\mathcal{N}(0, 25)$')
plt.title(
    r'Распределение $\xi_3=\xi_1+\xi_1\sim\mathcal{N}(-1 + 1, 3^2 + 4^2)$ ', 
    fontsize=20
)
plt.xlabel('Значение', fontsize=17)
plt.ylabel('Плотность', fontsize=17)
plt.legend(fontsize=16)
plt.show()

Пусть $\xi$ из $\mathcal{N}(a, \sigma^2)$. Тогда $\xi_{new} = c\xi\sim\mathcal{N}(c a, c^2 \sigma^2)$

In [39]:
sample = sps.norm(loc=5, scale=3).rvs(size=1000)
grid = np.linspace(-5, 30, 1000)

c = 2
new_sample = c*sample

plt.figure(figsize=(12,5))
plt.hist(new_sample, density=True, bins=30, alpha=0.6, 
         label=r'Гистограмма $\xi_{new} = c \xi$')
plt.plot(grid, sps.norm(c*5, c*3).pdf(grid), color='red', 
         lw=5, label=r'Плотность $\mathcal{N}(10, 36)$')
plt.title(
    r'Распределение $\xi_{new}=c \xi\sim\mathcal{N}(2\cdot5, 4\cdot9)$', 
    fontsize=20
)
plt.xlabel('Значение', fontsize=17)
plt.ylabel('Плотность', fontsize=17)
plt.legend(fontsize=16)
plt.show()

2.2 Равномерное распределение

${U}(a, b)$ — равномерное распределение.

Параметры в scipy.stats:

  • loc = $a$,
  • scale = $b-a$.

Свойства распределения:

  • математическое ожидание: $\frac{a+b}{2}$,
  • дисперсия: $\frac{(b-a)^2}{12}$.
In [40]:
show_pdf(
    pdf=sps.uniform.pdf, xmin=-0.5, xmax=1.5, ymax=2, grid_size=10000, 
    distr_name=r'$U(0, 1)$', loc=0, scale=1
)
In [41]:
grid = np.linspace(-3, 3, 10001)  # сетка для построения графика
sample = sps.uniform.rvs(size=1000)  # выборка размера 1000

plt.figure(figsize=(12, 5))
plt.hist(sample,  bins=30, density=True, alpha=0.6, 
         label='Гистограмма случайной величины') 
plt.plot(grid, sps.uniform.pdf(grid), color='red', lw=5, 
         label='Плотность случайной величины') 
plt.title(r'Случайная величина $\xi\sim U(0, 1)$', fontsize=20)
plt.xlim(-0.5, 1.5)
plt.legend(fontsize=14, loc=1)
plt.show()
In [42]:
# создать виджет, но не отображать его
ip = widgets.interactive(
    show_pdf,
    pdf=widgets.fixed(sps.uniform.pdf),
    grid_size=widgets.IntSlider(min=25, max=300, step=25, value=500),
    xmin=widgets.FloatSlider(min=-10, max=0, step=0.1, value=-5),
    xmax=widgets.FloatSlider(min=0, max=10, step=0.1, value=5),
    ymax=widgets.FloatSlider(min=0, max=2, step=0.1, value=1.4),
    loc=widgets.FloatSlider(min=-4, max=0, step=0.1, value=0),
    scale=widgets.FloatSlider(min=0.01, max=4, step=0.01, value=1),
    distr_name=r'$U$({loc}, {loc} + {scale})'
);

# отображаем слайдеры группами
display(widgets.HBox(ip.children[:2]))
display(widgets.HBox(ip.children[2:4]))
display(widgets.HBox(ip.children[5:7]))
# отображаем вывод функции
display(ip.children[-1])

ip.update()  # чтобы функция запустилась до первого изменения слайдеров
In [43]:
grid = np.linspace(-3, 7, 1000)  # сетка для построения графика
loc_values = [0, 0, 4]  # набор значений параметра a
scale_values = [1, 2, 1]  # набор значений параметра scale

plt.figure(figsize=(12, 5))
for i, (loc, scale) in enumerate(zip(loc_values, scale_values)):
    plt.plot(grid, sps.uniform(loc, scale).pdf(grid), lw=5, alpha=0.7, 
             label='$U' + '({}, {})$'.format(loc, scale))

plt.legend(fontsize=16)
plt.title('Плотности равномерного распределения', fontsize=20)
plt.xlabel('Значение', fontsize=18)
plt.ylabel('Плотность', fontsize=18)
plt.show()

Для равномерного распределения:

  • Параметр ${loc = a}$ определяет начало отрезка, на котором случайная величина равномерно распределена.
  • Параметр ${scale = b-a}$ определяет длину отрезка, на котором задана случайная величина. Значение плотности распределения на данном отрезке убывает с ростом данного параметра, то есть с ростом длины этого отрезка. Чем меньше длина отрезка, тем больше значение плотности вероятности на отрезке.