Обработка функций в Spark ML в действии

искусственный интеллект Spark

Эта статья подготовлена ​​технической командой OPPO Internet, укажите автора для перепечатки. В то же время приглашаем обратить внимание на нашу общедоступную учетную запись: OPPO_tech, чтобы поделиться с вами передовыми интернет-технологиями и деятельностью OPPO.

Смысл обработки признаков

Обычно данные, которые мы получаем, содержат грязные данные или шум. Перед обучением модели эти данные необходимо предварительно обработать, иначе лучшая модель может быть только «мусор на входе, мусор на выходе».

Предварительная обработка данных в основном включает три части: извлечение признаков, преобразование признаков и выбор признаков.

2. Извлечение признаков

Извлечение признаков обычно относится к процессу извлечения признаков из необработанных данных.

1. Счетчик-векторизатор

(1) Определение и использование: векторизатор счетчика нумерует все текстовые слова и подсчитывает частоту слова в документе как вектор признаков.

(2) Пример кода в spark мл

import org.apache.spark.ml.feature.{CountVectorizer, CountVectorizerModel}
val df = spark.createDataFrame(Seq(
      (0, Array("a","e","a","d","b")),
      (1, Array("a","c","b","d","c","f","a","b")),
      (2, Array("a","f"))
)).toDF("id", "words")    
var cv_model = new CountVectorizer().setInputCol("words").setOutputCol("features").setVocabSize(10).setMinDF(2).fit(df)
val cv1 = cv_model.transform(df)
cv1.show(false)

Примечание. Векторизатор подсчета объединит все данные вместе для дедупликации, чтобы сформировать словарь, и определит, нужно ли вводить словарь с помощью двух параметров setVocabSize и setMinDF. Где setVocabSize определяет длину словаря, а setMinDF определяет, сколько различных образцов должно появиться в словаре перед входом в словарь. В приведенном выше примере длина словаря установлена ​​равной 10, и он войдет в словарь только тогда, когда он появится как минимум в двух образцах, и только a, b, d и f могут войти в словарь. c и e появляются только в одном фрагменте данных, поэтому частота слов не будет учитываться.

2. Термин «частотно-обратная частота документа» (TF-IDF)

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

Например, слова, которые могут представлять общие значения, встречаются в документе много раз, но эти слова не имеют значения для идентификации документа. Нам нужны специальные слова, которые встречаются много раз и могут встречаться в небольшом количестве документов, чтобы эти слова могли идентифицировать документы. В крайнем случае, слово «мы» может встречаться более чем в N документах и ​​быть бесполезным. Многие детские ботиночки скажут, что мы можем удалить эти слова стоп-словами, да. И я говорю о такого рода словах, которые встречаются в широком диапазоне, но бесполезны для идентификации за пределами стоп-слов.

(2) Пример кода в spark мл

import org.apache.spark.ml.feature.{HashingTF, IDF, Tokenizer}
val wordsData = spark.createDataFrame(Seq(
      "传奇 游戏 战士".split(" "),
      "苹果 梨 香蕉".split(" "),
      "苹果 手机 流畅".split(" ")
    ).map(Tuple1.apply)).toDF("words")
wordsData.show(false)    
// step1 hashingTF
val hashingTF = new HashingTF().setInputCol("words").setOutputCol("rawFeatures").setNumFeatures(2000)
val featurizedData = hashingTF.transform(wordsData)
// step2 计算IDF
val idf = new IDF().setInputCol("rawFeatures").setOutputCol("features")
val idfModel = idf.fit(featurizedData)
val rescaledData = idfModel.transform(featurizedData)
rescaledData.select("words","features").show(false)

Примечание: setNumFeatures предназначен для установки длины функций. В этих трех фрагментах данных все слова, кроме «яблоко», встречаются только один раз, поэтому ценность идентификации документов относительно велика. Apple появляется в обоих данных одновременно, поэтому ценность идентифицирующих документов подавляется и становится очень низкой.

3. Вектор поворота слова (Word2Vec)

(1) Определение и использование: Вектор поворота слова предназначен для отображения слова в векторном пространстве и представления слова через набор векторов. Сходство слов можно представить, вычислив расстояние вектора.

(2) Пример кода в spark мл

import org.apache.spark.ml.feature.Word2Vec
val documentDF = spark.createDataFrame(Seq(
      "传奇 游戏 战士".split(" "),
      "苹果 梨 香蕉".split(" "),
      "传奇 游戏 种类多".split(" "),
      "苹果 手机 流畅".split(" ")
    ).map(Tuple1.apply)).toDF("text")
