Исходный размер 2480x3500

League of Legends: Чемпионат мира 2020

Мне очень нравится играть в игры

big
Исходный размер 1344x768

Тема чемпионов League of Legends была выбрана благодаря интересу к киберспортивной аналитике и профессиональной сцене игры. Мне было интересно взглянуть на них не только с игровой, но и с аналитической стороны — выявить скрытые закономерности: эффективность чемпионов на турнирах, влияние стороны карты на результат, связь пикрейта с винрейтом. Этот проект позволил объединить любовь к киберспорту с навыками анализа данных.

big
Исходный размер 1344x768

В рамках проекта был проведен анализ данных чемпионов League of Legends с турнира Worlds Championship. Интерес к киберспортивной аналитике и профессиональной игровой сцене определил выбор темы. В процессе исследования удалось выявить ключевые закономерности: распределение побед между сторонами карты, корреляцию пикрейта и винрейта, а также наиболее эффективных чемпионов турнира. Проект стал удачным примером объединения увлечения киберспортом с профессиональными навыками анализа данных.

Для визуализации данных я планирую использовать следующие типы графиков: • Тепловая карта • Столбчатая диаграмма • Круговая диаграмма • Точечный график (scatter plots)

Визуальное оформление

Графики оформлены в оттенках игры, соответствующем тематике цветов.

Исходный размер 2139x406

Загрузка данных

Для работы я импортировала библиотеки: pandas для работы с данными, matplotlib.pyplot для построения графиков, и загрузила основной файл из датасета. Также, для тепловой карты, использовалась библиотека matplotlib.colors.

import pandas as pd import matplotlib.pyplot as plt import seaborn as sns

Загрузка данных из папки Downloads

df = pd.read_csv(r'D:\Downloads\wc_champions (3).csv')

print("✅ Данные загружены!") print(f"Размер: {df.shape}") print(df.head())

Круговая диаграмма

Исходный размер 870x871

Была построена круговая диаграмма, отображающая распределение побед среди топ-5 чемпионов турнира. Для построения круговой диаграммы необходимо было отфильтровать данные по столбцу win_total, после чего нужно было выбрать 5 чемпионов с наибольшим количеством побед и рассчитать процентное соотношение их побед относительно общего числа побед в топ-5.

На круговой диаграмме представлено распределение побед среди топ-5 чемпионов турнира Worlds Championship. Для визуализации данных была использована пользовательская цветовая палитра, вдохновленная стилистикой League of Legends (золотой, темно-бирюзовый, бронзовый, серебристый, серый), а также настроен стиль текста для улучшения читаемости и эстетического восприятия диаграммы.

import pandas as pd import matplotlib.pyplot as plt from io import StringIO

Ваши данные (первые 10 чемпионов для примера, можно добавить всех)

data_text = """champion,sum_total,win_total,lose_total,pick_rate,winrate_total,sum_blue_side,win_blue_side,lose_blue_side,winrate_blue_side,sum_red_side,win_red_side,lose_red_side,winrate_red_side Graves,69,35,34,50.72%,60.53%,34,17,17,50.00%,35,18,17,51.43% Senna,46,21,25,45.65%,40.35%,21,12,9,57.14%,25,9,16,36.00% Jhin,42,28,14,66.67%,36.84%,20,10,10,50.00%,22,18,4,81.82% Leona,42,26,16,61.90%,36.84%,19,14,5,73.68%,23,12,11,52.17% Ashe,42,17,25,40.48%,36.84%,15,5,10,33.33%,27,12,15,44.44% Lillia,41,17,24,41.46%,35.96%,22,9,13,40.91%,19,8,11,42.11% Ornn,40,24,16,60.00%,35.09%,21,13,8,61.90%,19,11,8,57.89% Orianna,39,25,14,64.10%,34.21%,16,12,4,75.00%,23,13,10,56.52% Syndra,37,19,18,51.35%,32.46%,23,13,10,56.52%,14,6,8,42.86% Ezreal,34,20,14,58.82%,29.82%,19,12,7,63.16%,15,8,7,53.33%"""

Загрузка данных

df = pd.read_csv(StringIO(data_text))

Просмотр данных

print("✅ Данные загружены!") print(f"\n📊 Размер данных: {df.shape[0]} строк, {df.shape[1]} столбцов") print(f"\n📋 Названия столбцов:") print(df.columns.tolist())

print("\n🔍 Первые 5 строк:") print(df.head())

Создаем круговую диаграмму для топ-5 чемпионов по победам

top_5_wins = df.nlargest(5, 'win_total')[['champion', 'win_total']] print("\n🏆 Топ-5 чемпионов по победам:") print(top_5_wins)

