Руководство по проекту для начинающих в области науки о данных с использованием данных League of Legends
Введение
В первый раз, когда я построил гистограмму, я не мог сразу понять , как добавлять метки к столбцам. Особенно беспокоили меня горизонтальные гистограммы. Так что не беспокойтесь, если у вас тоже не получается заставить его работать . В этом посте вы узнаете, как это делается, а также несколько советов и приемов. для стилизации диаграммы.
ПРИМЕЧАНИЕ. Если вам нужно только увидеть, как добавлять метки, вы можете пропустить раздел: Создание гистограмм с метками.
Я включил весь код, который я написал для вас, чтобы вы могли его скопировать, если вы хотите печатать во время чтения, а также подробные объяснения того, как работает код.
Чтобы научить вас создавать гистограммы с метками, мне потребовались некоторые данные для работы. Поэтому я решил взять некоторые игровые данные из онлайн-игры League of Legends . Это делает руководство более интересным для поклонников игры, (включая меня) . Первая часть сообщения - это прогулка по тому, как я очищаю данные, чтобы привести их в предпочтительный для меня формат. Я рекомендую вам прочитать эту часть, а также она учит вас конвертировать данные из формата JSON в Pandas DataFrame.
Пост имеет следующую структуру:
- Введение
- Подготовка данных (JSON в Pandas DataFrame)
- Создание гистограмм с ярлыками
- Резюме и до свидания
Подготовка данных (JSON в Pandas DataFrame)
У меня есть файл JSON, содержащий базовую статистику (характеристики) всех чемпионов (игровых персонажей) в League of Legends. Вы можете получить доступ к файлу данных здесь. Данные выглядят так (см. снимок экрана):
Всего есть 153 чемпиона, которые все включают одни и те же ключи в свои словари.
В конечном итоге мы создадим гистограмму, которая покажет начальные hp (очки жизни) чемпионов, чтобы получить представление о том, какие чемпионы в начале имеют наибольшее здоровье. Если вам интересна другая статистика, вам будет очень легко изменить то, что показывает гистограмма, например, вам может быть интересно узнать, у каких чемпионов больше всего рекламы (урон от атаки).
Затем я хотел бы вместо этого преобразовать эти данные из формата JSON, в котором они сейчас находятся, в Pandas DataFrame.
Я призываю вас попробовать кодировать, так как это даст вам лучшее понимание! Учиться на собственном опыте.
import pandas as pd import matplotlib.pyplot as plt import json
Я начинаю с импорта необходимых библиотек, которые мы будем использовать. Pandas
позволяет нам создавать DataFrames
, что является хорошей структурой для работы, когда мы занимаемся наукой о данных. Matplotlib.pyplot
будет использоваться для построения диаграмм. json
позволит вам загрузить данные из файла JSON в память, чтобы мы могли с ними работать.
with open('champ_stats.json') as f: data = json.load(f) champion = data['Aatrox'] stat_names = list(champion.keys()) columns = ['champ'] + stat_names df = pd.DataFrame()
Я открываю файл данных и загружаю его в переменную data
. Затем я хотел бы иметь список, содержащий названия всех различных характеристик (статистика / характеристики чемпиона), так как это будут имена столбцов для готового DataFrame. Список статистики включен во все словари чемпионов в данных, поэтому нам просто нужно погрузиться в один из них и взять ключи из этого словаря. Мы получаем доступ к клавише 'Aatrox'
, поскольку это первый защитник данных. Это дает нам соответствующее значение, которое мы сохраняем в переменной champion
. Это значение - еще один словарь, в котором все ключи - это имена, которые мы ищем, поэтому мы используем функцию .keys()
для получения ключей, а возвращаемое значение преобразуется в список, поскольку функция была вызвана внутри функции list()
. Если этот шаг вас смущает, я написал другое руководство, в котором объясняется, как получить доступ к данным в словарях Python, которые вы можете найти здесь.
Имена столбцов для DataFrame будут 'champ'
для первого столбца, который будет содержать все имена чемпионов, а другие столбцы будут названы в соответствии с элементами в stat_names
. Мы сохраняем это в переменной columns
. Наконец, мы используем pd.DataFrame()
, чтобы создать пустой DataFrame, который мы сохраняем в переменной df
.
for name, stats in data.items(): values = [stats[x] for x in columns[1:]] row = pd.DataFrame([[name] + values], columns=columns) df = df.append(row) df.head()
На предыдущем шаге у нас был пустой DataFrame, и теперь пора заполнить его строками данных, где каждая строка представляет чемпиона. Теперь мы создаем оператор for, который перебирает все пары ключ-значение в словаре данных, (name
- ключ, а stats
- значение ). Нам нужен список всех значений статистики, и для его получения я использую понимание списка и сохраняю полученный список в переменной values
. Понимание списка работает следующим образом: для каждого имени (x
) в columns[1:]
мы берем это имя и используем его в качестве ключа для доступа к соответствующему значению из stats
, и это значение добавляется в список.
Затем мы создаем новый DataFrame, который сохраняем в переменной row
. Этот DataFrame создается с двумя параметрами. Во-первых, список внутри списка, где внутренний список содержит имя и все значения для текущего чемпиона. Во-вторых, формальный атрибут columns=
установлен в нашу переменную списка, также называемую columns
, это установит имена столбцов в DataFrame так, как мы хотим.
Затем мы добавляем row
к основному DataFrame, который мы назвали df
, это возвращает новый DataFrame, с помощью которого мы переопределяем предыдущий df
.
Наконец, мы вызываем метод head()
на df
для отображения первых строк DataFrame. Если вы написали код, вы должны получить следующий результат:
Данные теперь красиво отформатированы как DataFrame, и на следующем шаге мы, наконец, создадим гистограммы и добавим метки.
Создание гистограмм с метками
df_sorted_by_hp = df.sort_values('hp', ascending=False) x = df_sorted_by_hp['champ'][:15] y = df_sorted_by_hp['hp'][:15]
Чтобы улучшить диаграмму, я решил отсортировать строки в DataFrame по значению 'hp'
, а ascending=False
сортирует значения в порядке убывания. После этого мы сохраняем столбец чемпионов в переменную с именем x
и аналогично значения hp в переменную y
. Чтобы диаграмма не была слишком загромождена, я решил включить только первых 15 чемпионов, это сделано с суффиксом [:15]
.
fig, ax = plt.subplots(figsize=(20,4)) bars = ax.bar(x, y, width=0.5)
Мы используем plt.subplots(figsize=(20,4))
для создания объекта фигуры и объекта оси, которые сохраняются в переменных fig
и ax
. Мы установили размер фигуры 20 на 4 дюйма, это может быть не самый лучший размер, но вы можете поиграть с числами, пока не выясните, какой размер лучше всего подходит для вашей диаграммы. ax.bar(x, y, width=0.5)
создает гистограмму со значениями x
и y
и width
равным 0,5, опять же, вы можете попробовать разные размеры от 0 до 1 для ширины. Я сохраняю возвращенный объект в переменной bars
, которую мы вскоре будем использовать.
Код создаст следующую диаграмму, (только ее часть, чтобы она лучше подходила на Medium):
… Не очень круто
Во-первых, очень сложно различить разницу в высоте столбцов, а во-вторых, невозможно определить точную высоту каждой планки. Вот тут и пригодятся ярлыки!
Давайте добавим их сейчас!
Примечание. Добавьте следующий фрагмент кода к предыдущему.
for bar in bars: height = bar.get_height() label_x_pos = bar.get_x() + bar.get_width() / 2 ax.text(label_x_pos, height, s=f'{height}', ha='center', va='bottom')
Мы можем перебрать переменную bars
, чтобы пройти по каждому столбцу на графике. Мы сохраняем высоту каждой полосы в переменной с именем height
, получая ее из функции bar.get_height()
. Затем нам нужна позиция x для метки текущего бара в цикле. Мы получаем эту позицию из функции bar.get_x()
и складываем ширину полосы, разделенную на 2, чтобы получить значение x для центра полосы.
Наконец, мы используем ax.text(label_x_pos, height, s=f'{height}', ha='center')
для создания метки / текста. Эта функция принимает значение для позиции x и одно для позиции y, затем мы даем ей строку, которую она будет отображать, которая в данном случае является высотой полосы. Наконец, ha='center'
дополнительно помогает выровнять метку по центру полосы, а va='bottom'
помещает метку прямо над полосой.
В результате будет получена следующая диаграмма, (только ее часть, чтобы она лучше подходила для Medium):
Да! Теперь у нас есть метки для полос, отображающие их индивидуальную высоту!
Это явно лучше, но все еще можно улучшить.
Я думаю, что имена под полосками немного трудно читать из-за их размера. Также я хотел бы заголовок для диаграммы вместе с описанием осей. Кроме того, нет смысла начинать ось y с нуля. Наконец, я думаю, диаграмму можно было бы приправить цветом!
Примечание. Добавьте следующий фрагмент кода к предыдущему.
for tick in ax.xaxis.get_major_ticks(): tick.label.set_fontsize(14) for bar in bars[::2]: bar.set_color('r') plt.title('The 15 champions with the most HP') plt.xlabel('Champion name') plt.ylabel('Starting hp') plt.ylim([550,650]) plt.show()
Вы можете установить размер шрифта для каждого тика, перебирая тики, возвращаемые из ax.xaxis.get_major_ticks()
, и предоставляя размер шрифта с помощью tick.label.set_fontsize(14)
. Точно так же вы можете получить доступ к каждой второй полосе с помощью for bar in bars[::2]:
и установить цвет с помощью bar.set_color('r')
. Заголовок, метка x и метка y могут быть установлены с соответствующими функциями. Наконец, вы можете ограничить ось y (то же самое и для оси x) с помощью plt.ylim([550, 650])
. Я считаю, что начиная с 550 и заканчивая 650 работала эта диаграмма.
plt.show()
покажет готовую линейчатую диаграмму, (только ее часть, чтобы она лучше соответствовала среднему уровню):
Думаю, это большое улучшение!
Чтобы создать горизонтальную гистограмму, нам нужно очень немного изменить. По этой причине я покажу код в одном фрагменте и выделю изменения полужирным шрифтом. Также имейте в виду, что данные те же, что и раньше, и поэтому у нас все еще есть все имена в переменной x
и все значения hp в переменной y
.
fig, ax = plt.subplots(figsize=(4, 10)) bars = ax.barh(x,y, 0.5) for bar in bars: width = bar.get_width() #Previously we got the height label_y_pos = bar.get_y() + bar.get_height() / 2 ax.text(width, label_y_pos, s=f'{width}', va='center') for tick in ax.yaxis.get_major_ticks(): tick.label.set_fontsize(14) for bar in bars[::2]: bar.set_color('r') plt.title('The 15 champions with the most HP') plt.xlabel('Starting hp') plt.ylabel('Champion name') plt.xlim([550, 650]) plt.show()
Как и раньше, мы создаем объекты фигуры и осей и устанавливаем размер, однако на этот раз размер (4, 10) работает лучше (выше, чем в ширину). Чтобы создать горизонтальную гистограмму, мы используем ax.barh()
вместо ax.bar()
. Затем вместо высоты каждой полосы мы получаем ширину. Нам нужно получить позицию y полосок, используя bar.get_y()
вместо позиции x, и мы добавляем высоту полосы, деленную на 2, (обратите внимание, что высота здесь имеет другое значение по сравнению с предыдущим) .
Мы снова устанавливаем метку для панели с ax.text()
, однако мы используем width
для позиции x и для отображаемой строки. Кроме того, мы используем аргумент va='center'
, это помогает разместить метку в центре полосы. Попробуйте удалить его, чтобы увидеть разницу.
Для тактов мы просто изменяем размер y тактов вместо x. Наконец, вам нужно поменять метки для осей, а также ограничить ось x по отношению к оси y.
Результат:
Вуаля, теперь вы знаете, как создавать как вертикальные, так и горизонтальные гистограммы, а также добавлять метки, чтобы сделать их более читаемыми.
Резюме
Если вы следовали всему руководству, то теперь вы создали небольшой проект, в котором вы преобразовали данные JSON в Pandas DataFrame, а затем создали гистограммы с метками.
Лично я предпочитаю горизонтальную гистограмму, поскольку мне легче читать в этом случае.
Помните, что вы можете продолжить изучение данных, если вам интересно. Попробуйте выяснить, у какого чемпиона меньше всего здоровья, или покажите больше чемпионов в своих таблицах.
Если у вас есть какие-либо вопросы, комментарии или советы по улучшению публикации, не стесняйтесь обращаться ко мне!
Спасибо, что нашли время прочитать этот пост, надеюсь, вы узнали что-то полезное!
Продолжайте учиться!
- Якоб Тофтгаард Расмуссен