Как нормализовать данные в PySpark перед обучением ML-моделей

В прошлый раз мы говорили о методах NLP в PySpark. Сегодня рассмотрим методы нормализации и стандартизации данных модуля ML библиотеки PySpark. Читайте в нашей статье: применение Normalizer, StandardScaler, MinMaxScaler и MaxAbsScaler для нормализация и стандартизации данных.

Нормализация и стандартизация — методы шкалирования данных

Нормализация (normalization) и стандартизация (standardization) являются методами изменения диапазонов значений — шкалирования. Шкалирование особенно полезно в машинном обучении (Machine Learning), поскольку разные атрибуты могут измеряться в разных диапазонах, или значения одного атрибута варьируются слишком сильно. Например, один атрибут имеет диапазон от 0 до 1, а второй — от 1 до 1000. Для задачи регрессии второй атрибут оказывал бы большое влияние на обучение, хотя не факт, что он является более важным, чем первый. Нормализация и стандартизация отличаются своими подходами:

  • Нормализация подразумевает изменение диапазонов в данных без изменения формы распределения,

  • Стандартизация изменяет форму распределения данных (приводится к нормальному распределению).

Обычно достаточно нормализовать данные. Например, в глубоком обучении (Deep Learning) требуется перевести цвета изображений RGB из диапазона 0-255 к диапазону 0-1. А вот стандартизацию стоит применять при использование алгоритмов, которые основываются на измерении расстояний, например, k ближайших соседей или метод опорных векторов (SVM).

Normalizer: применение нормализации к строкам

Normalizer в PySpark необходим для нормализации не атрибутов (столбцов), а записей (строк) путем деления на p-норму [1]. Общая формула выглядит так:

p_norm = sum(X**p) ** (1/p)
X = X / p_norm

Единственным параметром в этом виде нормализации является p, причём

  • если p=1, то p-норма равна сумме значений каждой строки;

  • если p=∞, то p-норма равна максимальному значению в каждой строке.

Следующий код на Python демонстрирует результат при p=1:

from pyspark.ml.feature import Normalizer
from pyspark.ml.linalg import Vectors
dataFrame = spark.createDataFrame([
    (0, Vectors.dense([1.0, 0.5, -1.0]),),
    (1, Vectors.dense([2.0, 1.0, 1.0]),),
    (2, Vectors.dense([4.0, 10.0, 2.0]),)
], ["id", "features"])
normalizer = Normalizer(inputCol="features", outputCol="normFeatures", p=1.0)
l1NormData = normalizer.transform(dataFrame)
print("Normalized using L^1 norm")
l1NormData.show()
#
Normalized using L^1 norm
+---+--------------+------------------+
| id|      features|      normFeatures|
+---+--------------+------------------+
|  0|[1.0,0.5,-1.0]|    [0.4,0.2,-0.4]|
|  1| [2.0,1.0,1.0]|   [0.5,0.25,0.25]|
|  2|[4.0,10.0,2.0]|[0.25,0.625,0.125]|
+---+--------------+------------------+

В случае же p=∞  нормализация в PySpark приводит к другим результатам:

lInfNormData = normalizer.transform(dataFrame, {normalizer.p: float("inf")})
print("Normalized using L^inf norm")
lInfNormData.show()
#
Normalized using L^inf norm
+---+--------------+--------------+
| id|      features|  normFeatures|
+---+--------------+--------------+
|  0|[1.0,0.5,-1.0]|[1.0,0.5,-1.0]|
|  1| [2.0,1.0,1.0]| [1.0,0.5,0.5]|
|  2|[4.0,10.0,2.0]| [0.4,1.0,0.2]|
+---+--------------+--------------+

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

StandardScaler: приведение к нормальному распределению

StandardScaler в PySpark подразумевает приравнивание среднего значения к нулю и/или приравнивание стандартного отклонения к единице. В отличие от Normalizer применяется к атрибутам, т.е. к столбцам, а не строкам. Данный вид шкалирования стремится привести данные к нормальному распределению.

