Scala и Python находчивы в Интернете, давайте заставим Spark сиять с помощью Java!

Чему научиться машинному обучению с помощью Spark?

Такой сайт, как https://sparkbyexamples.com/, является примером высококачественных примеров, в основном на Scala и PySpark, а также на Java.

В Apache Spark repo есть много Java-примеров, в них приятно копнуть глубже, чтобы понять, как работает Spark.

Помимо этих ресурсов, Фавио Васкес написал один из самых качественных и удобных для начинающих постов о создании модели Spark MLLib:



Отдайте должное оригинальному автору содержания, которое необходимо прочитать, прежде чем переходить к следующему разделу этого поста!

В этом сообщении блога я расскажу о тех же процедурах построения модели машинного обучения с использованием SparkML.

Что и почему?

Spark написан на Scala, а сам Scala — отличный и элегантный язык!

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

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

Покажите мне исходный код на Java!

Хорошо, теперь вы прочитали сообщение Favio Vázquez, вы знаете PySpark и знаете, как использовать Pandas для работы с фреймворком данных в python.

Давайте погрузимся в ту же историю Титаника, используя Spark Java API, рабочую версию Java, для которой была построена выходная модель машинного обучения, и вы можете клонировать исходный код из этого GitHub Repo.

Приложение разработано с использованием Spark Java API (Spark SQL + MLLib) с Spring Boot в качестве будущей точки расширения.

Примечание. Приложение не предназначено для работы в формате FatJar, чтобы избежать сложности пути к ресурсу train.csv.

Далее, давайте шаг за шагом рассмотрим, как это работает!

Как строится модель машины:

Шаг 1. Настройте SparkSession

В журнале немного шумно, поэтому и spark.eventLog.enabled=false, и logging.level.root=WARN в Springapplication.properties

Мы запускаем все в локальном режиме, поэтому вам не нужно управлять кластером Spark.

Шаг 2. Считайте CSV-файл с Титаника

Kaggle провел конкурс на предсказание выжившего на Титанике, вы можете получить train.csv здесь: https://www.kaggle.com/c/titanic/data

Затем чтение CSV с использованием пути Spark:

Чтение CSV просто! При желании вы можете определить тип данных каждого столбца.

В Spark есть много классов, облегчающих жизнь — DataTypes имеют большинство часто используемых типов JVM (например, помогают разработчику Java использовать возможности Scala)

Конечно, после приведения типа данных (от String csv к некоторому Int/DoubleType) мы фильтруем (т.е. выбираем) нужные столбцы и игнорируем неиспользуемые столбцы.

col — это статический импортированный метод, который означает Column , у нас будет много взаимодействия с Column. Хорошая идея — проконсультироваться с Java API Column, так как у нас будет много использования ниже.

Dataframe должен выглядеть следующим образом:

Схема/DataType для каждого столбца выглядит так:

Наше col(“Pclass”).cast(DataTypes.DoubleType) в выражении select работает хорошо, приведение типов делает свою работу.

Шаг 3: Для человека, чтобы понять данные

Мы делаем некоторое исследовательское представление о статистике данных и обнуляемости:

Основная статистика:

У нас 891 пассажир (красный цвет), средний возраст 29,7 лет (зеленый цвет), самой молодой душе 5 месяцев (желтый цвет).

Шутка: кто-то выиграл в лотерею, так что билет бесплатный — Джек?😉

Есть отклонения?

Стоимость проезда большая: Max=512 и Mean=32, поэтому кто-то заплатил 512/32 = 16 раз больше стоимости проезда. Это *может* быть статистическим выбросом, это большая тема, поэтому мы пропустим ее в этом посте.

Есть нулевые значения?

Чтобы узнать, сколько null в каждом столбце, мы можем зациклить каждый столбец один за другим и подсчитать null, а затем join обратно в один кадр данных.

В приведенном выше коде я бросаю себе вызов за использование только API набора данных (т.е. без прямого Spark SQL).

И да, у нас есть нулевые значения:

Призыв к улучшению: признателен любому читателю, который предложит лучший способ (либо SparkSQL, либо API набора данных) о том, как сделать такой счетчик (null(col())) более простым способом.

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

Шутка: 2 человека, которые не сели на борт, это кто-то кроме Джека и Роуз 😂 Википедия сказала, что они сели на абордаж и тонут вместе с Титаником (фильм)

Шаг 4. Удалите пустые значения

Наш алгоритм машинного обучения не любит нули, нам нужны только полные данные — все или ничего!

Мы удаляем данные со всеми столбцами, в которых есть null, поэтому мы не строим модель с данными, в которых отсутствует age или embarked.

Мы фильтруем, используя это условие, которое также генерируется циклом for с использованием Dataset API:

((((((Survived IS NOT NULL) AND (Pclass IS NOT NULL)) AND (Sex IS NOT NULL)) AND (Age IS NOT NULL)) AND (Fare IS NOT NULL)) AND (Embarked IS NOT NULL))

После очистки данных (удалить null) осталось 712 пассажиров:

Шаг 5: Разработка функций

