Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

М2

.docx
Скачиваний:
13
Добавлен:
03.06.2024
Размер:
5.1 Mб
Скачать

ГУАП

КАФЕДРА № 41

ОТЧЕТ

ЗАЩИЩЕН С ОЦЕНКОЙ

ПРЕПОДАВАТЕЛЬ

старший преподаватель Е.К. Григорьев

должность, уч. степень, звание подпись, дата инициалы, фамилия

ОТЧЕТ О ЛАБОРАТОРНОЙ РАБОТЕ № 2

МОДЕЛИРОВАНИЕ ГЕНЕРАТОРОВ НОРМАЛЬНО РАСПРЕДЕЛЕННЫХ ПСЕВДОСЛУЧАЙНЫХ ЧИСЕЛ

по курсу: МОДЕЛИРОВАНИЕ

РАБОТУ ВЫПОЛНИЛ

СТУДЕНТ ГР. № подпись, дата инициалы, фамилия

Санкт-Петербург 2024

1 Цель работы

Получить навыки моделирования нормально распределенных псевдослучайных чисел в программной среде MATLAB/GNU Octave, а также первичной оценки качества полученных псевдослучайных чисел.

2 Ход работы

Вариант 15

m = 6, = 1.

Вычислена плотность вероятности по формуле:

,

,

Построен график (Рисунок 1).

Рисунок 1 – График плотности распределения

Для получения функции распределения необходимо интегрировать функцию плотности вероятности распределения:

= ,

Интеграл такого рода не выражается. Для его нахождения используется функция Лапласа:

, тогда:

,

С помощью таблицы значений функции Лапласа и свойства рассчитаны значения функции распределения:

;

;

;

;

;

Построен график (Рисунок 2).

Рисунок 2 – График функции распределения

Также графики были построены с помощью языка программирования Python (Рисунок 3). Код представлен в листинге 1.

Рисунок 3 – Графики

Листинг 1 – Код для построения графиков

import numpy as np

import matplotlib.pyplot as plt

from scipy import integrate

m = 6

sigma = 1

def distribution_density(x, m, sigma):

coefficient = 1 / np.sqrt(2 * np.pi * sigma)

exponent = np.exp(-((x - m) ** 2) / (2 * sigma**2))

return coefficient * exponent

def standard_normal_distribution(t):

return np.exp(-t**2 / 2)

def laplace_integral(x):

result, _ = integrate.quad(standard_normal_distribution, -np.inf, x)

return (1 / np.sqrt(2 * np.pi)) * result

def distribution_func(x, m, sigma):

return 0.5 + 0.5* laplace_integral((x - m) / sigma)

x_values = np.linspace(m - 3 * np.sqrt(sigma), m + 3 * np.sqrt(sigma))

distribution_values = distribution_density(x_values, m, sigma)

plt.figure(figsize = (20, 8))

plt.subplot(121)

plt.plot(x_values, distribution_values)

plt.xlabel('x')

plt.ylabel('f(x)')

plt.title('График плотности распределения')

plt.grid(True)

X_values = np.linspace(m - 3 * sigma, m + 3 * sigma, 1000)

F_X_values = [distribution_func(x, m, sigma) for x in X_values]

plt.subplot(122)

plt.plot(X_values, F_X_values, color='green')

plt.title('График функции распределения')

plt.xlabel('x')

plt.ylabel('F(x)')

plt.grid(True)

plt.show()

Разработан алгоритм генерации псевдослучайных чисел, основанный на центральной предельное теореме (Листинг 2). Данный способ основан на том, что сумма n одинаково распределенных независимых случайных величин X со средним Mx и дисперсией Dx стремится к нормально распределенной величина с параметрами nMx, nDx, при бесконечном увеличении n. Формула представлена на рисунке 4.

Рисунок 4 – Формула для генерации, основанной основанного на центральной предельной теореме

Листинг 2 – Функция алгоритма, основанного на центральной предельной теореме