StandardScaler рассчитывается для каждого атрибута следующим образом:

z = (X – u) / s

где u — среднее значение или 0 при with_mean=False, s — стандартное отклонение или 0 при with_std=False.

Следующий код на Python показывает применение StandardScaler в PySpark:

from pyspark.ml.feature import StandardScaler

scaler = StandardScaler(inputCol="features", outputCol="scaledFeatures",
                        withStd=True, withMean=True)
scalerModel = scaler.fit(dataFrame)
scaledData = scalerModel.transform(dataFrame)
scaledData.show()
#
+---+--------------+-------------------------------------------------------------+
|id |features      |scaledFeatures                                               |
+---+--------------+-------------------------------------------------------------+
|0  |[1.0,0.5,-1.0]|[-0.872,-0.623,-1.091]|
|1  |[2.0,1.0,1.0] |[-0.218,-0.529,0.218] |
|2  |[4.0,10.0,2.0]|[1.091,1.153,0.872]   |
+---+--------------+-------------------------------------------------------------+

MinMaxScaler: приведение к диапазону [0,1]

MinMaxScaler в PySpark применяется для шкалирования в диапазоне [min,max]. Рассчитывается как

X_std = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0))
X_scaled = X_std * (max - min) + min
# при min=0, max=1 => X_std = X_scaled

где min и max задаются как минимальное и максимальное допустимое значение, по умолчанию min=0, max=1. Вот так выглядит Python-код для такого вида нормализации:

from pyspark.ml.feature import MinMaxScaler


scaler = MinMaxScaler(inputCol="features", outputCol="scaledFeatures")
scalerModel = scaler.fit(dataFrame)
scaledData = scalerModel.transform(dataFrame)
print("Features scaled to range: [%f, %f]" % (scaler.getMin(), scaler.getMax()))
scaledData.select("features", "scaledFeatures").show(truncate=False)

Результат нормализации данных в PySpark:

Features scaled to range: [0.000000, 1.000000]
+--------------+-----------------------------------------------------------+
|features      |scaledFeatures                                             |
+--------------+-----------------------------------------------------------+
|[1.0,0.5,-1.0]|[0.0,0.0,0.0]                                              |
|[2.0,1.0,1.0] |[0.3333333333333333,0.05263157894736842,0.6666666666666666]|
|[4.0,10.0,2.0]|[1.0,1.0,1.0]                                              |
+--------------+-----------------------------------------------------------+

MaxAbsScaler: приведение к диапазону [-1,1]

С помощью MaxAbsScaler в PySpark значения атрибутов приводятся к диапазону [-1,1] путем деления на максимальное абсолютное значение каждого атрибута.

from pyspark.ml.feature import MaxAbsScaler

dataFrame = spark.createDataFrame([
    (0, Vectors.dense([1.0, 0.1, -8.0]),),
    (1, Vectors.dense([2.0, 1.0, -4.0]),),
    (2, Vectors.dense([4.0, 10.0, 8.0]),)
], ["id", "features"])
scaler = MaxAbsScaler(inputCol="features", outputCol="scaledFeatures")
scalerModel = scaler.fit(dataFrame)
scaledData = scalerModel.transform(dataFrame)
scaledData.show()

В результате нормализации получились следующие значения:

+--------------+----------------+
|      features|  scaledFeatures|
+--------------+----------------+
|[1.0,0.1,-8.0]|[0.25,0.01,-1.0]|
|[2.0,1.0,-4.0]|  [0.5,0.1,-0.5]|
|[4.0,10.0,8.0]|   [1.0,1.0,1.0]|
+--------------+----------------

 

О нормализации и стандартизации в PySpark в рамках подготовки и анализа данных перед обучением алгоритмов Machine Learning вы узнаете на специализированном курсе «Курс Анализ данных с Apache Spark» в нашем лицензированном учебном центре обучения и повышения квалификации разработчиков, менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data в Москве.

Источники

  1. https://en.wikipedia.org/wiki/Norm_(mathematics)#p-norm

Поиск по сайту