Привет!
В прошлый раз мы познакомились с инструментом Apache Spark, который в последнее время становится чуть ли не самым популярным средством для обработки больших данных и в частности, Large Scale Machine Learning. Сегодня мы рассмотрим подробнее библиотеку MlLib, а именно — покажем, как решать задачи машинного обучения — классификации, регресии, кластеризации, а также коллаборативной фильтрации. Кроме этого покажем, как можно исследовать признаки с целью отбора и выделения новых (т.н. Feature Engineering, о котором мы говорили ранее, причем не один раз).
План
Прежде всего посмотрим, как хранить объекты нашей обучающей выборки, как считать базовые статистики признаков, после чего — алгоритмы машинного обучения (классификация, регрессия, кластеризация) и наконец, рассмотрим пример построения рекомендательной системы — т.н. методы коллаборативной фильтрации, а если быть точнее — один из самых распространенных алгоритмов ALS.
Вектора
Для простых «плотных» векторов есть специальный класс Vectors.dense:
from pyspark.mllib.linalg import Vectors
my_vec = Vectors.dence ([1.12, 4.10, 1.5, -2.7, 3.5, 10.7, 0.7])
Для «разреженных» векторов используется класс Vectors.sparse:
from pyspark.mllib.linalg import Vectors
my_vec = Vectors.sparse(10, [0,2,4,9], [-1.2, 3.05, -4.08, 0.46])
Здесь первым аргументом является количество признаков (длина вектора), далее идут списком — номера ненулевых признаков, и после — сами значения признаков.
Размеченные вектора
Для размеченных точек в Spark'е есть специальный класс LabeledPoint:
from pyspark.mllib.regression import LabeledPoint
my_point = LabeledPoint(1.0, my_vec)
Где в классе LabeledPoint мы имеем LabeledPoint.features — любой из описанных выше векторов, а LabeledPoint.label — это, соответственно, метка, которая может принимать любое действительное значение в случае задачи регрессии и значения [0.0,1.0,2.0,...] — для задач классификации
Работа с признаками
Не секрет, что зачастую, чтобы построить хороший алгоритм машинного обучения, достаточно просто посмотреть на признаки, отобрать из наиболее релевантные или придумать новые. Для этой цели в спарке класс Statistics, с помощью которого можно делать все эти вещи, например:
from pyspark.mllib.stat import Statistics
summary = Statistics.colStats(features)
# meas of features
summary.mean
# non zeros features
summary.numNonzeros
# variance
summary.variance
# correlations of features
Statistics.corr(features)
Помимо этого, в Spark'е есть огромное количество дополнительных возможностей вроде сэмплирования, генерации стандартных признаков (вроде TF-IDF для текстов), а также такая важная вещь, как масштабирование признаков (читателю предлагается после прочтения данной статьи посмотреть это в документации). Для последнего есть специальный класс Scaler:
from pyspark.mllib.feature import StandardScaler
scaler = StandardScaler(withMean=True, withStd=True).fit(features)
scaler.transform (features.map(lambda x:x.toArray()))
Единственное, что важно помнить — в случае разреженных векторов это не работает и стратегию масштабирования надо продумывать под конкретную задачу. Теперь перейдем непосредственно к задачам машинного обучения.
Классификация и регрессия
Линейные методы
Самыми распространенными методами как всегда являются линейные классификаторы. Обучение линейного классификатора сводится к задаче выпуклой минимизации функционала от вектора весов. Различие заключается в выборе функции потерь, функции регуляризации, количества итераций и множества других параметров. Для примера, рассмотрим ниже логистическую функцию потерь (и, соответственно, т.н. метод логистической регрессии), 500 итераций и L2 — регуляризацию.
import pyspark.mllib.classification as cls
model = cls.LogisticRegressionWithSGD.train(train, iterations=500, regType="l2")
Аналогично делается и линейная регрессия:
import pyspark.mllib.regression as regr
model = regr.RidgeRegressionWithSGD.train(train)
Наивный Байес
В этом случае, алгоритм обучения принимает на вход всего 2 параметра — саму обучающую выборку и параметр сглаживания:
from pyspark.mllib.classification import NaiveBayes
model = NaiveBayes.train(train, 8.5)
model.predict(test.features)
Решающие деревья
В спарке, как и во многих других пакетах, реализованы деревья регрессии и классификации. Алгоритм обучения принимает на вход множество параметров, такие, как множество классов, максимальная глубина дерева. Также алгоритму необходимо указать, какие категории имеют категориальные признаки, а также множество других параметров. Однако одним из самых важных из них при обучении деревьев является так называемый impurity — критерий вычисления так называемой information gain, который обычно может принимать следующие значения: entropy и gini — для задач классификации, variance — для задач регрессии. Для примера рассмотрим бинарную классификацию с параметрами, определенными ниже:
from pyspark.mllib.tree import DecisionTree
model = DecisionTree.trainClassifier(train, numClasses=2, impurity='gini', maxDepth=5)
model.predict(test.map(lambda x: x.features))
Random Forest
Случайные леса, как известно, является одними из универсальных алгоритмов и следовало ожидать, что в этом инструменте они будут реализованы. Используют они деревья, описанные выше. Здесь точно также есть методы trainClassifier и trainRegression — для обучения классификатора и функции регрессии соответственно. Одними из самых важных параметров являются — количество деревьев в лесу, уже известный нам impurity, а также featureSubsetStrategy — количество признаков, которые рассматриваются при разбиении на очередном узле дерева (подробнее о значениях — см. документацию). Соответственно, ниже пример бинарной классификации с помощью 50 деревьев:
from pyspark.mllib.tree import RandomForest
model = RandomForest.trainClassifier(train, numClasses=2, numTrees=50, featureSubsetStrategy="auto", impurity='gini', maxDepth=20, seed=12)
model.predict(test.map(lambda x:x.features))
Кластеризация
Как и везде, в спарке реализован всем известный алгоритм KMeans, обучение которого принимает на вход непосредственно датасет, число кластеров, число итераций, а также стратегию выбора начальных центров кластеров (параметр initializationMode, который по умолчанию имеет значение k-means, а также может принимать значение random):
from pyspark.mllib.clustering import KMeans
clusters = KMeans.train(features, 3, maxIterations=100, runs=5, initializationMode="random")
clusters.predict(x.features))
Коллаборативная фильтрация
Учитывая, что самый известный пример применения Больших Данных — это рекомендательная система, было бы странным, если бы самые простейшие алгоритмы не были реализованы во многих пакетах. Это касается и Spark'а. В нем реализован алгоритм ALS (Alternative Least Square) — пожалуй, один из самых известных алгоритмов коллаборативной фильтрации. Описание самого алгоритма заслуживает отдельной статьи. Здесь только скажем в двух словах, что алгоритм фактически занимается разложением матрицы отзывов (строки которой — это пользователи, а столбцы — продукты) — на матрицы продукт — топик и топик-пользователь, где топики — это некоторые скрытые переменные, смысл которых зачастую не понятен (вся прелесть алгоритма ALS как раз в том, чтобы сами топики и их значения найти). Суть этих топиков в том, что каждый пользователь и каждый фильм теперь характеризуются набором признаков, а скалярное произведение этих векторов — это и есть оценка фильма конкретного пользователя. Обучающая выборка для этого алгоритма задается в виде таблицы userID -> productID -> rating. После чего делается обучение модели с помощью ALS (который, также как и другие алгоритмы, принимает на вход множество параметров, прочитать о которых предлагается читателю самостоятельно):
from pyspark.mllib.recommendation import ALS
model = ALS.train (ratings, 20, 60)
predictions = model.predictAll(ratings.map (lambda x: (x[0],x[1])))
Заключение
Итак, мы кратко рассмотрели библиотеку MlLib из фреймворка Apache Spark, который разрабатывался для распределенной обработки больших данных. Напомним, что основным преимуществом данного инструмента, как обсуждалось ранее, является то, что данные можно кэшировать в оперативной памяти, что позволяет существенно ускорять вычисления в случае итеративных алгоритмов, какими и являются большинство алгоритмов машинного обучения.
Автор: akrot