def uniform_to_normal(n, m, sigma):

    # Генерация равномерно распределенных чисел

    uniform_random_values = np.random.uniform(low=0.0, high=1.0, size=(n, 12))

    # Преобразование выборки равномерно распределенных чисел в выборку нормально распределенных

    normal_random_values = m + sigma * (np.sum(uniform_random_values, axis = 1) - 6)

   

    return normal_random_values

Разработан алгоритм генерации псевдослучайных чисел, основанный на преобразовании Бокса-Мюллера (Листинг 3). Этот метод позволяет генерировать сразу две независимые псевдослучайные величины со стандартным нормальным распределением. Формулы представлены на рисунке 5.

Рисунок 5 – Формулы преобразования Бокса-Мюллера

Листинг 3 – Функция преобразования Бокса-Мюллера

def box_muller_transformation(n, m, sigma):

    normal_random_numbers = []

    for _ in range(n // 2):

        # Генерация двух равномерно распределенных случайных величин

        r1, r2 = np.random.uniform(low=0.0, high=1.0, size=2)

        # Выполнение преобразования

        z0 = np.cos(2 * np.pi * r1) * np.sqrt(-2 * np.log(r2))

        z1 = np.sin(2 * np.pi * r1) * np.sqrt(-2 * np.log(r2))

       

        normal_random_numbers.extend([m + sigma * z0, m + sigma * z1])

   

    return np.array(normal_random_numbers)

Разработан алгоритм генерации псевдослучайных чисел, полярном методе Марсальи (Листинг 4). Метод представляет собой оптимизированную версию преобразования Бокса-Мюллера, где нет необходимости вычислять функции cos() и sin(). Формулы представлены на рисунке 6.

Рисунок 6 – Формулы полярного метода Марсальи

Листинг 4 – Функция полярного метода Марсальи

def marsaglia_polar_method(n, m, sigma):

    normal_random_numbers = []

    for _ in range(n):

        # Генерация пары равномерно распределенных чисел

        x, y = np.random.uniform(-1, 1, size=2)

        s = x**2 + y**2

        # Отбрасывание s, не попадающих в [0; 1]

        while s >= 1 or s == 0:

            x, y = np.random.uniform(-1, 1, size=2)

            s = x**2 + y**2

        z0 = np.sqrt(-2 * np.log(s) / s) * x

        z1 = np.sqrt(-2 * np.log(s) / s) * y

       

        normal_random_numbers.extend([m + sigma * z0, m + sigma * z1])

   

    return np.array(normal_random_numbers)

Разработан алгоритм генерации псевдослучайных чисел, с помощью встроенной функции генерации (Листинг 5).

Листинг 5 – Генерация с помощью встроенной функции

def numpy_random(n, m, sigma):

    standard_normal_random_numbers = np.random.randn(n)

    normal_random_numbers = m + sigma * standard_normal_random_numbers

   

    return normal_random_numbers

Для каждого алгоритма генерации сгенерированы выборки по 1000, 5000 и 10000 чисел. Для каждого набора случайных чисел построены графики: гистограмма, график эмпирической функции, распределение на плоскости, «квантиль-квантиль» (Рисунок 7 - 10).

Рисунок 7 – Гистограммы

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

Рисунок 8 – Графики эмпирической функции

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

Рисунок 9 – Распределение на плоскости

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

Рисунок 10 – Графики «квантиль-квантиль»

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

Для каждого набора случайных чисел вычислены метрики (Рисунок 11).

Рисунок 11 – Метрики

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

Код для построения графиков и вычисления метрик представлен в листинге 6.

Листинг 6 – Построение графиков и вычисление метрик

def randomizer(generator, n):

    if generator == 'Предельная центральная теорема':

        result = uniform_to_normal(n, m, sigma)

    elif generator == 'Преобразование Бокса-Мюллера':

        result = box_muller_transformation(n, m, sigma)

    elif generator == 'Полярный метод Марсальи':

        result = marsaglia_polar_method(n, m, sigma)        

    elif generator == 'Встроенная функция':

        result = numpy_random(n, m, sigma)

    return result

amounts = [1000, 5000, 10000]

colors = ['red', 'purple', 'blue']

generators = ['Предельная центральная теорема', 'Преобразование Бокса-Мюллера', 'Полярный метод Марсальи', 'Встроенная функция']

records = []

for i, amount in enumerate(amounts):

    for j, generator in enumerate(generators):

       

        random = randomizer(generator, amount)

        x = np.linspace(min(random), max(random), amount)

        ecdf = ECDF(random)

        y = ecdf(x)

       

        # Гистограмма

        plt.figure(1, figsize=(24, 18))

        plt.subplot(3, 4, i * 4 + j + 1)

        plt.hist(random, bins=50, color=colors[i], alpha = 0.7)

        plt.title(f'{amount}, {generator}', fontsize = 14)

        plt.xlabel('Value', fontsize = 16)

        plt.ylabel('Frequency', fontsize = 16)

        plt.grid(True)

                 

        # График ECDF

        plt.figure(2, figsize=(24, 18))

        plt.subplot(3, 4, i * 4 + j + 1)

        plt.plot(x, y, colors[i])

        plt.title(f'{amount}, {generator}', fontsize=14)

        plt.xlabel('Values', fontsize=18)

        plt.ylabel('ECDF', fontsize=18)

        plt.legend([str(amount)], fontsize=14, loc='lower right')

        plt.grid(True)

       

        random_shifted = np.roll(random, -1)

        # Диаграмма рассеивания

        plt.figure(3, figsize=(24, 18))

        plt.subplot(3, 4, i * 4 + j + 1)

        plt.scatter(random, random_shifted, s=3, c=colors[i], label=f'{amount}')

        plt.title(f'{amount}, {generator}', fontsize=14)

        plt.xlabel('Values', fontsize=18)

        plt.ylabel('Values', fontsize=18)

        plt.legend(loc='lower right')

        plt.grid(True)

       

        mean_val = round(np.mean(random), 3)

        var_val = round(np.var(random), 3)

        std_val = round(np.std(random), 3)

        record = {

            'Количество': amount,

            'Генератор': generator,

            'Мат. ожидание': mean_val,

            'Дисперсия': var_val,

            'Среднекв. откл.':std_val

        }

        records.append(record)

fig, axes = plt.subplots(len(amounts), len(generators), figsize=(24, 18))

for i, amount in enumerate(amounts):

    for j, generator in enumerate(generators):

       

        random = randomizer(generator, amount)

        x = np.linspace(min(random), max(random), amount)

       

        sm.qqplot(random, ax=axes[i, j], line='s', label=f'{amount}, {generator}',  alpha=0.5)

        axes[i, j].set_title(f'{amount}, {generator}', fontsize=12)

        axes[i, j].set_xlabel('Теоретические квантили', fontsize=12)

        axes[i, j].set_ylabel('Квантили исследуемой выборки', fontsize=12)

        axes[i, j].grid(True)

# Вычисление метрик аналитически

mean_analytical = m

variance_analytical = sigma**2

std_analytical = sigma

records.append({

            'Количество': "Аналитически",

            'Генератор': "Нормальное распределение",

            'Мат. ожидание': mean_analytical,

            'Дисперсия': variance_analytical,

            'Среднекв. откл.':std_analytical

    })

plt.show()

df = pd.DataFrame(records)

display(df)

3 Вывод

В ходе выполнения лабораторной работы построены графики плотности распределения и функции распределения для нормального распределения. С помощью программных средств реализованы генераторы нормально распределенных псевдослучайных чисел, основанные на центральной предельной теореме, преобразовании Бокса-Мюллера, полярном методе Марсальи и встроенной функции генерации. Сгенерированы выборки по 1000, 5000 и 10000 чисел, построены графики, вычислены метрики. Все генераторы показали значения метрик, близкие к аналитическим, генераторы работают стабильно.

Соседние файлы в предмете Моделирование