val word2Vec = new Word2Vec().setInputCol("text").setOutputCol("result").setVectorSize(10).setMinCount(2)
val model = word2Vec.fit(documentDF)
val result = model.transform(documentDF)
result.show(false)

Примечание: setVectorSize устанавливает длину вектора. setMinCount устанавливает минимальное количество раз, которое слово появляется в образце. Например, в приведенном выше примере мы устанавливаем длину вектора равной 10, и вектор будет преобразован только в том случае, если он встречается как минимум в двух выборках. Тогда три слова «яблоко», «легенда» и «игра» соответствуют условиям, поэтому расстояние между первыми данными и третьим вектором данных точно такое же, потому что «воин» и «многие виды» встречаются только один раз, и Он не будет использоваться для преобразования в вектор.Если для setMinCount установлено значение 1, расстояние векторного пространства между первой и третьей строками будет очень близким, но они не будут точно одинаковыми, потому что два «бойца» и Также будут рассмотрены «многие виды» слов.

3. Преобразование функций

1. Преобразование непрерывных данных в дискретные данные

1.1 Бинаризатор
  1. Определение и использование: процесс преобразования непрерывных данных в функции 0-1 в соответствии с пороговым значением.

  2. Примечание: Собственные значения, превышающие пороговое значение, будут отображаться в 1,0, а собственные значения, меньшие или равные пороговому значению, будут отображаться в 0,0; двоичный ввод inputCol поддерживает векторный (Vector) и двойной точности (Double) типы .

1.2 Дискретная рекомбинация (Bucketizer)
  1. Определение и использование: преобразование непрерывных данных в соответствующие интервалы сегментов в соответствии с правилами сегментации.

  2. Пример кода в spark мл:

import org.apache.spark.ml.feature.Bucketizer
val data = Array(-8.0, -0.5, -0.3, 0.0, 0.2, 9.0)
val splits = Array(Double.NegativeInfinity, -0.5, 0.0, 0.5, Double.PositiveInfinity)
val dataFrame = spark.createDataFrame(data.map(Tuple1.apply)).toDF("features")
val bucketizer = new Bucketizer().setInputCol("features").setOutputCol("bucketedFeatures").setSplits(splits)
bucketizer.transform(dataFrame).show(false)  

Примечание. В третьей строке кода в приведенном выше примере правило сегментации сформулировано как (отрицательная бесконечность, 0,5), [-0,5, 0), [0, 0,5), [0,5, положительное и отрицательное плохое) четыре абзаца. Каждый сегмент слева закрыт, справа открыт [а, б) режим. Когда верхняя и нижняя границы разделения неопределенны, следует добавить Double.NegativeInfinity и Double.PositiveInfinity, чтобы избежать пересечения границы.

1.3 Квантильный дискретизатор
  1. Определение и использование: преобразование непрерывных данных в соответствующие им сегменты в соответствии с правилом квантилей.

  2. Пример кода в spark мл:

import org.apache.spark.ml.feature.QuantileDiscretizer
val data = Array((0, 18.0), (1, 19.0), (2, 8.0), (3, 5.0), (4, 2.2))
var df = spark.createDataFrame(data).toDF("id", "hour")
val discretizer = new QuantileDiscretizer().setInputCol("hour").setOutputCol("result").setNumBuckets(3)
val result = discretizer.fit(df).transform(df)
result.show()

Примечание: setNumBuckets устанавливает количество сегментов квантиля равным 3. Затем разделите часовые данные на 3 сегмента.

2. Преобразование строки и индекса друг в друга

2.1 Преобразование String-Indexer (StringIndexer)
  1. Определение и использование: преобразование строковых функций в индексы. Многие модели во время обучения принимают только числовые признаки, поэтому для обучения строки необходимо преобразовать в числовые значения.

  2. Пример кода в spark мл:

import org.apache.spark.ml.feature.StringIndexer
val df = spark.createDataFrame(
  Seq((0, "a"), (1, "b"), (2, "c"), (3, "a"), (4, "a"), (5, "c"))
).toDF("id", "category")
val indexer = new StringIndexer().setInputCol("category").setOutputCol("categoryIndex")
val indexed = indexer.fit(df).transform(df)
indexed.show(false)

Примечание. Индекс отсортирован по частоте тегов. Самый распространенный индекс тега, 0, представляет наиболее часто встречающийся тег. Новые строки могут встречаться в новых наборах данных. Например, в обучающем наборе есть только a,b,c, а в новом наборе данных будут a,b,c,d. Есть две стратегии работы с вновь появляющейся строкой d. Первый — генерировать исключение (по умолчанию), а второй — полностью игнорировать строки, содержащие такие теги, переопределяя setHandleInvalid("skip").

