Главная страница
Навигация по странице:

  • УПРАЖНЕНИЯ 15.3. Молекулярное движение

  • 15.4. Измененные случайные блуждания

  • УПРАЖНЕНИЯ 15.6. Два кубика D8

  • 15.10. Эксперименты с библиотеками

  • Мэтиз. Изучаем Python. Crash course2 n d e d i t i o na h a n d s o n, p r o j e c t b a s e d i n t r o d u c t i o n t o p r o g r a m m i n g


    Скачать 6.2 Mb.
    НазваниеCrash course2 n d e d i t i o na h a n d s o n, p r o j e c t b a s e d i n t r o d u c t i o n t o p r o g r a m m i n g
    Дата28.06.2022
    Размер6.2 Mb.
    Формат файлаpdf
    Имя файлаМэтиз. Изучаем Python.pdf
    ТипДокументы
    #618322
    страница37 из 52
    1   ...   33   34   35   36   37   38   39   40   ...   52
    Рис. 15.11. Случайное блуждание c 50 000 точек

    Случайное блуждание 337
    Поэкспериментируйте с этим кодом и посмотрите, насколько вам удастся увели- чить количество точек в случайном блуждании, прежде чем система начнет заметно тормозить или диаграмма потеряет свою визуальную привлекательность.
    Изменение размера диаграммы для заполнения экрана
    Визуализация гораздо эффективнее передает закономерности в данных, если она адаптирована под размер экрана. Чтобы диаграмма лучше смотрелась на экране, измените размер области просмотра Matplotlib:
    rw_visual.py
    while True:
    # Построение случайного блуждания.
    rw = RandomWalk()
    rw.fill_walk()
    # Назначение размера области просмотра.
    plt.style.use('classic')
    fig, ax = plt.subplots(figsize=(15, 9))
    Функция figure()
    управляет шириной, высотой, разрешением и цветом фона диа- граммы. Параметр figsize получает кортеж с размерами окна диаграммы в дюймах.
    Matplotlib предполагает, что разрешение экрана составляет 100 пикселов на дюйм; если этот код не дает точного размера, внесите необходимые изменения в чис- ла. Или, если вы знаете разрешение экрана в вашей системе, передайте его plt.
    subplots()
    в параметре dpi для выбора размера, эффективно использующего до- ступное пространство:
    fig, ax = plt.subplots(figsize=(10, 6), dpi=128)
    УПРАЖНЕНИЯ
    15.3. Молекулярное движение: измените программу rw_visual .py и замените plt.scatter()
    вызовом plt.plot()
    . Чтобы смоделировать путь пыльцевого зерна на поверхности водя- ной капли, передайте значения rw.x_values и rw.y_values и включите аргумент linewidth
    Используйте 5000 точек вместо 50 000.
    15.4. Измененные случайные блуждания: в классе
    RandomWalk значения x_step и y_step ге- нерируются по единому набору условий. Направление выбирается случайно из списка
    [1,
    -1]
    , а расстояние — из списка
    [0, 1,
    2,
    3,
    4]
    . Измените значения в этих списках и посмо- трите, что произойдет с общей формой диаграммы. Попробуйте применить расширенный список вариантов расстояния (например, от 0 до 8) или удалите
    –1
    из списка направлений по оси x или y.
    15.5. Рефакторинг: метод fill_walk()
    получился слишком длинным. Создайте новый ме- тод с именем get_step()
    , который определяет расстояние и направление для каждого шага, после чего вычисляет этот шаг. В результате метод fill_walk()
    должен содержать два вы- зова get_step()
    :

    338 Глава 15 • Генерирование данных x_step = self.get_step()
    y_step = self.get_step()
    Рефакторинг сокращает размер fill_walk()
    , а метод становится более простым и понятным.
    Моделирование бросков кубиков в Plotly
    В этом разделе мы воспользуемся пакетом визуализации Plotly для построения ин- терактивных визуализаций. Пакет Plotly особенно хорошо подходит для визуализа- ций, которые будут отображаться в браузере, потому что изображение автоматически масштабируется по размерам экрана зрителя. Кроме того, Plotly генерирует интерак- тивные визуализации; когда пользователь наводит указатель мыши на некоторые элементы, на экране появляется расширенная информация об этом элементе.
    В этом проекте мы займемся анализом результатов бросков кубиков. При броске одного шестигранного кубика существует равная вероятность выпадения любого числа от 1 до 6. С другой стороны, при броске двух кубиков некоторые суммы выпадают с большей вероятностью, чем другие. Чтобы определить, какие числа наиболее вероятны, мы сгенерируем набор данных, представляющих брошенные кубики. Затем на базе данных большого количества бросков будет построена диа- грамма, по которой можно определить, какие результаты более вероятны.
    Броски кубиков часто используются в математике для пояснения различных типов анализа данных. Впрочем, они также находят применение в реальных приложе- ниях — скажем, в казино и в обычных играх («Монополия», ролевые игры и т. д.).
    Установка Plotly
    Установите Plotly при помощи pip по аналогии с тем, как это делалось с Matplotlib:
    $ python -m pip install --user plotly
    (Если при установке Matplotlib использовалась команда python3
    или другая, убе- дитесь в том, что в данном случае используется то же самое.)
    Примеры визуализаций, которые могут быть построены с использованием Plotly, представлены в галерее диаграмм: зайдите на сайт https://plot .ly/python/
    . Каждый пример сопровождается исходным кодом, так что вы сможете увидеть, как была построена каждая из визуализаций.
    Создание класса кубика
    Для моделирования броска одного кубика будет использоваться класс
    Die
    :
    die.py
    from random import randint

    Моделирование бросков кубиков в Plotly 339
    class Die():
    """Класс, представляющий один кубик."""

    def __init__(self, num_sides=6):
    """По умолчанию используется шестигранный кубик."""
    self.num_sides = num_sides def roll(self):
    """"Возвращает случайное число от 1 до числа граней."""

    return randint(1, self.num_sides)
    Метод
    __init__()
    получает один необязательный аргумент. Если при создании экземпляра кубика аргумент с количеством сторон не передается, по умолчанию создается шестигранный кубик. Если же аргумент присутствует, то переданное значение используется для определения количества граней . (Кубики принято обозначать по количеству граней: шестигранный кубик — D6, восьмигранный —
    D8 и т. д.)
    Метод roll()
    использует функцию randint()
    для получения случайного числа в диапазоне от 1 до количества граней . Функция может вернуть начальное зна- чение (1), конечное значение (
    num_sides
    ) или любое целое число в этом диапазоне.
    Бросок кубика
    Прежде чем строить визуализацию на основе этого класса, бросим кубик D6, вы- ведем результаты и убедимся в том, что они выглядят разумно:
    die_visual.py
    from die import Die
    # Создание кубика D6.

    die = Die()
    # Моделирование серии бросков с сохранением результатов в списке.
    results = []

    for roll_num in range(100):
    result = die.roll()
    results.append(result)
    print(results)
    В точке  создается экземпляр
    Die с шестью гранями по умолчанию. В точке  моделируются 100 бросков кубика, а результат каждого броска сохраняется в спи- ске results
    . Выборка выглядит примерно так:
    [4, 6, 5, 6, 1, 5, 6, 3, 5, 3, 5, 3, 2, 2, 1, 3, 1, 5, 3, 6, 3, 6, 5, 4,
    1, 1, 4, 2, 3, 6, 4, 2, 6, 4, 1, 3, 2, 5, 6, 3, 6, 2, 1, 1, 3, 4, 1, 4,
    3, 5, 1, 4, 5, 5, 2, 3, 3, 1, 2, 3, 5, 6, 2, 5, 6, 1, 3, 2, 1, 1, 1, 6,
    5, 5, 2, 2, 6, 4, 1, 4, 5, 1, 1, 1, 4, 5, 3, 3, 1, 3, 5, 4, 5, 6, 5, 4,
    1, 5, 1, 2]

    340 Глава 15 • Генерирование данных
    Беглое знакомство с результатами показывает, что класс
    Die работает. В результа- тах встречаются граничные значения 1 и 6, то есть модель возвращает наименьшее и наибольшее возможное значение; значения 0 и 7 не встречаются, а значит, все результаты лежат в диапазоне допустимых значений. Также в выборке встречаются все числа от 1 до 6, то есть представлены все возможные результаты.
    Анализ результатов
    Чтобы проанализировать результаты бросков одного кубика D6, мы подсчитаем, сколько раз выпадало каждое число:
    die_visual.py
    # Моделирование серии бросков с сохранением результатов в списке.
    results = []

    for roll_num in range(1000):
    result = die.roll()
    results.append(result)
    # Анализ результатов.
    frequencies = []

    for value in range(1, die.num_sides+1):

    frequency = results.count(value)

    frequencies.append(frequency)
    print(frequencies)
    Так как Plotly используется для анализа, а не для вывода результатов, количество моделируемых бросков можно увеличить до 1000 . Для анализа создается пустой список frequencies
    , в котором хранится количество выпадений каждого значения.
    Программа перебирает возможные значения (от 1 до 6 в данном случае) в цикле , подсчитывает количество вхождений каждого числа в результатах , после чего присоединяет полученное значение к списку frequencies
    . Содержимое списка выводится перед построением визуализации:
    [155, 167, 168, 170, 159, 181]
    Результаты выглядят разумно: мы видим все шесть частот, по одной для каждого возможного результата при броске D6, и ни одна из частот не выделяется на общем фоне. А теперь займемся наглядным представлением результатов.
    Построение гистограммы
    Имея список частот, можно построить гистограмму результатов. Гистограмма пред- ставляет собой столбцовую диаграмму, наглядно отображающую относительные частоты результатов. Код построения гистограммы выглядит так:

    Моделирование бросков кубиков в Plotly 341
    die_visual.py
    from plotly.graph_objs import Bar, Layout from plotly import offline from die import Die
    # Анализ результатов.
    frequencies = []
    for value in range(1, die.num_sides+1):
    frequency = results.count(value)
    frequencies.append(frequency)
    # Визуализация результатов.

    x_values = list(range(1, die.num_sides+1))

    data = [Bar(x=x_values, y=frequencies)]

    x_axis_config = {'title': 'Result'}
    y_axis_config = {'title': 'Frequency of Result'}

    my_layout = Layout(title='Results of rolling one D6 1000 times',
    xaxis=x_axis_config, yaxis=y_axis_config)

    offline.plot({'data': data, 'layout': my_layout}, filename='d6.html')
    Чтобы построить столбцовую диаграмму, необходимо создать столбец для каж- дого из возможных результатов. Эти результаты сохраняются в списке x_values
    , который начинается с 1 и заканчивается количеством граней кубика . Plotly не может получить результат функции range()
    напрямую, поэтому необходимо явно преобразовать диапазон в список при помощи функции list
    . Класс
    Bar из Plotly представляет набор данных, который будет форматироваться в виде столбцовой диаграммы . Класс должен быть заключен в квадратные скобки, поскольку набор данных может состоять из нескольких элементов.
    Для осей предусмотрены различные возможности настройки, и каждый параметр конфигурации сохраняется в виде элемента в словаре. На данный момент мы толь- ко задаем заголовок каждой оси . Класс
    Layout()
    возвращает объект, который за- дает макет и конфигурацию диаграммы в целом . Здесь также задается заголовок диаграммы и передаются словари конфигурации осей x
    и y
    Диаграмма строится вызовом функции offline.plot()
    . Этой функции пере- дается словарь с объектами данных и макета; она также получает имя файла для сохранения результата. В нашем примере результат сохраняется в файле с именем d6 .html
    При запуске программы die_visual .py должен открыться браузер с файлом d6 .html
    Если это не происходит автоматически, откройте новую вкладку в любом браузере, а затем откройте файл d6 .html
    (из папки, в которой был сохранен файл die_visual .py
    ).
    Диаграмма должна выглядеть примерно так, как на рис. 15.12. (Изображение было слегка изменено для печати; по умолчанию Plotly генерирует диаграммы с более темным фоном, чем на иллюстрации.)

    342 Глава 15 • Генерирование данных
    Рис. 15.12. Простая гистограмма, созданная с использованием Plotly
    Обратите внимание на интерактивность диаграмм, построенных с использованием
    Plotly: если навести указатель мыши на столбец диаграммы, вы увидите данные, связанные с этим столбцом. Данная возможность особенно полезна при нанесе- нии нескольких наборов данных на одну диаграмму. Также обратите внимание на кнопки в правом верхнем углу: они позволяют изменить масштаб визуализации и сохранить ее в графическом файле.
    Бросок двух кубиков
    При броске двух кубиков вы получаете большие значения с другим распределением результатов. Изменим наш код и создадим два кубика D6, моделирующих бросок пары кубиков. При броске каждой пары программа складывает два числа (по одно- му с каждого кубика) и сохраняет сумму в results
    . Сохраните копию die_visual .py под именем dice_visual .py и внесите следующие изменения:
    dice_visual.py
    from plotly.graph_objs import Bar, Layout from plotly import offline from die import Die
    # Создание двух кубиков D6.
    die_1 = Die()
    die_2 = Die()
    # Моделирование серии бросков с сохранением результатов в списке.
    results = []
    for roll_num in range(1000):

    Моделирование бросков кубиков в Plotly 343

    result = die_1.roll() + die_2.roll()
    results.append(result)
    # Анализ результатов.
    frequencies = []

    max_result = die_1.num_sides + die_2.num_sides

    for value in range(2, max_result+1):
    frequency = results.count(value)
    frequencies.append(frequency)
    # Визуализация результатов.
    x_values = list(range(2, max_result+1))
    data = [Bar(x=x_values, y=frequencies)]

    x_axis_config = {'title': 'Result', 'dtick': 1}
    y_axis_config = {'title': 'Frequency of Result'}
    my_layout = Layout(title='Results of rolling two D6 dice 1000 times',
    xaxis=x_axis_config, yaxis=y_axis_config)
    offline.plot({'data': data, 'layout': my_layout}, filename='d6_d6.html')
    Создав два экземпляра
    Die
    , мы бросаем кубики и вычисляем сумму для каждого броска . Самый большой возможный результат (12) вычисляется суммировани- ем наибольших результатов на обоих кубиках; мы сохраняем его в max_result
    .
    Наименьший возможный результат (2) равен сумме наименьших результатов на обоих кубиках. В процессе анализа подсчитывается количество результатов для каждого значения от 2 до max_result
    . (Также можно было использовать диапазон range(2,
    13)
    , но он работал бы только для двух кубиков D6. При моделировании реальных ситуаций лучше писать код, который легко адаптируется для разных ситуаций. В частности, этот код позволяет смоделировать бросок пары кубиков с любым количеством граней.)
    При создании диаграммы мы включаем ключ dtick в словарь x_axis_config
    .
    Этот параметр управляет расстоянием между делениями на оси x. С появлением дополнительных столбцов на гистограмме в конфигурации по умолчанию Plotly будет снабжать метками только часть столбцов. Параметр 'dtick':
    1
    приказывает
    Plotly помечать все деления. Также мы обновляем заголовок диаграммы и изме- няем имя выходного файла.
    После выполнения кода в браузере должна появиться диаграмма, примерный вид которой показан на рис. 15.13.
    На диаграмме показаны примерные результаты, которые могут быть получены для пары кубиков D6. Как видите, реже всего выпадают результаты 2 и 12, а чаще всего 7, потому что эта комбинация может быть выброшена шестью способами, а именно: 1+6, 2+5, 3+4, 4+3, 5+2 и 6+1.
    Броски кубиков с разным числом граней
    Создадим кубики с 6 и 10 гранями и посмотрим, что произойдет, если бросить их
    50 000 раз:

    344 Глава 15 • Генерирование данных
    Рис. 15.13. Смоделированные результаты 1000 бросков двух шестигранных кубиков
    dice_visual.py
    from plotly.graph_objs import Bar, Layout from plotly import offline from die import Die
    # Создание кубиков D6 и D10.
    die_1 = Die()

    die_2 = Die(10)
    # Моделирование серии бросков с сохранением результатов в списке.
    results = []
    for roll_num in range(50000):
    result = die_1.roll() + die_2.roll()
    results.append(result)
    # Анализ результатов.
    # Визуализация результатов.
    X_values = list(range(2, max_result+1))
    data = [Bar(x=x_values, y=frequencies)]
    x_axis_config = {'title': 'Result', 'dtick': 1}
    y_axis_config = {'title': 'Frequency of Result'}

    my_layout = Layout(title='Results of rolling a D6 and a D10 50000 times',
    xaxis=x_axis_config, yaxis=y_axis_config)
    offline.plot({'data': data, 'layout': my_layout}, filename='d6_d10.html')
    Чтобы создать модель кубика D10, мы передаем аргумент 10 при создании второго экземпляра
    Die
     и изменяем первый цикл для моделирования 50 000 бросков

    Моделирование бросков кубиков в Plotly 345
    вместо 1000. Наименьший возможный результат, как и прежде, равен 2, зато наи- больший увеличился до 16; мы соответственно изменяем заголовок, метки оси x
    и метки серии данных .
    На рис. 15.14 показана полученная диаграмма. Вместо одного наиболее вероят- ного результата их стало целых пять. Это объясняется тем, что наименьшее (1+1) и наибольшее (6+10) значения по-прежнему могут быть получены только одним способом, но кубик D6 ограничивает количество способов генерирования средних чисел: суммы 7, 8, 9, 10 и 11 можно выбросить шестью способами. Следовательно, именно эти результаты являются наиболее частыми и все эти числа выпадают с равной вероятностью.
    Рис. 15.14. Результаты 50 000 бросков шести- и десятигранного кубиков
    Возможность применения Plotly для моделирования бросков кубиков дает су- щественную свободу при исследовании этого явления. За считаные минуты вы сможете смоделировать огромное количество бросков с разнообразными куби- ками.
    УПРАЖНЕНИЯ
    15.6. Два кубика D8: создайте модель, которая показывает, что происходит при 1000-крат- ном бросании двух восьмигранных кубиков. Попробуйте заранее представить, как будет выглядеть визуализация, перед моделированием; проверьте правильность своих интуитив- ных представлений. Постепенно наращивайте количество бросков, пока не начнете заме- чать ограничения, связанные с ресурсами вашей системы.
    15.7. Три кубика: при броске трех кубиков D6 наименьший возможный результат равен
    3, а наибольший — 18. Создайте визуализацию, которая показывает, что происходит при броске трех кубиков D6.

    346 Глава 15 • Генерирование данных
    15.8. Умножение: при броске двух кубиков результат обычно определяется суммировани- ем двух чисел. Создайте визуализацию, которая показывает, что происходит при умноже- нии этих чисел.
    15.9. Генераторы: для наглядности в списках этого раздела используется длинная форма цикла for
    . Если вы уверенно работаете с генераторами списков, попробуйте написать гене- ратор для одного или обоих циклов в каждой из этих программ.
    15.10. Эксперименты с библиотеками: попробуйте использовать Matplotlib для создания визуализации бросков кубиков, а Plotly — для создания визуализации случайного блужда- ния. (Для выполнения этого упражнения вам придется обратиться к документациям обеих библиотек.)
    Итоги
    В этой главе вы научились генерировать наборы данных и строить визуализа- ции этих данных. Вы научились строить простые диаграммы с использованием
    Мatplotlib и применять точечные диаграммы для анализа случайных блужданий.
    Вы узнали, как построить гистограмму с использованием Plotly и как исследовать результаты бросков кубиков с разным количеством граней при помощи гистограм- мы.
    Генерирование собственных наборов данных в программах — интересный и мощ- ный способ моделирования и анализа различных реальных ситуаций. В дальней- ших проектах визуализации данных обращайте особое внимание на ситуации, которые могут быть смоделированы на программном уровне. Присмотритесь к визуализациям, встречающимся в выпусках новостей, — возможно, они были сгенерированы методами, сходными с теми, о которых вы узнали в этих проектах?
    В главе 16 мы загрузим данные из сетевого источника и продолжим использовать
    Мatplotlib и Plotly для анализа данных.

    1   ...   33   34   35   36   37   38   39   40   ...   52


    написать администратору сайта