Подготовка датасетов в PySpark — одна из задач, которую необходимо выполнить для последующего анализа данных или обучения моделей Machine Learning. Сегодня мы поговорим о работе с векторами. Читайте в этой статье: как преобразовать столбцы в векторы, привести признаки к категориям, разрезать векторы с указанными индексами, а также как провести поэлементное умножение векторов в PySpark.
VectorAssembler: преобразование столбцов в векторы в PySpark
VectorAssembler объединяет заданный список столбцов в один векторный столбец. Является, пожалуй, самым важным векторным преобразователем в PySpark, поскольку модели машинного обучения требуют на вход векторы. VectorAssembler принимает следующие типы входных столбцов: числовые, логические и векторные. Не принимает столбцы со строками. Значения входных столбцов будут объединены в вектор в указанном порядке. В аргументе inputCols указываются столбцы, которые нужно преобразовать, а outputCol — это название выходного столбца (по умолчанию features). Пример преобразования в векторы в PySpark:
from pyspark.ml.linalg import Vectors
from pyspark.ml.feature import VectorAssembler
dataset = spark.createDataFrame(
schema=["id", "hour", "mobile", "userFeatures", "clicked"],
data=[
(0, 18, True, Vectors.dense([0.0, 10.0, 0.5]), 1.0),
(1, 12, False, Vectors.dense([1.0, 18.0, 1.5]), 0.0)
])
assembler = VectorAssembler(
inputCols=["hour", "mobile", "userFeatures"],
outputCol="features")
print('До:')
dataset.show()
print('После (обратите внимание на True и False):')
output = assembler.transform(dataset)
output.select("features", "clicked").show(truncate=False)
До: +---+----+------+--------------+-------+ | id|hour|mobile| userFeatures|clicked| +---+----+------+--------------+-------+ | 0| 18| true|[0.0,10.0,0.5]| 1.0| | 1| 12| false|[1.0,18.0,1.5]| 0.0| +---+----+------+--------------+-------+ После (обратите внимание на True и False): +-----------------------+-------+ |features |clicked| +-----------------------+-------+ |[18.0,1.0,0.0,10.0,0.5]|1.0 | |[12.0,0.0,1.0,18.0,1.5]|0.0 | +-----------------------+-------+
VectorIndexer: индексирование категорий
VectorIndexer помогает индексировать категориальные векторные признаки. Этот класс сам определяет, какие признаки в векторе являются категориальными и преобразует их в индексы категорий. В частности, VectorIndexer производит следующее:
- Принимает на вход столбец с вектором, а также параметр
maxCategories. - Решает, какие признаки должны быть категориальными, опираясь на количество уникальных значений отдельного признака. Так, те признаки, у которых количество уникальных значений меньше, чем
maxCategories, будут объявлены категориальными. - Вычисляет индексы категорий, начиная индексацию с нуля.
- Индексирует категориальные признаки и преобразует исходные значения признаков в индексы (категории).
Индексирование категориальных признаков позволяет таким алгоритмам, как Decision Trees (деревья решения) и Tree Ensembles (Ансамбли деревьев), соответствующим образом обрабатывать эти признаки.
Прочитаем результат VectorAssembler (тот, что выше), а затем применим над ним VectorIndexer, чтобы решить, какие признаки следует рассматривать как категориальные. Эти преобразованные векторы затем могут быть переданы в один из алгоритмов PySpark, например DecisionTreeRegressor.
from pyspark.ml.feature import VectorIndexer
indexer = VectorIndexer(inputCol="features", outputCol="indexed",
maxCategories=2)
indexerModel = indexer.fit(output)
categoricalFeatures = indexerModel.categoryMaps
print("Всего нашлось %d категориальных признаков" %
(len(categoricalFeatures)))
# output из примера выше (VectorAssembler)
indexedData = indexerModel.transform(output)
indexedData.select('features', 'indexed').show(truncate=False)
Всего нашлось 5 категориальных признаков +-----------------------+---------------------+ |features |indexed | +-----------------------+---------------------+ |[18.0,1.0,0.0,10.0,0.5]|[1.0,1.0,0.0,0.0,0.0]| |[12.0,0.0,1.0,18.0,1.5]|[0.0,0.0,1.0,1.0,1.0]| +-----------------------+---------------------+
VectorSlicer: разрезаем векторы
VectorSlicer принимает на вход вектор признаков и выводит новый вектор с подмассивом исходных признаков. Иными словами, это то же самое разрезание списков в Python, например, list[5:10] — взять все элементы, начиная с 5-го индекса и заканчивая 10-м.
VectorSlicer в PySpark выводит новые вектора, основываясь на следующих двух типах индексов:
- Целочисленные индексы, представляющие индексы в векторе. За это отвечает параметр
indices. - Строковые индексы, представляющие названия признаков. Указывается в параметре
names.
Должен быть указан хотя бы один из этих параметров. Ниже пример в PySpark для разрезания вектора. Диапазон индексов указан в параметре indices.
from pyspark.ml.feature import VectorSlicer
from pyspark.ml.linalg import Vectors
df = spark.createDataFrame(
schema=['userFeatures'],
data=[
[Vectors.dense([3.0, -2.0, 2.3, 4.7])],
[Vectors.dense([-2.0, 2.3, 0.0, 5.4])]
])
slicer = VectorSlicer(inputCol="userFeatures", outputCol="features",
indices=[1, 2])
output = slicer.transform(df)
output.select("userFeatures", "features").show()
+------------------+----------+ | userFeatures| features| +------------------+----------+ |[3.0,-2.0,2.3,4.7]|[-2.0,2.3]| |[-2.0,2.3,0.0,5.4]| [2.3,0.0]| +------------------+----------+
ElementwiseProduct: поэлементное умножение
Поэлементное умножение между двумя векторами в PySpark осуществляется через ElementwiseProduct. Умножаются только те элементы, которые имеют одинаковые индексы.

В аргументе scalingVec указывается, на какой вектор нужно умножить выбранный столбец. Пример в PySpark для поэлементного умножения векторов:
from pyspark.ml.feature import ElementwiseProduct
df = spark.createDataFrame(
data=[
[Vectors.dense([1.0, 2.0, 3.0]),],
[Vectors.dense([4.0, 5.0, 6.0]),]
], schema=["vector"])
transformer = ElementwiseProduct(
scalingVec=[0.0, 1.0, 2.0],
inputCol="vector", outputCol="transformedVector")
transformer.transform(df).show()
+-------------+-----------------+ | vector|transformedVector| +-------------+-----------------+ |[1.0,2.0,3.0]| [0.0,2.0,6.0]| |[4.0,5.0,6.0]| [0.0,5.0,12.0]| +-------------+-----------------+
О том, как работать с векторами Spark и подготавливать датасеты для решения реальных задач Machine Learning, вы узнаете на специализированном курсе «Машинное обучение в Apache Spark» в лицензированном учебном центре обучения и повышения квалификации разработчиков, менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data в Москве.



