如何为 ML 算法向量化 DataFrame 列?
How to vectorize DataFrame columns for ML algorithms?
有一个带有一些分类字符串值的 DataFrame(例如 uuid|url|browser)。
我会将其转换为双精度以执行接受双精度矩阵的 ML 算法。
作为转换方法,我使用 StringIndexer (spark 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
)
现在的问题是我将迭代 df 的每个列,调用此函数并在解析的双列中添加(或转换)原始字符串列,因此结果将是:
初始 df:
[String: uuid|String: url| String: browser]
最终 df:
[String: uuid|Double: uuid_index|String: url|Double: url_index|String: browser|Double: Browser_index]
提前致谢
您可以简单地 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)
有一个带有一些分类字符串值的 DataFrame(例如 uuid|url|browser)。
我会将其转换为双精度以执行接受双精度矩阵的 ML 算法。
作为转换方法,我使用 StringIndexer (spark 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
)
现在的问题是我将迭代 df 的每个列,调用此函数并在解析的双列中添加(或转换)原始字符串列,因此结果将是:
初始 df:
[String: uuid|String: url| String: browser]
最终 df:
[String: uuid|Double: uuid_index|String: url|Double: url_index|String: browser|Double: Browser_index]
提前致谢
您可以简单地 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)