Помня о шахматах благодаря ферзевому гамбиту от Netflix, на этой неделе я использовал PySpark для создания классификатора с несколькими метками для прогнозирования результатов шахматных матчей из Chess Game Dataset.

Настраивать

Процесс настройки вашей локальной среды для использования Apache Spark, возможно, является самой сложной частью этого процесса. Сначала вы должны установить Docker, а затем загрузить образ контейнера для PySpark, специализированного для Jupyter Notebooks. Если вы уже используете Docker и ваш Docker Hub обновлен, процесс установки, скорее всего, будет ускорен, но, к сожалению, мой процесс настройки включал не только загрузку Docker, но и не одно, а два обновления Mac OS, чтобы я мог использовать Докер на моем ноутбуке. Ниже приведен общий обзор конфигурации PySpark:

Установите Docker и PySpark

Docker - это служба, используемая для доставки программного обеспечения в пакетах, называемых контейнерами, которые содержат все конфигурации и библиотеки, необходимые для запуска программного обеспечения. PySpark для Jupyter Notebooks доступен для загрузки в виде контейнера Docker, поэтому первый шаг этого процесса включает загрузку Docker на ваш локальный компьютер.

После установки Docker на мой Mac я использовал команды терминала, чтобы вытащить образ PySpark Docker из удаленного репозитория и запустить контейнер:

docker pull jupyter/pyspark-notebook
docker run -it jupyter/pyspark-notebook:latest /bin/bash

Чтобы проверить успешную установку PySpark, я попытался импортировать его в Jupyter Notebook, создать экземпляр объекта Spark Context и выполнить простую команду:

Ожидаемый результат здесь - это что-то вроде [729, 375, 601, 610, 695], что указывает на то, что PySpark установлен успешно!

Пока что мы создали SparkContext, который является основной точкой входа для Spark. SparkContext представляет подключение к кластеру Spark и используется для выполнения операций в этом кластере.

Чтобы использовать возможности машинного обучения Spark, мы будем использовать конструкцию под названием Spark Session, которая является абстракцией более высокого уровня контекста Spark и эффективно функционирует как оболочка для объекта. После создания экземпляра Spark Session можно использовать для создания Spark DataFrame:

Проверка данных

Наконец-то мы готовы приступить к работе с некоторыми данными! Начнем с изучения нашего набора шахматных данных. Набор шахматных данных содержит около 20 000 шахматных партий, включая рейтинг белых и черных игроков, начальные ходы, время начала и окончания каждой игры, общее количество ходов, сделанных в игре, и многое другое.

Мы можем использовать df.head() аналогично тому, как мы предварительно просматриваем Pandas DataFrames, чтобы взглянуть на первую строку нашей таблицы. Однако результат не так четко ориентирован:

Мы можем проверить заголовки столбцов и типы данных с помощью df.dtypes:

и мы можем просматривать различные значения, используя df.select('winner').distinct().collect():

Мы будем использовать этот набор данных для создания классификатора, который определяет исход шахматных партий из трех возможных вариантов: белый, черный или ничья.

Функциональная инженерия

Мы начнем процесс моделирования с создания новой функции, основанной на времени начала и окончания каждой игры, чтобы определить продолжительность игры. В Pandas мы можем использовать простую операцию вычитания между двумя столбцами, которая автоматически векторизуется, и назначить ее нашему новому имени столбца. В PySpark мы используем операцию df.withColumn() для выполнения аналогичного процесса:

df_new = df.withColumn("duration", df['last_move_at'] - df['created_at'])

Фиктивные переменные

Как видно выше, у нас есть ряд строковых переменных (victory_status, increment_code и Opening_name), которые необходимо преобразовать в фиктивные переменные перед процессом моделирования. Это достигается с помощью объекта StringIndexer(), импортированного из pyspark.ml.feature, который преобразует каждую строку в индекс. Три индексатора строк (для трех соответствующих функций, которые должны быть преобразованы в фиктивные) помещаются в конвейер, который упрощает процесс создания индексов для каждой из этих трех переменных.

Затем проиндексированные столбцы вводятся в версию OneHotEncoder PySpark:

Spark OneHotEncoderEstimator преобразует каждую проиндексированную функцию в SparseVector. Например, функция opening_name_index преобразуется с помощью OHE в opening_name_dummy, который выводится как opening_name_dummy=SparseVector(1476, {234: 1.0}))

Моделирование

Чтобы начать процесс моделирования, мы сначала указываем наши функции и целевую переменную и преобразуем наш обрезанный фрейм данных с нашими спроектированными функциями в векторизованный фрейм данных, который будет использоваться в наших моделях. VectorAssembler - это преобразователь, который объединяет список столбцов в один векторный столбец. Он используется для объединения всех ваших функций в единый вектор функций, который затем используется для обучения моделей машинного обучения.

Чтобы создать разделение на поезд / тест, мы можем использовать пакет pyspark или просто выполнить randomSplit() над данными:

train_data, test_data = vector_df.randomSplit([.75, .25])

Мы создаем экземпляр базовой модели классификатора случайного леса, указывая столбцы функций, labelCol (целевая переменная,), а также дополнительные гиперпараметры, и подгоняем модель к нашим обучающим данным:

Затем мы используем нашу обученную модель, чтобы делать прогнозы на основе данных тестирования:

predictions = forest_model.transform(test_data).select('winner', 'prediction')

Оценка модели

PySpark имеет MulticlassClassificationEvaluator пакет, который можно использовать для оценки вашей модели путем сравнения ваших прогнозов с ожидаемой меткой. Создав экземпляр своего оценщика, я использовал его, чтобы получить оценку F1 и оценку точности для моей модели:

Затем я хотел проверить важность функции, чтобы увидеть, какие особенности, в частности, оказали наибольшее влияние на прогноз исхода шахматного матча:

sorted(list(zip(forest_model.featureImportances,features)),reverse=True)

Неудивительно, что рейтинг игрока имеет большое значение при определении того, кто выиграет шахматный матч!

Последние мысли

Чтобы продолжить этот проект, я мог бы начать включать больше функций, настройку гиперпараметров с эквивалентом Spark ML для поиска по сетке или даже исследовать различные типы моделей.

В ходе этого исследования я обнаружил, что после короткой кривой обучения синтаксис и процесс моделирования для использования Spark ML довольно интуитивно понятны для специалистов по данным, которые знакомы с манипулированием данными в Pandas и моделированием с помощью Scikit-Learn, и я бы рекомендовал всем Специалисты по обработке данных находят время, чтобы узнать больше о машинном обучении с Apache Spark.

Хотите изучить проект полностью? Посмотрите репозиторий GitHub здесь!