2.2 Индексная строка (IndexToString)

Определение и использование: обычно используется в сочетании с приведенным выше конвертером строковых индексов. Сначала строковые признаки преобразуются в числовые признаки с помощью преобразователя строковых индексов, а после завершения обучения модели числовые признаки восстанавливаются в строковые признаки с помощью преобразователя индексных строк.

3. Регуляризация (нормализатор)

  1. Определение и использование: областью регуляризации является каждая строка данных, то есть каждая выборка данных. Нормализуйте каждую часть данных, вычислив p-норму. Операции регуляризации могут нормализовать входные данные и повысить производительность алгоритмов последующего обучения.

  2. Пример кода в spark мл:

import org.apache.spark.ml.feature.Normalizer
import org.apache.spark.ml.linalg.{Vector,Vectors}
val data=Seq(Vectors.dense(-1,1,1,8,56),Vectors.dense(-1,3,-1,-9,88),Vectors.dense(0,5,1,10,96), Vectors.dense(0,5,1,11,589),Vectors.dense(0,5,1,11,688))
val df=spark.createDataFrame(data.map(Tuple1.apply)).toDF("features")    
val normalizer = new Normalizer().setInputCol("features").setOutputCol("normFeatures").setP(1.0)
normalizer.transform(df).show(false)

4. Нормализация (StandardScaler)

  1. Определение и использование. Областью нормализации является каждый столбец данных, то есть каждый элемент измерения. Нормализуйте каждую функцию, чтобы она имела однородное стандартное отклонение. С одной стороны, значения разных выборок в одном и том же признаке могут сильно отличаться, и какие-то аномально маленькие или аномально большие данные будут вводить в заблуждение правильное обучение модели; с другой стороны, если распределение данных сильно разбросано , это также повлияет на результаты обучения. Вышеупомянутые два метода отражены в дисперсии будет очень большой.

  2. Пример кода в spark мл:

import org.apache.spark.ml.feature.StandardScaler
import org.apache.spark.ml.linalg.{Vector,Vectors}
val dataFrame = spark.createDataFrame(Seq(
(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)))).toDF("id", "features")
val scaler = new StandardScaler().setInputCol("features")
.setOutputCol("scaledFeatures").setWithStd(true).setWithMean(false)
val scalerModel = scaler.fit(dataFrame)
val scaledData = scalerModel.transform(dataFrame)
scaledData.show(false)

Примечание. В приведенном выше примере стандартное отклонение каждого столбца масштабируется до 1. Если стандартное отклонение объекта равно нулю, значение по умолчанию, возвращаемое для этого объекта в векторе, равно 0,0.

5. Анализ основных компонентов (PCA)

(1) Определение и использование. Анализ главных компонентов (АГК) — это статистический метод, который по существу выполняет базисное преобразование в линейном пространстве, чтобы максимизировать дисперсию преобразованных данных, спроецированных на низкоразмерное пространство. Вес или важность координатной оси определяется в соответствии с дисперсией после преобразования, и та, у которой больший вес, становится главной составляющей. В основном используется для уменьшения размерности.

(2) Пример кода в spark мл:

import org.apache.spark.ml.feature.PCA
import org.apache.spark.ml.linalg.{Vector,Vectors}
val data = Array(
  Vectors.sparse(5, Seq((1, 1.0), (3, 7.0))),
  Vectors.dense(2.0, 0.0, 3.0, 4.0, 5.0), Vectors.dense(4.0, 0.0, 0.0, 6.0, 7.0))
val df = spark.createDataFrame(data.map(Tuple1.apply)).toDF("features")
val scaledDataFrame = new StandardScaler().setInputCol("features").setOutputCol("scaledFeatures").fit(df).transform(df)
val pca = new PCA().setInputCol("features").setOutputCol("pcaFeatures").setK(3).fit(scaledDataFrame)
val pcaDF = pca.transform(scaledDataFrame)
pcaDF.select("features","pcaFeatures").show(false)    

Примечание. Приведение к K-мерному пространству задается setK. В приведенном выше примере изначально были 5-мерные объекты, которые были уменьшены до 3-мерных объектов с помощью pca. Собственные векторы должны быть нормализованы перед pca. Поскольку значение каждого главного компонента слишком сильно варьируется, разница составляет порядок величины. После стандартизации собственных векторов главные компоненты в основном находятся на том же уровне, и результат становится более разумным. Для выбора значения K вы можете сначала выбрать большее значение и рассчитать дисперсию модели с помощью pcaModel.explainedVariance.Когда дисперсия имеет тенденцию быть стабильной, рекомендуется выбрать соответствующее значение K.

6. Преобразование вектор-индексатор (VectorIndexer)

