Люди, интересующиеся шахматами и разбирающиеся в этом виде спорта, с высокой вероятностью задумывались о начальных комбинациях ходов, которым стоит научиться в самом начале своего пути. В этой практической части мы проанализируем датасет из 20058 наблюдений с сайта lichess.org, который домтупен на платформе kaggle.com
id - идентификатор игры
rated - оцениваемая игра или нет
created_at - время начала игры
last_move_at - время последнего хода
turns - количество ходов
victory_status - статус игры
winner - победитель (Ч/Б)
white_id - идентификатор игрока, играющего белыми
white_rating - рейтинг игрока (Б)
black_id - идентификатор игрока, играющего черными
black_rating - рейтинг игрока (Ч)
moves - ходы в стандартных шахматных обозначениях
opening_eco - стандартный код для каждого типа дебюта
opening_name - название дебюта
opening_ply - количество ходов на дебютных этапах
Исследовательский вопрос: С чего стоит начинать игру типичному игроку в равной (c сопоставимыми рейтингами) игре?
Разобьем ответ на этот вопрос на две части, где нулевой пункт про распределения рейтингов черных и белых:
Очистка данных (выравнивание уровней игроков в интервале 100 пунктов) и изучение распределений
Определение стратегии по названиям из столбца opening_name. То есть предстоит извлечь базовое название стратегии, исходя из паттерна написания этих стратегий.
Подсказка: В Excel можно воспользоваться авто-заполнением, которое здорово упростит вам работу
Можно посмотреть небольшое видео по этой ссылке
Давайте загрузим датасет games.csv
library(dplyr)
library(ggplot2)
library(ggpubr)
library(tidyr)
chess = read.csv('games.csv')
Исходя из структуры датасета, можно с уверенностью утверждать о чистоте данных, так как все переменные представлены в тех типах, которые соответствуют их природе. То есть числовые - это числовые, а строковые - это строковые.
chess %>% str()
## 'data.frame': 20058 obs. of 16 variables:
## $ id : chr "TZJHLljE" "l1NXvwaE" "mIICvQHh" "kWKvrqYL" ...
## $ rated : chr "FALSE" "TRUE" "TRUE" "TRUE" ...
## $ created_at : num 1.5e+12 1.5e+12 1.5e+12 1.5e+12 1.5e+12 ...
## $ last_move_at : num 1.5e+12 1.5e+12 1.5e+12 1.5e+12 1.5e+12 ...
## $ turns : int 13 16 61 61 95 5 33 9 66 119 ...
## $ victory_status: chr "outoftime" "resign" "mate" "mate" ...
## $ winner : chr "white" "black" "white" "white" ...
## $ increment_code: chr "15+2" "5+10" "5+10" "20+0" ...
## $ white_id : chr "bourgris" "a-00" "ischia" "daniamurashov" ...
## $ white_rating : int 1500 1322 1496 1439 1523 1250 1520 1413 1439 1381 ...
## $ black_id : chr "a-00" "skinnerua" "a-00" "adivanov2009" ...
## $ black_rating : int 1191 1261 1500 1454 1469 1002 1423 2108 1392 1209 ...
## $ moves : chr "d4 d5 c4 c6 cxd5 e6 dxe6 fxe6 Nf3 Bb4+ Nc3 Ba5 Bf4" "d4 Nc6 e4 e5 f4 f6 dxe5 fxe5 fxe5 Nxe5 Qd4 Nc6 Qe5+ Nxe5 c4 Bb4+" "e4 e5 d3 d6 Be3 c6 Be2 b5 Nd2 a5 a4 c5 axb5 Nc6 bxc6 Ra6 Nc4 a4 c3 a3 Nxa3 Rxa3 Rxa3 c4 dxc4 d5 cxd5 Qxd5 exd5 "| __truncated__ "d4 d5 Nf3 Bf5 Nc3 Nf6 Bf4 Ng4 e3 Nc6 Be2 Qd7 O-O O-O-O Nb5 Nb4 Rc1 Nxa2 Ra1 Nb4 Nxa7+ Kb8 Nb5 Bxc2 Bxc7+ Kc8 Qd"| __truncated__ ...
## $ opening_eco : chr "D10" "B00" "C20" "D02" ...
## $ opening_name : chr "Slav Defense: Exchange Variation" "Nimzowitsch Defense: Kennedy Variation" "King's Pawn Game: Leonardis Variation" "Queen's Pawn Game: Zukertort Variation" ...
## $ opening_ply : int 5 4 3 3 5 4 10 5 6 4 ...
Предупреждение: мы не ожидали от вас построения графиков и дополнительного статистического анализа - это just for fun и демонстрации интересных статистических трюков в R.
В силу того, что нам предстоить строить рекомендации для игроков с более-менее равными уровнями, первым делом, нужно изучить распределения и связь между рейтингами черных и белых игроков.
Распределение рейтингов черных игроков
Построив нашу первую гистограмму, можем заметить, что наблюдения распределены в похожем на “колокол” виде - это можно увидеть на светло-голубом графике ниже.
chess %>% ggplot(aes(x = black_rating)) + geom_histogram()
Красный колокол - это так называемое нормальное распределение, которое вы сможете изучить на курсах статистики, которые были упомянуты в первых двух подборках полезных бесплатных курсов.
Исходя из этого графика, распределение рейтингов черных близко к нормальному
ggdensity(data=chess, x = "black_rating", fill = "light blue") +
scale_x_continuous(limits = c(0, 3000)) +
stat_overlay_normal_density(color = "red", linetype = "dashed") + theme_bw() + theme(text = element_text(size=12), axis.text.x = element_text(angle=90, hjust=1), plot.background = element_rect())
Распределение рейтингов белых игроков
Проделав аналогичную процедуру сможем сделать аналогичные выводы и относительно белых
chess %>% ggplot(aes(x = white_rating )) + geom_histogram()
ggdensity(data=chess, x = "white_rating", fill = "light blue") +
scale_x_continuous(limits = c(0, 3000)) +
stat_overlay_normal_density(color = "red", linetype = "dashed") + theme_bw() + theme(text = element_text(size=12), axis.text.x = element_text(angle=90, hjust=1), plot.background = element_rect())
Давайте посмотрим на совместное распределение рейтингов черных и белых - то есть построим диаграмму рассеяния со значениями рейтингов черных на оси У, а белых на оси Х. Заметим, что в данных присутствует некоторый шум, а точнее - есть игры, где игрок с рейтингом 1000 противостоял игроку с рейтингом в 2500, но мы хотим несколько упростить задачу, сравняв уровни игроков для получения несмещенных результатов.
ggplot(data = chess,
aes(x = white_rating,
y = black_rating)) +
geom_point() +
geom_smooth() +
labs(
x = "White Player Rating",
y = "Black Player Rating")
Очистим данные, оставив их в интервале 100 пунктов и заметим, что гарфик заметно изменился в лучшую сторону, а в новом датасете similar_chess осталось 9162 наблюдений - это меньше половины от исходного числа.
similar_chess <- chess %>%
filter(white_rating >= black_rating - 100, white_rating <= black_rating + 100)
ggplot(data = similar_chess,
aes(x = white_rating,
y = black_rating)) +
geom_point() +
geom_smooth() +
labs(
x = "White Player Rating",
y = "Black Player Rating")
Давайте начнем с распределения выигрышных игр среди игроков двух сторон. На первый взляд, белые и черные играют почти одинаково - это хорошо, так как мы можем убедиться в справедливости (в равности уровней) встреч. Но на этом наше исследование не заканчивается!
ggplot(data = similar_chess,
aes(x = winner,
fill = winner)) +
scale_fill_manual(values = c("#000000", "#D3D2C7", "#EEEED2")) +
geom_bar() +
labs(title = "Fair Game Outcomes",
x = "Winner",
y = "Wins") +
scale_x_discrete(limits = c("white","black","draw")) +
theme(legend.position = "none") +
geom_text(aes(label = ..count..), stat = "count", vjust = 1.5, color = c("#EEEED2", "#000000", "#000000"))
Перейдём к самой сложной части, которая не ожидалась от вас именно в таком углубленном формате - вам можно было пределить лучшую дебютную стратегию с помощью изучения структуры датасета
Но давайте мы покажем вам более интересный поход к анализу
Стратегии, как оказалось, представлены в данном датасете в огромном множестве вариаций, но нам нужны основные названия этих стратегий - то, что до “:”. Например, Sicilian Defense, Pawn Game и другие.
Кроме этого, стоит ограничить множество рассматриваемых стратегий до пяти самых лучших, так как нас не интересуют те, что не в топе.
similar_chess_clean <- similar_chess %>%
separate(opening_name, c("basic_opening", "variation_detail"), sep = ":") %>%
separate(basic_opening, c("basic_opening_no_numerical", "numerical_characters"), sep = "#") %>%
separate(basic_opening_no_numerical, c("basic_opening_clean", "basic_variation"), sep = "\\|") %>%
group_by(winner, basic_opening_clean) %>%
summarize(number_of_wins=n()) %>%
arrange(desc(number_of_wins))
popular_openings <- similar_chess_clean %>%
group_by(basic_opening_clean) %>%
summarize(number_of_wins = sum(number_of_wins)) %>%
arrange(desc(number_of_wins))
most_popular_openings <- top_n(popular_openings, 5, number_of_wins) %>%
arrange(desc(number_of_wins))
Построим рядстолбчатую диаграмму с пятью лучшими стратегиями по количеству выигранных игр
ggplot(data = most_popular_openings,
aes(x = basic_opening_clean,
y = number_of_wins,
fill = basic_opening_clean)) +
geom_bar(stat = "identity") +
labs(title = "Самые популярные стратегии",
x = 'Основная стратегия',
y = "Количество игр") +
scale_x_discrete(limits = c("Sicilian Defense","French Defense", "Queen's Pawn Game", "Italian Game", "King's Pawn Game")) +
theme(legend.position = "none") +
geom_text(aes(label = number_of_wins), stat = "identity", vjust = 1.5)
Теперь построим диаграмму с показателями белых
most_popular_openings = top_n(similar_chess_clean, 5, number_of_wins)
ggplot(data = most_popular_openings %>%
filter(winner == "white"),
aes(x = basic_opening_clean,
y = number_of_wins,
fill = basic_opening_clean)) +
geom_bar(stat = "identity") +
scale_x_discrete(limits = c("Sicilian Defense","French Defense", "Queen's Pawn Game", "Italian Game", "King's Pawn Game")) +
labs(title = "Самые популярные стратегии белых",
x = "Основная стратегия",
y = "Количество выигрышей") +
theme(legend.position = "none") +
geom_text(aes(label = number_of_wins), stat = "identity", vjust = 1.5)
А теперь построим диаграмму с показателями черных
ggplot(data = most_popular_openings %>%
filter(winner == "black"),
aes(x = basic_opening_clean,
y = number_of_wins,
fill = basic_opening_clean)) +
geom_bar(stat = "identity") +
scale_x_discrete(limits = c("Sicilian Defense","French Defense", "Queen's Pawn Game", "King's Pawn Game", "Italian Game")) +
labs(title = "Самые популярные стратегии черных",
x = "Основная стратегия",
y = "Количество выигрышей") +
theme(legend.position = "none") +
geom_text(aes(label = number_of_wins), stat = "identity", vjust = 1.5)
Первый вывод Независимо от выбранного цвета, наблюдается абсолютная доминация со стороны игроков, придерживающихся Sicilian Defense
Абсолютные величины - это хорошо, но нас, аналитиков, интересуют также относительные величины (пропорции).
most_popular_openings_winrate_stage <- most_popular_openings %>%
group_by(basic_opening_clean) %>%
summarize(total_games = sum(number_of_wins))
most_popular_openings_winrate <- merge(most_popular_openings,
most_popular_openings_winrate_stage,
by = "basic_opening_clean") %>%
mutate(win_rate = 100 * (number_of_wins / total_games)) %>%
arrange(desc(win_rate)) %>%
filter(basic_opening_clean != "Ruy Lopez")
Второй вывод Можем заметить, что Sicilian Defense в большей пропорции доминируется черными игроками, но эта разница нелика (всего 1,27%)
ggplot(data = most_popular_openings_winrate,
aes(x = basic_opening_clean,
y = win_rate,
fill = winner)) +
geom_bar(stat = "identity") +
scale_fill_manual(values = c("#000000", "#D3D2C7", "#EEEED2")) +
scale_x_discrete(limits = c("Sicilian Defense","French Defense", "Queen's Pawn Game", "King's Pawn Game", "Italian Game")) +
geom_text(aes(label = paste0(round(win_rate, 2), "%")), stat = "identity", position = position_stack(vjust = 0.5),
color = c("#000000", "#EEEED2", "#EEEED2",
"#EEEED2", "#EEEED2", "#000000",
"#000000", "#000000", "#EEEED2",
"#000000", "#000000", "#000000",
"#000000", "#000000", "#000000"))
Ответ на исследовательский вопрос
Если бы ко мне обратились бы за советом о дебютной стратегии в честной игре, то я смело смог бы рекомендовать Sicilian Defense, как минимум, на платформе lichess.org в силу наблюдаемой нами абсолютной доминации этой стратегии над всеми другими.