Книга Изучаем Python
Скачать 4.68 Mb.
|
326 Глава 15 • Генерирование данных В этом примере создается случайное блуждание из 50 000 точек (что в большей степени соответствует реальным данным), и каждая точка рисуется с размером s =1. Как видно из рис. 15.10, изображение получается эфемерным и туманным. Простая точечная диаграмма превратилась в произведение искусства! Поэкспериментируйте с этим кодом и посмотрите, насколько вам удастся увели- чить количество точек в случайном блуждании, прежде чем система начнет заметно «тормозить» или диаграмма потеряет свою визуальную привлекательность. Рис. 15.10. Случайное блуждание из 50 000 точек Изменение размера диаграммы для заполнения экрана Визуализация гораздо эффективнее передает закономерности в данных, если она адаптирована под размер экрана. Чтобы диаграмма лучше смотрелась на экране, измените размер области просмотра matplotlib : rw_visual.py while True: # Make a random walk, and plot the points. rw = RandomWalk() rw.fill_walk() # Назначение размера области просмотра. plt.figure(figsize=(10, 6)) Функция figure() управляет шириной, высотой, разрешением и цветом фона диаграммы. Параметр figsize получает кортеж с размерами окна диаграммы в дюймах. Моделирование бросков кубиков в Pygal 327 Python предполагает, что разрешение экрана составляет 80 пикселов на дюйм; если этот код не дает точного размера, внесите необходимые изменения в числа. Или, если вы знаете разрешение экрана в вашей системе, передайте его figure() в параметре dpi для выбора размера, эффективно использующего доступное про- странство: plt.figure(dpi=128, figsize=(10, 6)) УПРАЖНЕНИЯ 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(): x_step = get_step() y_step = get_step() Рефакторинг сокращает размер fill_walk(), а метод становится более простым и понятным . Моделирование бросков кубиков в Pygal В этом разделе мы воспользуемся пакетом визуализации Pygal для создания фай- лов с масштабируемой векторной графикой. Такие файлы хорошо подходят для визуализаций, имеющих разное представление на экранах разного размера, потому что изображение автоматически масштабируется по размерам экрана зрителя. Если вы собираетесь использовать свои визуализации в веб-приложениях, Pygal будет хорошим вариантом; ваша работа будет хорошо смотреться на любом устройстве, которое будет использоваться для просмотра ваших визуализаций. В этом проекте мы займемся анализом результатов бросков кубиков. При броске одного шестигранного кубика существует равная вероятность выпадения любого числа от 1 до 6. С другой стороны, при броске двух кубиков некоторые суммы выпадают с большей вероятностью, чем другие. Чтобы определить, какие числа наиболее вероятны, мы сгенерируем набор данных, представляющих брошенные кубики. Затем на базе данных большого количества бросков будет построена диаграмма, по которой можно определить, какие результаты более вероятны. Броски кубиков часто используются в математике для пояснения различных типов анализа данных. Впрочем, они также находят применение в реальных приложе- ниях — скажем, в казино и в обычных играх («Монополия», ролевые игры и т. д.). 328 Глава 15 • Генерирование данных Установка Pygal Установите Pygal при помощи pip . (Если вы еще не использовали pip , обратитесь к разделу «Установка пакетов Python с использованием pip» на с. 227.) В системах Linux и OS X команда должна выглядеть примерно так: pip install --user pygal В системе Windows она выглядит так: python -m pip install --user pygal ПРИМЕЧАНИЕ Возможно, при установке пакетов вам придется использовать команду pip3 вместо pip . Если же эта команда не работает, попробуйте исключить флаг --user . Галерея Pygal Примеры визуализаций, которые могут быть построены с использованием Pygal, представлены в галерее диаграмм: зайдите на сайт http://www.pygal.org/, щелкните на ссылке Documentation , затем щелкните на ссылке Chart types . Каждый пример со- провождается исходным кодом, так что вы сможете увидеть, как была построена каждая из визуализаций. Создание класса кубика Для моделирования броска одного кубика мы будем использовать следующий класс: die.py from random import randint 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 и т. д.) Моделирование бросков кубиков в Pygal 329 Метод roll() использует функцию randint() для получения случайного числа в диапазоне от 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] Беглое знакомство с результатами показывает, что класс Die работает. В результа- тах встречаются граничные значения 1 и 6, то есть модель возвращает наименьшее и наибольшее возможное значение; значения 0 и 7 не встречаются, а значит, все результаты лежат в диапазоне допустимых значений. Также в выборке встречаются все числа от 1 до 6, то есть представлены все возможные результаты. Анализ результатов Чтобы проанализировать результаты бросков одного кубика D6, мы подсчитаем, сколько раз выпадало каждое число: die_visual.py # Моделирование серии бросков с сохранением результатов в списке. results = [] for roll_num in range(1000): result = die.roll() results.append(result) 330 Глава 15 • Генерирование данных # Анализ результатов. frequencies = [] for value in range(1, die.num_sides+1): frequency = results.count(value) frequencies.append(frequency) print(frequencies) Так как Pygal используется для анализа, а не для вывода результатов, количество моделируемых бросков можно увеличить до 1000 . Для анализа создается пустой список frequencies , в котором хранится количество выпадений каждого значения. Программа перебирает возможные значения (от 1 до 6 в данном случае) в цикле , подсчитывает количество вхождений каждого числа в результатах , после чего присоединяет полученное значение к списку frequencies . Содержимое списка выводится перед построением визуализации: [155, 167, 168, 170, 159, 181] Результаты выглядят разумно: мы видим все шесть частот, по одной для каждого возможного результата при броске D6, и ни одна из частот не выделяется на общем фоне. А теперь займемся наглядным представлением результатов. Построение гистограммы Имея список частот, можно построить гистограмму результатов. Гистограмма пред- ставляет собой столбцовую диаграмму, наглядно отображающую относительные частоты результатов. Код построения гистограммы выглядит так: die_visual.py import pygal # Анализ результатов. frequencies = [] for value in range(1, die.num_sides+1): frequency = results.count(value) frequencies.append(frequency) # Визуализация результатов. hist = pygal.Bar() hist.title = "Results of rolling one D6 1000 times." hist.x_labels = ['1', '2', '3', '4', '5', '6'] hist.x_title = "Result" hist.y_title = "Frequency of Result" hist.add('D6', frequencies) hist.render_to_file('die_visual.svg') Чтобы построить столбцовую диаграмму, мы создаем экземпляр pygal.Bar() , ко- торый сохраняется в переменной hist . Затем мы задаем атрибут title объекта Моделирование бросков кубиков в Pygal 331 hist (обычная строка, используемая как заголовок гистограммы), используем воз- можные результаты броска D6 как метки оси x , а также добавляем надпись для каждой из осей. Метод add() используется для добавления на гистограмму серии значений (при этом ему передается метка для добавляемого набора и список значений, отображаемых на диаграмме). Наконец, диаграмма записывается в файл SVG, что предполагает имя файла с расширением .svg Полученную диаграмму проще всего просмотреть в браузере. Откройте новую вкладку в любом браузере, а в ней откройте файл die_visual .svg (из папки, в которой был сохранен файл die_visual .py ). Диаграмма должна выглядеть примерно так, как на рис. 15.11. (Мы слегка изменили изображение для печати; по умолчанию Pygal генерирует диаграммы с более темным фоном, чем на рисунке.) Рис. 15.11. Простая гистограмма, созданная с использованием Pygal Обратите внимание на интерактивность диаграмм, построенных с использованием Pygal: если навести указатель мыши на столбец диаграммы, вы увидите данные, связанные с этим столбцом. Данная возможность особенно полезна при нанесении нескольких наборов данных на одну диаграмму. Бросок двух кубиков При броске двух кубиков вы получаете большие значения с другим распределением результатов. Изменим наш код и создадим два кубика D6, моделирующих бросок пары кубиков. При броске каждой пары программа складывает два числа (по од- ному с каждого кубика) и сохраняет сумму в results . Сохраните копию die_visual . py под именем dice_visual .py и внесите следующие изменения: dice_visual.py import pygal 332 Глава 15 • Генерирование данных from die import Die # Создание двух кубиков D6. die_1 = Die() die_2 = Die() # Моделирование серии бросков с сохранением результатов в списке. results = [] for roll_num in range(1000): 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) # Визуализация результатов. hist = pygal.Bar() hist.title = "Results of rolling two D6 dice 1000 times." hist.x_labels = ['2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'] hist.x_title = "Result" hist.y_title = "Frequency of Result" hist.add('D6 + D6', frequencies) hist.render_to_file('dice_visual.svg') Создав два экземпляра Die , мы бросаем кубики и вычисляем сумму для каждого броска . Самый большой возможный результат (12) вычисляется суммировани- ем наибольших результатов на обоих кубиках; мы сохраняем его в max_result . Наименьший возможный результат равен сумме наименьших результатов на обоих кубиках. В процессе анализа подсчитывается количество результатов для каждого значения от 2 до max_result . (Также можно было использовать диапазон range(2, 13) , но он работал бы только для двух кубиков D6. При моделировании реальных ситуаций лучше писать код, который легко адаптируется для разных ситуаций. В частности, этот код позволяет смоделировать бросок пары кубиков с любым количеством граней.) При создании диаграммы мы задаем заголовок, метки оси x и серии данных . (Если бы список x_labels был намного длиннее, то его было бы удобнее сгенери- ровать автоматически в цикле.) После выполнения кода обновите в браузере вкладку с диаграммой; примерный вид диаграммы показан на рис. 15.12. На диаграмме показаны примерные результаты, которые могут быть получены для пары кубиков D6. Как видите, реже всего выпадают результаты 2 и 12, а чаще всего 7, потому что эта комбинация может быть выброшена шестью способами: 1+6, 2+5, 3+4, 4+3, 5+2 и 6+1. Моделирование бросков кубиков в Pygal 333 Рис. 15.12. Смоделированные результаты 1000 бросков двух шестигранных кубиков Броски кубиков с разным числом граней Создадим кубики с 6 и 10 гранями и посмотрим, что произойдет, если бросить их 50 000 раз: different_dice.py from die import Die import pygal # Создание кубиков 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) # Analyze the results. # Визуализация результатов. hist = pygal.Bar() hist.title = "Results of rolling a D6 and a D10 50,000 times." hist.x_labels = ['2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16'] hist.x_title = "Result" hist.y_title = "Frequency of Result" hist.add('D6 + D10', frequencies) 334 Глава 15 • Генерирование данных hist.render_to_file('dice_visual.svg') Чтобы создать модель кубика D10, мы передаем аргумент 10 при создании вто- рого экземпляра Die1 и изменяем первый цикл для моделирования 50 000 бросков вместо 1000. Наименьший возможный результат, как и прежде, равен 2, зато наи- больший увеличился до 16; мы соответственно изменяем заголовок, метки оси x и метки серии данных . На рис. 15.13 показана полученная диаграмма. Вместо одного наиболее вероят- ного результата их стало целых пять. Это объясняется тем, что наименьшее (1+1) и наибольшее (6+10) значения по-прежнему могут быть получены только одним способом, но кубик D6 ограничивает количество способов генерирования средних чисел: суммы 7, 8, 9, 10 и 11 можно выбросить шестью способами. Следовательно, именно эти результаты являются наиболее частыми, и все эти числа выпадают с равной вероятностью. Рис. 15.13. Результаты 50 000 бросков шести- и десятигранного кубиков Возможность применения Pygal для моделирования бросков кубиков дает суще- ственную свободу при исследовании этого явления. За считаные минуты вы смо- жете смоделировать огромное количество бросков с разнообразными кубиками. УПРАЖНЕНИЯ 15-6 . Автоматические метки: измените программы die .py и dice_visual .py . Замените список, используемый для задания значений hist .x_labels, циклом, автоматически генерирующим этот список . Если вы хорошо освоили генераторы списков, также попробуйте заменить другие циклы for в die_visual .py и dice_visual .py генераторами списков . Итоги 335 15-7 . Два кубика D8s: создайте модель, которая показывает, что происходит при 1000-крат- ном бросании двух восьмигранных кубиков . Постепенно наращивайте количество бросков, пока не начнете замечать ограничения, связанные с ресурсами вашей системы . 15-8 . Три кубика: при броске 3 кубиков D6 наименьший возможный результат равен 3, а наибольший — 18 . Создайте визуализацию, которая показывает, что происходит при бро- ске трех кубиков D6 . 15-9 . Умножение: при броске двух кубиков результат обычно определяется суммированием двух чисел . Создайте визуализацию, которая показывает, что происходит при умножении этих чисел . 15-10 . Эксперименты с библиотеками: попробуйте использовать matplotlib для создания ви- зуализации бросков кубиков, а Pygal — для создания визуализации случайного блуждания . Итоги В этой главе вы научились генерировать наборы данных и строить визуализа- ции этих данных. Вы научились строить простые диаграммы с использованием matplotlib и применять точечные диаграммы для анализа случайных блужданий. Вы узнали, как построить гистограмму с использованием Pygal и как исследовать результаты бросков кубиков с разным количеством граней при помощи гисто- граммы. Генерирование собственных наборов данных в программах — интересный и мощ- ный способ моделирования и анализа различных реальных ситуаций. В дальней- ших проектах визуализации данных обращайте особое внимание на ситуации, которые могут быть смоделированы на программном уровне. Присмотритесь к визуализациям, встречающимся в выпусках новостей, — возможно, они были сгенерированы методами, сходными с теми, о которых вы узнали в этих проектах? В главе 16 мы загрузим данные из сетевого источника и продолжим использовать matplotlib и Pygal для анализа данных. 16 Загрузка данных В этой главе мы загрузим наборы данных из сетевого источника и создадим рабо- тоспособные визуализации этих данных. В Интернете можно найти невероятно разнообразную информацию, бульшая часть которой еще не подвергалась осно- вательному анализу. Умение анализировать данные позволит вам выявить связи и закономерности, не найденные никем другим. В этой главе рассматривается работа с данными в двух популярных форматах, CSV и JSON. Модуль Python csv будет применен для обработки погодных данных в формате CSV (с разделением запятыми) и анализа динамики высоких и низких температур в двух разных местах. Затем библиотека matplotlib будет использована для построения на базе загруженных данных диаграммы изменения температур. Позднее в этой главе модуль json будет использован для обращения к данным численности населения, хранимым в формате JSON, а при помощи модуля Pygal будет построена карта распределения населения по странам. К концу этой главы вы будете готовы к работе с разными типами и форматами наборов данных и начнете лучше понимать принципы построения сложных визу- ализаций. Возможность загрузки и визуализации сетевых данных разных типов и форматов крайне важна для работы с разнообразными массивами данных в ре- альном мире. Формат CSV Один из простейших вариантов хранения — запись данных в текстовый файл как серий значений, разделенных запятыми; такой формат хранения получил название CSV (от Comma Separated Values, то есть «значения, разделенные запятыми»). На- пример, одна строка погодных данных в формате CSV может выглядеть так: 2014-1-5,61,44,26,18,7,-1,56,30,9,30.34,30.27,30.15,,,,10,4,,0.00,0,,195 Это погодные данные за 5 января 2014 г. в Ситке (Аляска). В данных указаны мак- симальная и минимальная температуры, а также ряд других показателей за этот день. У человека могут возникнуть проблемы с чтением данных CSV, но этот фор- мат хорошо подходит для программной обработки и извлечения значений, а это ускоряет процесс анализа. Начнем с небольшого набора погодных данных в формате CSV, запи- санного в Ситке; файл с данными можно загрузить среди ресурсов книги |