Почему spark.ml не реализует никаких алгоритмов spark.mllib?

Следуя Spark MLlib Guide, мы можем прочитать, что Spark имеет две библиотеки для машинного обучения:

  • spark.mllib, построенный поверх RDD.
  • spark.ml, построенный поверх Dataframes.

В соответствии с этим и этим вопросом о StackOverflow, Dataframes лучше (и новее), чем RDD и следует использовать, когда это возможно.

Проблема заключается в том, что я хочу использовать общие алгоритмы машинного обучения (например: "Частый шаблон" , Naive Bayes и т.д.) и spark.ml (для данных) не предоставляют таких методов, только spark.mllib (для RDD) предоставляет эти алгоритмы.

Если Dataframes лучше, чем RDD, и упомянутое руководство рекомендует использовать spark.ml, почему не являются обычными методами машинного обучения, реализованными в этой библиотеке?

Что здесь отсутствует?

Ответ 1

Spark 2.0.0

В настоящее время Spark сильно продвигается к API DataFrame с постоянным устареванием RDD API. В то время как число встроенных алгоритмов "ML" растет, основные моменты, выделенные ниже, по-прежнему действительны и внутренне многие этапы реализуются непосредственно с использованием RDD.

См. также: Переключить API MLlib на основе RDD в режим обслуживания в Spark 2.0

Spark & ​​lt; 2.0.0

Я предполагаю, что основная недостающая точка заключается в том, что алгоритмы spark.ml вообще не работают с DataFrames. Поэтому на практике это скорее вопрос обертки ml, чем что-либо еще. Даже встроенная реализация ML (например ml.recommendation.ALS использует RDDs внутренне).

Почему бы не реализовать все с нуля поверх DataFrames? Скорее всего, потому, что только очень небольшое подмножество алгоритмов машинного обучения действительно может извлечь выгоду из оптимизаций, которые в настоящее время реализованы в Catalyst, не говоря уже об эффективном и естественном применении с использованием DataFrame API/SQL.

  • Большинство алгоритмов ML требуют эффективной библиотеки линейной алгебры, а не табличной обработки. Использование оптимизатора на основе затрат для линейной алгебры может быть интересным дополнением (я думаю, что уже есть), но похоже, что сейчас здесь нечего выиграть.
  • API DataFrames дает вам очень мало контроля над данными. Вы не можете использовать разделитель *, вы не можете получить доступ к нескольким записям в то время (я имею в виду, например, целый раздел), вы ограничены относительно небольшим набором типов и операций, вы не можете использовать изменяемые данные структур и т.д.
  • Catalyst применяет локальные оптимизации. Если вы передадите выражение SQL-запроса/DSL, оно может его проанализировать, изменить порядок, применить ранние прогнозы. Все это то, что большие, но типичные масштабируемые алгоритмы требуют итеративной обработки. Так что вы действительно хотите оптимизировать, это целый рабочий процесс, и только DataFrames не быстрее, чем обычные RDD, и в зависимости от операции может быть на самом деле медленнее.
  • Итеративная обработка в Spark, особенно с объединениями, требует строгого контроля над количеством разделов, иначе происходят странные вещи. DataFrames не дают вам контроля над разделением. Кроме того, DataFrame/Dataset не предоставляют встроенные возможности контрольной точки (исправлено в Spark 2.1), что делает итеративную обработку практически невозможной без уродливых хаков
  • Игнорирование информации о низком уровне реализации некоторых групп алгоритмов, таких как FPM, не очень хорошо вписывается в модель, определенную ML-конвейерами.
  • Многие оптимизации ограничены собственными типами, а не расширениями UDT, такими как VectorUDT.

Есть еще одна проблема с DataFrames, которая не связана с машинным обучением. Когда вы решите использовать DataFrame в своем коде, вы отдаете почти все преимущества статической типизации и вывода типа. Это очень субъективно, если вы считаете, что это проблема или нет, но одно точно, оно не кажется естественным в мире Scala.

Что касается лучшего, более нового и более быстрого, я бы посмотрел на Deep Dive в Оптимизатор Catalyst Spark SQLs, в частности часть, относящуюся к квазикварталам

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


* Это было изменено в Spark 1.6, но оно по-прежнему ограничено по умолчанию HashPartitioning