Цвета League of Legends (5 основных цветов)

colors = ['

C89B3C', '

0A323C', '

785A28', '

A9B4C2', '#5E5E5E']

Настройка стиля

plt.rcParams.update({ 'font.size': 14, 'font.weight': 'bold', 'text.color': 'black' })

Построение круговой диаграммы

plt.figure(figsize=(10, 8)) wedges, texts, autotexts = plt.pie( top_5_wins['win_total'], labels=top_5_wins['champion'], autopct='%1.1f%%', colors=colors, startangle=90, wedgeprops={'edgecolor': 'black', 'linewidth': 2}, textprops={'fontsize': 12, 'fontweight': 'bold'}, pctdistance=0.85 )

Настройка текста процентов

for autotext in autotexts: autotext.set_color('white') autotext.set_fontweight('bold') autotext.set_fontsize(12)

plt.title('Топ-5 чемпионов по количеству побед\nWorlds Championship', fontsize=16, fontweight='bold', pad=20) plt.axis('equal') plt.tight_layout() plt.show()

Статистика

print(f"\n📊 Статистика:") print(f"Всего чемпионов в топ-5: {len(top_5_wins)}") print(f"Всего побед у топ-5: {top_5_wins['win_total'].sum()}") for _, row in top_5_wins.iterrows(): print(f" {row['champion']}: {row['win_total']} побед")

Точечный график

Исходный размер 1077x718

Благодаря этому точечному графику мы увидели, как связаны пикрейт чемпиона и его винрейт на турнире. А также различия в этих показателях между чемпионами с разным количеством сыгранных матчей.

После фильтрации чемпионов с высоким пикрейтом (более 40%) от менее популярных видов, я приступила к построению графика. На нём каждая точка представляет отдельного чемпиона, а цвет точки соответствует количеству сыгранных им матчей (размер точки также отражает этот показатель). Это позволило наглядно увидеть, какие чемпионы демонстрируют высокую эффективность при высокой популярности, а какие — показывают хороший винрейт, оставаясь в тени более популярных собратьев.

from io import StringIO import pandas as pd import matplotlib.pyplot as plt

Ваши данные

data = """champion,sum_total,win_total,lose_total,pick_rate,winrate_total,sum_blue_side,win_blue_side,lose_blue_side,winrate_blue_side,sum_red_side,win_red_side,lose_red_side,winrate_red_side Graves,69,35,34,50.72%,60.53%,34,17,17,50.00%,35,18,17,51.43% Senna,46,21,25,45.65%,40.35%,21,12,9,57.14%,25,9,16,36.00% Jhin,42,28,14,66.67%,36.84%,20,10,10,50.00%,22,18,4,81.82% Leona,42,26,16,61.90%,36.84%,19,14,5,73.68%,23,12,11,52.17% Ashe,42,17,25,40.48%,36.84%,15,5,10,33.33%,27,12,15,44.44% Lillia,41,17,24,41.46%,35.96%,22,9,13,40.91%,19,8,11,42.11% Ornn,40,24,16,60.00%,35.09%,21,13,8,61.90%,19,11,8,57.89% Orianna,39,25,14,64.10%,34.21%,16,12,4,75.00%,23,13,10,56.52% Syndra,37,19,18,51.35%,32.46%,23,13,10,56.52%,14,6,8,42.86% Ezreal,34,20,14,58.82%,29.82%,19,12,7,63.16%,15,8,7,53.33%"""

Загрузка данных

df = pd.read_csv(StringIO(data))

Очищаем процентные значения

df['pick_rate'] = df['pick_rate'].str.rstrip('%').astype(float) df['winrate_total'] = df['winrate_total'].str.rstrip('%').astype(float) df['winrate_blue_side'] = df['winrate_blue_side'].str.rstrip('%').astype(float) df['winrate_red_side'] = df['winrate_red_side'].str.rstrip('%').astype(float)

print("✅ Данные загружены!") print(f"📊 Всего чемпионов: {len(df)}")

Фильтруем данные — оставляем чемпионов с высоким пикрейтом (pick_rate > 40%)

df_popular = df[df['pick_rate'] > 40]

print(f"\n🔍 Чемпионов с пикрейтом > 40%: {len(df_popular)}")

Проверяем, есть ли данные

if not df_popular.empty:

# Цветовая палитра League of Legends
colors = ['<h3>C89B3C', '</h3>0A323C', '<h3>785A28', '</h3>A9B4C2', '<h3>5E5E5E', '</h3>F0E6D2']

# Создаем словарь цветов для разных ролей (если есть данные о ролях)
# В данном случае используем категории по количеству игр
df_popular['category'] = pd.cut(df_popular['sum_total'], 
                                 bins=[0, 30, 50, 100], 
                                 labels=['Мало игр (0-30)', 'Средне игр (30-50)', 'Много игр (50+)'])

unique_categories = df_popular['category'].unique()
color_map = {category: colors[i % len(colors)] for i, category in enumerate(unique_categories)}

Строим точечный график зависимости винрейта от пикрейта

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

for category in unique_categories:
    subset = df_popular[df_popular['category'] == category]
    plt.scatter(subset['pick_rate'],
               subset['winrate_total'],
               c=color_map[category],
               label=category,
               s=subset['sum_total'] * 2,  # Размер точки зависит от количества игр
               alpha=0.7,
               edgecolor='black',
               linewidth=1.5)
    
    # Добавляем подписи для самых заметных чемпионов
    for _, row in subset.iterrows():
        if row['sum_total'] > 40:  # Подписываем только популярных чемпионов
            plt.annotate(row['champion'], 
                       (row['pick_rate'], row['winrate_total']),
                       xytext=(5, 5), 
                       textcoords='offset points',
                       fontsize=9,
                       fontweight='bold')

# Улучшаем внешний вид
plt.grid(True, linestyle='--', alpha=0.7)
plt.xlabel('Пикрейт (%)', fontsize=12, fontweight='bold')
plt.ylabel('Винрейт (%)', fontsize=12, fontweight='bold')
plt.title('Зависимость винрейта от пикрейта среди чемпионов\nWorlds Championship', 
          fontsize=14, fontweight='bold', pad=20)
plt.legend(title='Количество игр', bbox_to_anchor=(1.05, 1), loc='upper left')
plt.tight_layout()

# Отображаем график
plt.show()

# Выводим статистику
print(f"\n📊 Статистика:")
print(f"Всего чемпионов с пикрейтом > 40%: {len(df_popular)}")
print(f"Средний пикрейт: {df_popular['pick_rate'].mean():.1f}%")
print(f"Средний винрейт: {df_popular['winrate_total'].mean():.1f}%")
print(f"\n📈 Корреляция между пикрейтом и винрейтом: {df_popular['pick_rate'].corr(df_popular['winrate_total']):.3f}")
print(f"\n🏆 Распределение по количеству игр:")
print(df_popular['category'].value_counts())

else: print("⚠️ Нет чемпионов с пикрейтом > 40%")

Для понимания графика, я сделала подписи к осям Х и Y.

Добавляем подписи для самых заметных чемпионов

    for _, row in subset.iterrows():
        if row['sum_total'] > 40:  # Подписываем только популярных чемпионов
            plt.annotate(row['champion'], 
                       (row['pick_rate'], row['winrate_total']),
                       xytext=(5, 5), 
                       textcoords='offset points',
                       fontsize=9,
                       fontweight='bold')

Тепловая карта

Исходный размер 1046x717

Для построения тепловой карты я определила топ-5 чемпионов, одержавших наибольшее количество побед на турнире Worlds Championship. Затем сгруппировала данные по этим чемпионам и признаку эффективности на разных сторонах карты (синяя и красная), чтобы выявить, на какой стороне лидеры турнира демонстрируют лучшие результаты. На основе этих данных построила тепловую карту, где интенсивность цвета отображает винрейт чемпиона на соответствующей стороне.

from io import StringIO import pandas as pd import numpy as np import matplotlib.pyplot as plt

Ваши данные (полные)

data = """champion,sum_total,win_total,lose_total,pick_rate,winrate_total,sum_blue_side,win_blue_side,lose_blue_side,winrate_blue_side,sum_red_side,win_red_side,lose_red_side,winrate_red_side Graves,69,35,34,50.72%,60.53%,34,17,17,50.00%,35,18,17,51.43% Senna,46,21,25,45.65%,40.35%,21,12,9,57.14%,25,9,16,36.00% Jhin,42,28,14,66.67%,36.84%,20,10,10,50.00%,22,18,4,81.82% Leona,42,26,16,61.90%,36.84%,19,14,5,73.68%,23,12,11,52.17% Ashe,42,17,25,40.48%,36.84%,15,5,10,33.33%,27,12,15,44.44% Lillia,41,17,24,41.46%,35.96%,22,9,13,40.91%,19,8,11,42.11% Ornn,40,24,16,60.00%,35.09%,21,13,8,61.90%,19,11,8,57.89% Orianna,39,25,14,64.10%,34.21%,16,12,4,75.00%,23,13,10,56.52% Syndra,37,19,18,51.35%,32.46%,23,13,10,56.52%,14,6,8,42.86% Ezreal,34,20,14,58.82%,29.82%,19,12,7,63.16%,15,8,7,53.33%"""

Загрузка данных

df = pd.read_csv(StringIO(data))

Очищаем процентные значения

df['winrate_total'] = df['winrate_total'].str.rstrip('%').astype(float) df['winrate_blue_side'] = df['winrate_blue_side'].str.rstrip('%').astype(float) df['winrate_red_side'] = df['winrate_red_side'].str.rstrip('%').astype(float) df['pick_rate'] = df['pick_rate'].str.rstrip('%').astype(float)

print("✅ Данные загружены!") print(f"📊 Всего чемпионов: {len(df)}")

1. Выбираем топ-5 чемпионов по количеству побед

top_5_champions = df.nlargest(5, 'win_total')['champion'].tolist()

2. Фильтруем DataFrame по этим чемпионам

df_top = df[df['champion'].isin(top_5_champions)].copy()

3. Создаем столбцы с винрейтом на синей и красной стороне

df_top['blue_text'] = 'Винрейт на синей стороне' df_top['red_text'] = 'Винрейт на красной стороне'

4. Строим сводную таблицу: чемпион → сторона → винрейт

pivot_df = df_top.pivot_table( index='champion', values=['winrate_blue_side', 'winrate_red_side'], aggfunc='mean' )

Переименовываем колонки для читаемости

pivot_df.columns = ['Винрейт на синей стороне (%)', 'Винрейт на красной стороне (%)']

5. Сортируем чемпионов по общему винрейту (для наглядности)

pivot_df['avg_winrate'] = (pivot_df['Винрейт на синей стороне (%)'] + pivot_df['Винрейт на красной стороне (%)']) / 2 pivot_df = pivot_df.sort_values('avg_winrate', ascending=False) pivot_df = pivot_df.drop('avg_winrate', axis=1)

6. Создаем тепловую карту с помощью matplotlib

fig, ax = plt.subplots(figsize=(10, 6))

Цветовая карта League of Legends (от зеленого/золотого к красному/темному)

colors = ['

C89B3C', '

785A28', '

0A323C', '

5E5E5E', '#F0E6D2'] cmap = plt.cm.colors.ListedColormap(colors[:len(pivot_df.columns)])

Рисуем тепловую карту

im = ax.imshow(pivot_df.values, cmap='RdYlGn', aspect='auto', vmin=30, vmax=80)

Настройка осей

ax.set_xticks(np.arange(len(pivot_df.columns))) ax.set_yticks(np.arange(len(pivot_df.index))) ax.set_xticklabels(pivot_df.columns, rotation=15, ha='right', fontsize=11, fontweight='bold') ax.set_yticklabels(pivot_df.index, fontsize=11, fontweight='bold')

Добавляем значения в ячейки

for i in range(len(pivot_df.index)): for j in range(len(pivot_df.columns)): value = pivot_df.values[i, j] text_color = 'white' if value < 50 or value > 70 else 'black' text = ax.text(j, i, f'{value:.1f}%', ha="center", va="center", color=text_color, fontweight='bold', fontsize=12)

Настройка внешнего вида

ax.set_xlabel('Сторона карты', fontsize=12, fontweight='bold') ax.set_ylabel('Чемпион', fontsize=12, fontweight='bold') ax.set_title('Сравнение эффективности топ-5 чемпионов\nна синей и красной стороне\nWorlds Championship', fontsize=14, fontweight='bold', pad=20)

Добавляем цветовую шкалу

cbar = plt.colorbar(im, ax=ax, shrink=0.8) cbar.set_label('Винрейт (%)', fontsize=11, fontweight='bold')

Добавляем рамки между ячейками

for i in range(len(pivot_df.index) + 1): ax.axhline(i - 0.5, color='white', linewidth=2) for j in range(len(pivot_df.columns) + 1): ax.axvline(j - 0.5, color='white', linewidth=2)

plt.tight_layout() plt.show()

Выводим статистику

print("\n📊 СТАТИСТИКА:") print(f"Всего чемпионов в топ-5: {len(df_top)}") print(f"\n🏆 Топ-5 чемпионов по количеству побед:") for i, champion in enumerate(top_5_champions, 1): champ_data = df[df['champion'] == champion].iloc[0] print(f"{i}. {champion}: {champ_data['win_total']} побед (всего игр: {champ_data['sum_total']})")

print(f"\n📈 Распределение винрейта по сторонам:") print(pivot_df.round(1))

Мы используем файлы cookies для улучшения работы сайта НИУ ВШЭ и большего удобства его использования. Более подробную...
Показать больше