Апрель 2016
Том 31 номер 4
Большие данные - Обработка данных и машинное обучение в Spark
Евгений Чувыров | Апрель 2016
Исходный код можно скачать по ссылке
Продукты и технологии:
Microsoft Azure, HDInsight, Apache Spark, Python
В статье рассматриваются:
- доступность сверхмасштабной обработки данных в Microsoft Cloud;
- Apache Spark — современная инфраструктура анализа больших данных, развертываемая в Azure за минуты;
- примеры решения задач машинного обучения в Spark.
Вот вам вопрос: как называется инфраструктура, которая многое позаимствовала из проекта Microsoft Dryad, стала самым популярным проектом с открытым исходным кодом за 2015 год и установила рекорд в обработке данных, отсортировав 100 Тб данных всего за 23 минуты? Ответ: Apache Spark.
В этой статье я расскажу о скорости работы и причинах популярности Spark, а также о том, почему она является сейчас явным лидером в области обработки и анализа больших данных. Используя подписку Microsoft Azure, я представлю примеры решения задач машинного обучения (machine learning, ML) с помощью Spark, сделав маленький шажок от проектирования ПО в мир обработки и анализа данных. Но, прежде чем углубиться в анализ данных и ML, важно сказать несколько слов о различных компонентах инфраструктуры Spark и о ее взаимосвязи с Azure.
Компоненты Spark
Ценность инфраструктуры Spark в том, что она обеспечивает обработку больших данных в кластерах обычных компьютеров. Такая обработка возможна благодаря ядру Spark Core, которое упаковывает запросы данных и распределяет их по кластеру. Помимо Spark Core, в инфраструктуре Spark есть несколько дополнительных компонентов, и каждый из них применим к задачам из специфических предметных областей. Не исключено, что вам никогда не понадобится работать ни с одним из этих компонентов, если вы заинтересованы только в манипуляциях над большими данными и создании отчетов по ним. Однако в этой статье я буду использовать MLLib для создания ML-модели, которая позволит довольно точно «угадывать» цифры, написанные от руки (подробнее об этом позже). Другие компоненты инфраструктуры Spark обеспечивают обработку потоковых данных (Spark Streaming), манипуляции графами и вычисления по знаменитому алгоритму ранжирования страницы PageRank (GraphX), а также выполнение SQL-запросов поверх распределенных данных (Spark SQL).
Выполнение Spark в Azure
Есть немало вариантов в экспериментировании со Spark: от применения управляемых сервисов с databricks.com (эта компания создала Spark и продолжает ее развивать), подготовки контейнера Docker и отбора предварительно установленных образов Spark из Docker Hub до получения полного репозитария исходного кода с GitHub (github.com/apache/spark) и самостоятельного создания продукта. Но поскольку эта статья об Azure, я хотел бы показать, как создаются кластеры Spark в Azure. Причина этого крайне интересна: Azure предоставляет гарантии корпоративного уровня для Spark, развернутой в вычислительных кластерах Azure. Azure дает SLA, поддерживаемое Microsoft, на уровне 99,9% для всех кластеров Spark, а также предлагает поддержку для предприятий по формуле «24×7» и мониторинг кластеров. Эти гарантии в сочетании с простотой развертывания кластеров и рядом объявлений по поводу Spark и Azure на конференции 2016 Build делают Microsoft Cloud великолепной средой для ваших задач, связанных с большими данными.
Волшебная пыль
Секрет, который делает Spark столь популярной сегодня среди аналитиков данных, является двояким: эта инфраструктура быстра и программирование в ней — одно удовольствие. Сначала рассмотрим, что делает Spark гораздо более быстрой по сравнению с предшествующими инфраструктурами.
Предшественник Spark, Hadoop MapReduce, был рабочей лошадкой в области аналитики больших данных с тех пор, когда в 2005 году Дуг Каттинг (Doug Cutting) и Майк Кафарелла (Mike Cafarella) основали проект Apache Hadoop. Средства MapReduce ранее были доступны только в информационных центрах Google и имели полностью закрытый код. Hadoop отлично работала в случае пакетной обработки в кластере, но ей была свойственно отсутствие гибкости. Операции Map и Reduce были связаны, т. е. сначала вы выполняли задачу Map, потом задачу Reduce. Однако в сложных задачах требовалось комбинировать множество операций Map и Reduce. Кроме того, каждую задачу приходилось разлагать на операции преобразования (map) и редукции (reduce). Выполнение этих последовательных операций занимало длительное время и было утомительно в программировании. Другими словами, это не было аналитикой в реальном времени.
В противоположность этому инфраструктура Spark применяет интеллектуальный подход к задачам анализа данных. Она конструирует Directed Acyclic Graph (DAG) исполнения перед планированием задач, во многом по аналогии с тем, как SQL Server конструирует план выполнения запроса перед осуществлением операции выборки данных или какой-то манипуляции над ними. DAG предоставляют информацию о преобразованиях, которые будут выполняться над данными, и Spark получает возможность интеллектуально объединять многие из этих преобразований в единую стадию, а затем разом выполнить все преобразования — эта идея впервые появилась в Project Dryad, созданном Microsoft Research.
Кроме того, Spark умеет интеллектуально сохранять данные в памяти с помощью конструкций Resilient Distributed Datasets (RDD) (я поясню их потом) и разделять их между DAG. Такое разделение данных между DAG позволяет быстрее выполнять задания, чем то было бы возможно без этой оптимизации. На рис. 1 показан DAG для «hello world» в области обработки данных — подсчета слов в заданном текстовом файле. Обратите внимание на то, как несколько операций, а именно чтение текстового файла, flatMap и map, объединяются в единую стадию, что обеспечивает более быстрое выполнение. В следующем примере приведен реальный код на Scala (поскольку Spark написан на Scala), выполняющий подсчет слов (даже если вы никогда не видели ни одной строки кода на Scala, готов поспорить, что вы моментально поймете, как реализовать подсчет слов в Spark):
val wordCounts = textFile.flatMap(line => line.split(" ")).map(word => (word,1))
.reduceByKey((a, b) => a + b)
Рис. 1. Directed Acyclic Graph (DAG) для подсчета слов
Stage 0 | Стадия 0 |
textFile | textFile |
flatMap | flatMap |
map | map |
reduceByKey | reduceByKey |
Вторая причина популярности Spark — ее модель программирования. Реализация подсчета слов в Spark (в коде на Scala) гораздо проще, чем аналогичная реализация в Hadoop MapReduce. Помимо программирования на Scala, вы можете создавать приложения Spark на Java и Python, который я использую в этой статье. До появления Spark аналитики и программисты, работающие с Hadoop MapReduce, были вынуждены использовать неестественную парадигму разбиения сложной задачи на набор операций Map и Reduce. В случае Spark для преобразования и анализа данных применяется функциональное программирование, знакомое любому .NET-разработчику, работающему с LINQ и лямбда-функциями.
Вскоре вы увидите, какой простой и в тоже время мощной является модель программирования Spark. Но, прежде чем писать функциональный код, одинаково хорошо работающий с большими и малыми наборами данных, вы должны создать распределенный кластер машин, на который установлены все необходимые компоненты Spark и который готов принимать передаваемые вами задачи. Создание кластера Spark было бы совершенно устрашающим делом, если бы вам пришлось создавать и конфигурировать этот кластер самостоятельно. К счастью, Microsoft Cloud позволяет выполнить всю подготовку несколькими щелчками кнопки мыши. В следующем разделе я расскажу, как это делается.
Развертывание кластера Spark
Теперь давайте создадим кластер HDInsight в Azure. Считайте HDInsight собирательным термином, охватывающим технологии Hadoop и Spark; Hadoop HDInsight и Spark HDInsight — это два примера управляемых сервисов Azure для работы с большими данными.
Чтобы подготовить кластер Spark, войдите в Azure Portal (portal.azure.com) и последовательно щелкайте New | Data + Analytics | HDInsight | Create. Заполните свойства HDInsight Cluster, указав Name, Cluster Type = Spark, задайте Cluster Operating System как Linux (поскольку Spark разработан и развивается в Linux), а поле версии оставьте без изменений, как показано на рис. 2. Укажите остальную требуемую информацию, включая удостоверения для входа на кластер и имя учетной записи хранилища/контейнера. Затем щелкните кнопку Create. Процесс создания кластера занимает от 15 до 30 мин.
Рис. 2. Создание кластера Spark в Azure
По окончании процесса создания вы получите плитку на портале Azure, представляющую только что созданный кластер HDInsight. Наконец, вы можете заняться кодом! Однако давайте сначала рассмотрим среду программирования и языки, доступные при использовании Spark.
Программировать в среде Spark можно несколькими способами. Во-первых, можно обращаться к оболочке Spark командой spark-shell, как поясняется по ссылке bit.ly/1ON5Vy4, и после установления SSH-сеанса с ведущим узлом кластера Spark писать Scala-программы в стиле REPL, а также передавать программные конструкции по одной за раз (не волнуйтесь, если это предложение прозвучало так, будто оно написано на иностранном языке, — просто переходите прямо к варианту 3). Во-вторых, можно выполнять приложения Scala в Spark (передавая их командой spark-submit, которая поясняется по ссылке bit.ly/1fqgZHY). Наконец, есть возможность использовать блокноты Jupyter (jupyter.org) поверх Spark. Если вы не знакомы с проектом Jupyter, то блокноты Jupyter (Jupyter notebooks) предоставляют визуальную интерактивную веб-среду, в которой выполняются скрипты для анализа данных. Я предпочитаю именно этот метод анализа и убежден, что, как только вы опробуете их, они станут и для вас предпочтительным методом программирования в Spark. Azure HDInsight устанавливает среду блокнотов Jupyter поверх кластера за вас, облегчая начало работы с ними.
Чтобы получить доступ к блокнотам Jupyter, щелкните плитку Cluster Dashboards, как показано на рис. 3, затем щелкните плитку блокнота Jupyter в выскальзывающем окне (slide-out window). Войдите, используя удостоверения, указанные вами при создании кластера, и вы должны увидеть, что среда Jupyter готова принять новые блокноты или редактировать старые. Теперь щелкните кнопку New в правом верхнем углу и выберите Python 2. Почему Python 2? Дело в том, что, хотя сама Spark написана на Scala и большая часть программирования в Spark осуществляется на Scala, вам доступен мост (bridge) Python через Pyspark. Кстати, ведутся ожесточенные споры о том, на чем следует кодировать — на Scala или Python. Каждый язык имеет свои явные преимущества, причем Scala потенциально быстрее, а Python, возможно, более выразителен и является самым распространенным языком программирования в анализе данных (bit.ly/1WTSemP). Это позволяет вам использовать выразительный, но лаконичный Python при программировании поверх кластера Spark. Я тоже предпочитаю Python для анализа данных (наряду с системой R) и могу использовать все мощные библиотеки для Python, к которым я привык.
Рис. 3. Доступ к блокнотам Jupyter в Azure HDInsight через Cluster Dashboards
Вы наконец готовы погрузить в выполнение ML и задач анализа данных в блокнотах Jupyter.
Машинное обучение в Spark
Чтобы проиллюстрировать ML в Spark, я воспользуюсь примером «небольших» данных для классических задач ML: распознавания цифр, написанных от руки, таких как в почтовых индексах на конвертах. Хотя набор данных совсем невелик, изящество этого решения в том, что, если объем данных потребуется увеличить в тысячу раз, вы сможете добавить больше машин в кластер и по-прежнему выполнять анализ данных за приемлемое время. Никаких изменений в демонстрируемый здесь код не понадобится — инфраструктура Spark сама позаботится о распределении рабочей нагрузки по индивидуальным машинам в кластере. Файл данных, который я буду использовать, также является классическим; его часто называют набором данных MNIST, и он содержит 50 000 рукописных цифр, готовых для анализа. Хотя набор данных MNIST можно получить во многих местах в сети, веб-сайт Kaggle предоставляет удобный доступ к этим данным (bit.ly/1QJN20c).
Небольшое отступление для тех, кто не знаком с kaggle.com. На нем проводятся соревнования по ML, где почти 500 000 аналитиков со всего мира соревнуются на денежные призы или за шанс попасть на собеседование в одну из лидирующих компаний в области ML. Я принимал участие в пяти соревнованиях на Kaggle, и, если вы склонны к соперничеству, вы получите большое удовольствие. Кроме того, сам сайт Kaggle работает в Azure!
Давайте остановимся на минутку и разберемся в содержимом файла train.csv. Каждая его строка является попиксельным представлением изображения размером 28×28, содержащим рукописную цифру вроде показанной на рис. 4 (на этой иллюстрации приведено увеличенное изображение). Первое поле указывает, что это за цифра; остальные поля содержат значения интенсивности свечения пикселей от 0 до 255 всех 784 пикселей (28×28).
Рис. 4. Увеличенный образец цифры 7, представленной в наборе данных MNIST
Открыв новый блокнот Jupyter, вставьте в первую ячейку следующий код:
from pyspark import SparkContext
from pyspark.mllib.regression import LabeledPoint
from pyspark.mllib.tree import RandomForest
import time
sc = SparkContext(appName="MNISTDigitsDT")
#TODO: предоставьте свой путь к train.csv в строках ниже,
# для загрузки файлов в облако и чтения их полного пути
# можно использовать Azure Storage Explorer
fileNameTrain = 'wasb://datasets@chuvyrov.blob.core.windows.net/trainingsample.csv'
fileNameTest = 'wasb://datasets@chuvyrov.blob.core.windows.net/validationsample.csv'
mnist_train = sc.textFile(fileNameTrain)
mnist_test = sc.textFile(fileNameTest)
Этот код импортирует необходимые библиотеки для ML в Spark, затем указывает местонахождение файлов данных, которые будут использоваться для обучения и проверки модели (заметьте, что эти файлы должны располагаться в вашей учетной записи хранилища, доступной из Spark в Microsoft Cloud через ссылку вида wasb://). Наконец, последние две строки создают RDD из текстовых файлов. RDD — это закулисная магия Spark; они являются распределенными структурами данных, но сложность их реализации обычно скрывается от программиста или пользователя. Кроме того, вычисление этих RDD происходит в отложенном режиме, после чего они сохраняются, так что, если вам вновь понадобится использовать какой-то RDD, он будет немедленно доступен без повторного вычисления или извлечения. Когда вы манипулируете RDD, это инициирует генерацию DAG и выполнение запланированных задач (staged tasks) в кластере Spark, о чем я уже вкратце рассказывал.
Нажмите Shift+Enter внутри ячейки Jupyter, что выполнить вставленный вами код. Отсутствие новостей должно быть хорошим признаком (если вы не получили сообщение об ошибке, значит, все в порядке), и теперь RDD должны быть доступны вам для запроса и манипуляций. Эти RDD на данный момент содержат строки текста, разделенного запятыми, поскольку именно в таком виде были данные MNIST.
Следующий шаг — определение простой функции, которая поможет вам преобразовать эти строки текста в собственный объект LabeledPoint. Этот объект требуется алгоритму ML, используемому для обучения и прогнозирования. Если в двух словах, этот объект содержит массив характеристик (features) (иногда характеристики удобно рассматривать как поля в таблице базы данных) или характеристики одной точки данных, а также метку или значение, прогнозировать которое вы пытаетесь обучить. Если пока это звучит не совсем понятно, то, возможно, поможет просмотр MNIST-файла train.csv. Вы заметите, что каждая строка в train.csv имеет в первом поле цифру, а во всех остальных — числа от 0 до 255. Первое поле называется меткой, поскольку мы пытаемся обучить машину, как предсказывать это число. Все остальные поля являются характеристиками, и все вместе они называются вектором характеристик (feature vector). Эти характеристики — яркость каждого оцифрованного элемента изображения цифры, где 0 — черный, 255 — белый, а прочие значения в этом диапазоне определяют градации яркости. Все изображения имеют 28 пикселей в высоту и 28 пикселей в ширину, что дает 784 поля, где содержатся яркости элементов изображения в файле train.csv (28*28=784).
Скопируйте и вставьте следующую функцию в новую ячейку в своем блокноте Jupyter:
def parsePoint(line):
# Разбираем строку текста в объект MLlib LabeledPoint
values = line.split(',')
values = [0 if e == '' else int(e) for e in values]
return LabeledPoint(int(values[0]), values[1:])
Нажмите Shift+Enter для выполнения кода. Теперь вы определили функцию parsePoint, которая была вычислена Spark и доступна вам для использования с только что считанным набором данных. Эта функция принимает одну строку разделенного запятыми текста, разбивает его на индивидуальные значения и преобразует их в объект LabeledPoint.
Затем вы выполняете некоторую базовую чистку данных, чтобы подготовить их для алгоритма обучения; к сожалению, этот алгоритм пока недостаточно интеллектуален, чтобы самостоятельно узнать, какая часть данных имеет прогностическое значение. Поэтому пропустите заголовок файла train.csv, используя прием, позаимствованный со stackoverflow.com; потом вы выведете первую строку полученного RDD, чтобы быть уверенным, что его состояние именно такое, какое и ожидалось:
# Пропускаем заголовок (header)
header = mnist_train.first() # извлекаем заголовок
# Отфильтровываем заголовок с помощью лямбды
mnist_train = mnist_train.filter(lambda x:x !=header)
print mnist_train.first()
Теперь вы готовы применить подход с функциональным программированием с помощью оператора .map(parsePoint) в следующем разделе для преобразования RDD в формат, пригодный для ML-алгоритмов в Spark. Это преобразование, по сути, заключается в разборе каждой строки внутри mnist_train RDD и конвертации этого RDD в набор объектов LabeledPoint.
RDD и интерактивность: основы мощи Spark
Здесь есть несколько важных вопросов. Прежде всего вы имеете дело со структурой данных, распределенной в кластере машин (RDD), однако сложность распределенных вычислений почти полностью скрывается от вас. Вы применяете функциональные преобразования к RDD, а Spark закулисно оптимизирует всю обработку в кластере доступных машин:
labeledPoints = mnist_train.map(parsePoint)
# Разбиваем данные на обучающий и проверочный наборы
# (для проверки выделяется 30% исходных данных)
(trainingData, testData) = labeledPoints.randomSplit([0.7, 0.3])
print mnist_train.first()
Хотя последняя строка (с выражением print) может показаться тривиальной, возможность интерактивного запроса больших наборов данных — крайне мощная функция, которая практически отсутствовала в мире больших наборов данных до Spark. В ваших проектах анализа данных и манипуляций над большими наборами данных это будет очень полезный метод проверки того, что преобразования, которые вы считаете примененными, действительно применены. Это еще одно преимущество Spark над другими инфраструктурами обработки больших данных.
Также обратите внимание на разбиение данных на обучающий и проверочный наборы данных с помощью функции randomSplit. Здесь идея в том, чтобы создать ML-модель, используя данные в trainingData RDD, и проверить ее, используя данные в testData RDD, как вы вскоре увидите в коде.
Теперь вы готовы применить ML-алгоритм к распределенному набору данных, который вы только что создали (mnist_train). В качестве краткого обзора вспомните, что в задачах ML почти во всех случаях есть два разных этапа. Во-первых, вы обучаете модель, используя известный набор данных с известными выводами; во-вторых, делаете прогнозы на основе модели, созданной (или обученной) на первом этапе. В следующем коде для обучения модели используется алгоритм RandomForest, доступный в инфраструктуре Spark Machine Learning (Spark MLLib). RandomForest — это один из нескольких распределенных алгоритмов, имеющихся в Spark MLLib и один из самых мощных. Вставьте следующий код в новую ячейку:
depthLevel = 4
treeLevel = 3
# Запускаем таймер
start_time = time.time()
# Ниже создается модель, используя алгоритм случайного леса
# (Random Forest) из Spark MLLib
model = RandomForest.trainClassifier(trainingData, numClasses=10,
categoricalFeaturesInfo={},
numTrees=treeLevel, featureSubsetStrategy="auto",
impurity='gini', maxDepth=depthLevel, maxBins=32)
print("Training time --- %s seconds ---" % (time.time() - start_time))
Заметьте, как этот код начинает замерять время выполнения алгоритмов, а потом задает начальные значения для некоторых параметров, ожидаемых алгоритмом RandomForest, а именно для maxDepth и numTrees. Запустите этот код, нажав Shift+Enter. Возможно, вас интересует, что представляет собой этот RandomForest и как он работает? RandomForest — это ML-алгоритм, который на самом высоком уровне конструирует множество решающих деревьев (decision trees) на основе данных, случайным образом выбирая переменную, на которой разделяет решающее дерево (т. е. одно дерево могло бы быть столь же простым, как «если пиксель в правом нижнем углу белый, то, вероятно, это номер 2»), а затем принимает окончательное решение после опроса всех сконструированных деревьев. К счастью, распределенная версия этого алгоритма уже имеется в Spark. Однако ничто не мешает вам писать собственные алгоритмы, приди такое вам в голову; распределенный алгоритм k-Nearest Neighbors (kNN) (k ближайших соседей) все еще отсутствует в инфраструктуре Spark.
Теперь вернемся к задаче распознавания цифр MNIST. Если ваша среда похожа на мою, вы должны получить время выполнения алгоритма обучения около 21 секунды. То есть за 21 секунду вы обучили модель (используя алгоритм RandomForest), и ее уже можно применять для предсказания цифр, которые вы видите, по заданным характеристикам, проанализированных вами. Теперь вы готовы к самой важной части задачи ML — к предсказаниям на основе созданной вами модели. Кроме того, вы готовы и к оценке точности этих предсказаний, как показано на рис. 5.
Рис. 5. Оценка точности предсказаний
# Оцениваем модель на тестовых экземплярах
# и вычисляем ошибку проверки
1 # Запуск таймера
2 start_time = time.time()
3 # Предсказываем, используя ранее созданную модель
4 predictions = model.predict(testData.map(lambda x: x.features))
5 # Проверяем предсказания, используя проверочный набор данных
6 labelsAndPredictions = testData.map(lambda lp: lp.label).zip(predictions)
7 testErr = labelsAndPredictions.filter(lambda (v, p): v != p).count() /
8 float(testData.count())
9 print('Test Error = ' + str(testErr))
10 print("Prediction time --- %s seconds ---" % (time.time() - start_time))
11 #print('Learned classification tree model:')
12 #print(model.toDebugString())
Обратите внимание на конструкцию model.predict в строке 4 на рис. 5. Это строка, в которой делается собственно предсказание на основе ранее созданной вами модели. В строках 5–7 вы используете некоторые базовые стратегии манипуляции данными для временного соотнесения (через функцию zip) предсказанных значений с реальными. Затем вы просто вычисляете процентную долю правильных предсказаний и выводите время выполнения.
Результат этой начальной классификации со столь высокой ошибкой слегка обескураживает (т. е. получается, что ваша модель работает с коэффициентом погрешности, близким к 43%?). Вы можете улучшить модель, используя концепцию гиперпараметрического поиска с варьированием (grid hyperparameter search), где вы пробуете серии значений при создании модели, тут же проверяете и в конечном счете получаете схождение гиперпараметрических значений, которые дают вам лучшие результаты в целом. Иначе говоря, проводите группу систематических экспериментов, чтобы определить, какие параметры модели дают наилучшее прогнозируемое значение.
Гиперпараметры, к которым вы будете применять поиск с варьированием, — numTrees и maxDepth; вставьте код с рис. 6 в новую ячейку блокнота.
Рис. 6. Итеративный поиск оптимальных параметров с варьированием в алгоритме RandomForest в Spark
1 bestModel = None
2 bestTestErr = 100
3 # Определяем диапазон пробуемых гиперпараметров
4 maxDepths = range(4,10)
5 maxTrees = range(3,10)
6
7 # Перебираем параметры в циклах для глубины и уровней дерева
8 for depthLevel in maxDepths:
9 for treeLevel in maxTrees:
10
11 # Запускаем таймер
12 start_time = time.time()
13 # Обучаем ML-классификатор RandomForest
14 model = RandomForest.trainClassifier(trainingData,
15 numClasses=10, categoricalFeaturesInfo={},
16 numTrees=treeLevel, featureSubsetStrategy="auto",
17 impurity='gini', maxDepth=depthLevel, maxBins=32)
18
19 # Делаем предсказания, используя созданную выше модель
20 predictions = model.predict(testData.map(lambda x: x.features))
21 # Связываем предсказания с реальными значениями
и определяем коэффициент погрешности
22 labelsAndPredictions = testData.map(lambda lp: lp.label).zip(predictions)
23 testErr = labelsAndPredictions.filter(lambda (v, p): v != p)
24 .count() / float(testData.count())
25
26 # Выводит информацию о модели по мере продвижения на каждой итерации цикла
27 print ('\maxDepth = {0:.1f}, trees = {1:.1f}: trainErr = {2:.5f}'
28 .format(depthLevel, treeLevel, testErr))
29 print("Prediction time --- %s seconds ---" % (time.time() - start_time))
30 if (testErr < bestTestErr):
31 bestModel = model
32 bestTestErr = testErr
33
34 print ('Best Test Error: = {0:.3f}\n'.format(bestTestErr))
Заметьте, как в строках 8–14 вы сканируете набор параметров numTrees для алгоритма случайного леса с 3 до 10, создавая модели и оценивая их результаты. Затем в строках 30–32 вы захватываете модель, если она дает более хорошие результаты, чем предыдущие модели, или отбрасываете ее в ином случае. Дайте этому циклу поработать некоторое время; в конце его работы вы должны получать значения ошибки предсказаний не выше 10%.
Заключение
Когда я начал писать эту статью, моей главной целью было показать на примерах, насколько легко программировать в Spark, особенно если вы любите функциональное программирование и Azure. Дополнительной целью было желание продемонстрировать, как можно выполнять задачи ML на больших и малых наборах данных с помощью библиотеки Spark MLLib. Попутно я хотел объяснить, почему Spark работает с распределенными данными быстрее, чем ее предшественники, и поделиться некоторые любопытными фактами о том, как мы пришли к тому что имеем сегодня в области аналитики распределенных данных.
Microsoft вносит большой вклад в будущее больших данных, ML, аналитики и Spark. Сейчас самое время осваивать эти технологии, чтобы в полной мере задействовать возможности вычислений и анализа данных с высочайшей степенью масштабируемости, обеспечиваемой Microsoft Cloud. Azure обеспечивает все условия для быстрой работы Spark и ее масштабирования для операций с большими наборами данных, и все это поддерживается гарантиями уровня обслуживания, которые можно ожидать лишь от лучших провайдеров корпоративных облаков.
Теперь, когда вы создали ML-модель и сделали прогнозы на известных данных, вы также можете строить прогнозы на других данных, которые не включают метки правильности (true labels), а именно на файле test.csv с Kaggle.com. Затем вы можете передать свои результаты Kaggle.com, чтобы поучаствовать в соревновании по распознаванию цифр на этой платформе. Я хотел бы быть в курсе результатов, которых вы добьетесь. Вопросы, комментарии, предложения и достижения в ML отправляйте мне по электронной почте на адрес eugene.chuvyrov@microsoft.com.
Евгений Чувыров (Eugene Chuvyrov) — архитектор облачных решений в Microsoft в группе Technical Evangelism and Development, где помогает компаниям в окрестностях залива Сан-Франциско в полной мере использовать преимущества высочайшей масштабируемости в Microsoft Cloud. Хотя в настоящее время основное внимание уделяет партнерам в области высочайшей масштабируемости обработки данных, не забывает о своем прошлом опыте в качестве инженера ПО и любит писать готовый к использованию в облаке код на C#, JavaScript и Python. Следите за его заметками в Twitter: @EugeneChuvyrov.
Выражаю благодарность за рецензирование статьи эксперту Microsoft Бруно Теркали (Bruno Terkaly).