Как векторизовать столбцы DataFrame для алгоритмов ML?

имеют DataFrame с некоторыми категориальными строковыми значениями (например, uuid | url | browser).

Я хотел бы преобразовать его в ******, чтобы выполнить алгоритм ML, который принимает двойную матрицу.

В качестве метода конвертации я использовал StringIndexer (искра 1.4), которые отображали мои строковые значения в двойные значения, поэтому я определил такую ​​функцию:

def str(arg: String, df:DataFrame) : DataFrame =
 (
 val indexer = new StringIndexer().setInputCol(arg).setOutputCol(arg+"_index")
 val newDF = indexer.fit(df).transform(df)
 return newDF
 )

Теперь проблема в том, что я буду перебирать столбец foreach из df, вызывать эту функцию и добавлять (или преобразовывать) исходный столбец строки в разборный двойной столбец, поэтому результат будет выглядеть следующим образом:

Начальный df:

[String: uuid|String: url| String: browser]

Финал df:

[String: uuid|******: uuid_index|String: url|******: url_index|String: browser|******: Browser_index]

Заранее спасибо

1 ответ

Вы можете просто foldLeft по столбцам Array:

val transformed: DataFrame = df.columns.foldLeft(df)((df, arg) => str(arg, df))

Тем не менее, я буду утверждать, что это не очень хороший подход. Поскольку src отбрасывает StringIndexerModel, он не может использоваться, когда вы получаете новые данные. Из-за этого я бы рекомендовал использовать Pipeline:

import org.apache.spark.ml.Pipeline
val transformers: Array[org.apache.spark.ml.PipelineStage] = df.columns.map(
 cname => new StringIndexer()
 .setInputCol(cname)
 .setOutputCol(s"${cname}_index")
)
// Add the rest of your pipeline like VectorAssembler and algorithm
val stages: Array[org.apache.spark.ml.PipelineStage] = transformers ++ ???
val pipeline = new Pipeline().setStages(stages)
val model = pipeline.fit(df)
model.transform(df)

VectorAssembler можно включить следующим образом:

val assembler = new VectorAssembler()
 .setInputCols(df.columns.map(cname => s"${cname}_index"))
 .setOutputCol("features")
val stages = transformers :+ assembler

Вы также можете использовать RFormula, который менее настраиваемый, но гораздо более краткий:

import org.apache.spark.ml.feature.RFormula
val rf = new RFormula().setFormula(" ~ uuid + url + browser - 1")
val rfModel = rf.fit(dataset)
rfModel.transform(dataset)

licensed under cc by-sa 3.0 with attribution.