(1) Определение и использование: в основном используется для пакетного преобразования дискретных функций в функции категорий.

(2) Пример кода в spark мл:

import org.apache.spark.ml.feature.VectorIndexer
import org.apache.spark.ml.linalg.Vectors
val data=Seq(Vectors.dense(-1,1,1,8,56),
             Vectors.dense(-1,3,-1,-9,88),
             Vectors.dense(0,5,1,10,96), 
             Vectors.dense(0,5,1,11,589))
val df=spark.createDataFrame(data.map(Tuple1.apply)).toDF("features")    
val indexer = new VectorIndexer().setInputCol("features").setOutputCol("indexed").setMaxCategories(3)
val indexerModel = indexer.fit(df)
indexerModel.transform(df).show(false)

Примечание. Установите для setMaxCategories значение K и преобразуйте объекты, количество объектов которых меньше или равно K, в индексы. Например, в приведенном выше примере для setMaxCategories установлено значение 3, а во втором столбце есть три категории объектов, поэтому они перекодируются в 0,1,2.

7. SQL-трансформер (SQLTransformer)

(1) Определение и использование: Многие детские туфли, которые привыкли использовать sql для обработки данных, могут использовать конвертер sql для обработки функций.

(2) Пример кода в spark мл:

import org.apache.spark.ml.feature.SQLTransformer
val df = spark.createDataFrame(
  Seq((0, 1.0, 3.0), (2, 2.0, 5.0))).toDF("id", "v1", "v2")
val sqlTrans = new SQLTransformer().setStatement(
  "SELECT *, (v1 + v2) AS v3, (v1 * v2) AS v4 FROM __THIS__")
sqlTrans.transform(df).show()

8. OneHotEncoder

Горячее кодирование сопоставляет метрики меток с двоичными переменными.

9. МинМаксСкалер

Преобразуйте отдельные собственные значения в указанный диапазон, обычно [0,1].

10. Слияние векторов признаков (VectorAssembler)

Объедините исходные функции и функции, сгенерированные различными преобразователями функций, в единый вектор функций. Значения входных столбцов последовательно добавляются в новый вектор в указанном порядке.

4. Выбор функции

Выбор функций заключается в выборе этих более простых и эффективных функций из вектора функций. Он подходит для удаления избыточных функций при анализе многомерных данных и повышения производительности модели. Функции после выбора функций являются подмножеством исходных функций.

1. Векторный слайсер

На основе существующей библиотеки функций некоторые необходимые функции выбираются по индексу или имени столбца.

2. Формула РФ

Создайте вектор признаков и столбец меток с помощью формулы модели R. Он подходит для преобразования всех дискретных функций в числовое представление с помощью простого кода, когда необходимо выполнить OneHotEncoder.

3. Выбор функции хи-квадрат (ChiSqSelector)

(1) Определение и использование: выбор признаков хи-квадрат ранжирует признаки в соответствии с критерием независимости хи-квадрата для классификации. В основном, когда есть куча фич, но мы не знаем, какие из них полезные, а какие нет. Функции можно быстро отфильтровать с помощью выбора функций хи-квадрат. Недостатком является то, что скорость относительно низкая.

(2) Пример кода в spark мл:

import org.apache.spark.ml.feature.ChiSqSelector
import org.apache.spark.ml.feature.VectorIndexer
val data = Seq( (7, Vectors.dense(0.0, 0.0, 18.0, 1.0), 1.0), 
  (8, Vectors.dense(0.0, 1.0, 12.0, 0.0), 0.0), (9, Vectors.dense(1.0, 0.0, 15.0, 0.2), 0.0))
val df = spark.createDataset(data).toDF("id", "features", "clicked")
val selector = new ChiSqSelector().setNumTopFeatures(2).setFeaturesCol("features").setLabelCol("clicked").setOutputCol("selectedFeatures")
val result = selector.fit(df).transform(df)
result.show(false)

Использованная литература:

  1. spark.apache.org/docs/latest…

  2. Woohoo.Apache.wiki/pages/view P…

  3. blog.CSDN.net/Лю Линъюань…

Наконец-то настал момент~

Команда маркировки данных OPPO Business Center набирает сотрудников на несколько вакансий, мы стремимся проникать в большие данные, чтобы понять бизнес-интересы каждого пользователя OPPO. В процессе быстрого расширения данных и глубокого изучения мы искренне приглашаем вас, имеющих более двух лет опыта в области анализа данных, обработки больших данных, машинного обучения/глубокого обучения, НЛП и т. д., присоединиться к нам и расти вместе с нашей командой и бизнес!

Возобновление доставки: ping.wang#oppo.com