Наш пример вряд ли может претендовать на разработку какой-либо новой функции из существующей, в этом примере мы могли бы назвать это «Сопоставление строки с числом».

Причина преобразования строки в число заключается в том, что наш RandomForestClassifier может принимать только числа, поэтому «мужской» / «женский» не имеет смысла для этого алгоритма.

Таким образом, в Sex мы сопоставляем «Мужской» -> 0, «Женский» -> 1, а затем сохраняем его в новом столбце Gender. То же самое происходит для Embarked -> Boarded .

Вместо того, чтобы использовать Dataset.map, мы можем попросить Indexer сделать всю тяжелую работу за нас.

Ясно, что это означает, что индексатор будет принимать столбец Sex и помещать вывод в столбец Gender.

Метод fit позволяет Indexer узнать, что представляют собой данные (например, «Мужской» -> 0, «Женский» -> 1), затем часть действия — transform, которая выполняет col(Sex) map to col(Gender) using the mapping of "Male -> 0 and Female -> 1"

Есть причина, по которой fit и transform являются двумя отдельными методами — в этом блоге не будет говориться о том, как использование fitAndTransform восприимчиво к предубеждениям, полученным при изучении невидимых данных / прогнозированию / прогнозированию, но имейте это в виду в своих будущих проектах.

Затем мы собираем столбцы в один массив, хранящийся в столбце feature:

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

Например: можно представить, что Pclass пассажиры 1-го класса могут иметь лучший обзор кабины, но 2-й класс может быть ближе всего к спасательной шлюпке, поэтому мы можем создать функцию DistanceToLifeboat и попробовать, может ли алгоритм машинного обучения использовать эту функцию для улучшения. предсказание.

Шаг 6: Построение модели с использованием обучающего набора

У нас есть все данные в одном фрейме данных, поэтому мы можем разделить больший набор на train и test фрейм данных на randomSplit.

Это не лучшая практика для разделения таким образом, причина указана в комментарии к коду:

На самом деле, мы должны использовать просмотренные данные train.csv для обучения модели и невидимый файл test.csv для проверки.
Поскольку мы не хотим загружать test.csv для тестовой части, мы просто разделяем существующий файл train.csv. -› 80 % обучение, 20 % проверка (представьте, что мы не видим 20 % тестовых данных)
Из-за простоты этого примера смещения/упреждения не произошло;

Очень прямолинейно: используя RandomForestClassifier.fit (наш алгоритм ML), он попытается настроить модель с помощью «Feature» и приложит все усилия, чтобы максимально сохранить algo.learn(feature)=answerhold true, исправляя model (т.е. обучение) вдоль каждого запись пассажиров.

Вы заметили, что столбец Survived не включен в характеристики?

Помните, что мы хотим сохранить "algo.learn(feature)=answer” удержание, исправив model, если вы поместите ответ Survived в функцию, то algo.learn(feature+answer)=answer любой простой алгоритм узнает, что он может напрямую получить ответ из него. На самом деле мы подгоняем модель, чтобы выяснить, какой тип результатов значений признаков соответствует результату.

Когда ваша модель машинного обучения обладает силой супермена со 100% точностью, вы должны спросить себя — слишком ли это хорошо, чтобы быть правдой?

Шаг 6: Попробуйте добавить в модель некоторые невидимые данные и спрогнозировать

Теперь у нас есть модель из предыдущего шага, мы можем легко перенести невидимые данные в наш прогноз: model(featureOfUnseenData) => prediction

Операции estimator.fit, а затем estimator.transform обычно встречаются в рабочем процессе машинного обучения.

Прогноз по модели выглядит следующим образом:

Вы уже можете видеть, что в приведенном выше кадре данных результата есть некоторая неточность прогноза.

Шаг 7. Оцените, насколько хороша наша модель

Теперь у нас есть и «факт», и «прогноз», давайте посмотрим, хорошо ли наша модель предсказывает выживаемость, используя признаки PClass, Age, Gender и Boarded.

Конечно, точность 79,07% — это нормально для первой попытки, всегда есть место для улучшения!

Наконец: подумайте, как улучшить

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

Здравый смысл также полезен: учитывая PClass Джека и Роуз, у Розы больше шансов выжить, чем у Джека.

Мы также можем изменить фазу/изменить вывод машинного обучения, чтобы использовать вероятность (например, 90% выживают) вместо бинарного (выжить/не выжить) результата для различных вариантов использования.

Резюме:

Здорово! Вы закончили этот пост в блоге! В этом блоге используются термины непрофессионала (иногда чрезмерно упрощенные), чтобы объяснить машинное обучение 101 с использованием Spark Java API на реальном примере.

Также было продемонстрировано, как использовать Spark Java API для выполнения задач, обычно встречающихся в обучении Pandas/Scikit, и опытный читатель должен заметить сходство.

Опять же, весь исходный код можно скачать с этого GitHub Repo.

Не стесняйтесь оставлять свои отзывы, подписываться и аплодировать, чтобы поощрить меня писать больше в блоге о машинном обучении.

Приятного обучения!

Вывод моего машинного обучения из моего апостериорного исследования

Хин Лам