3

我正在查看Spark 1.5 数据框/行 api和逻辑回归的实现。据我了解,train其中的方法首先将转换dataframeRDD[LabeledPoint]as,

override protected def train(dataset: DataFrame): LogisticRegressionModel = {
     // Extract columns from data.  If dataset is persisted, do not persist oldDataset.
     val instances = extractLabeledPoints(dataset).map {
           case LabeledPoint(label: Double, features: Vector) => (label, features)
     }
...

然后进行特征标准化等。

我感到困惑的是,DataFrameis 的类型RDD[Row]并且Row允许有 any valueTypes,例如(1, true, "a string", null)似乎是数据帧的有效行。如果是这样,extractLabeledPoints上面的意思是什么?似乎它仅选择Array[Double]作为Vector. 如果数据框中的列是 会发生什么strings?另外,整数分类值会发生什么?

在此先感谢,尼基尔

4

2 回答 2

5

让我们暂时忽略 Spark。一般来说,包括逻辑回归在内的线性模型需要数字自变量。它不以任何方式特定于 Spark / MLlib。如果输入包含分类或有序变量,则必须首先对这些变量进行编码。一些语言,比如 R,以透明的方式处理这个问题:

> df <- data.frame(x1 = c("a", "b",  "c", "d"), y=c("aa", "aa", "bb", "bb"))
> glm(y ~ x1, df, family="binomial")

Call:  glm(formula = y ~ x1, family = "binomial", data = df)

Coefficients:
(Intercept)          x1b          x1c          x1d  
 -2.357e+01   -4.974e-15    4.713e+01    4.713e+01  
...

但真正在幕后使用的是所谓的设计矩阵:

> model.matrix( ~ x1, df)
  (Intercept) x1b x1c x1d
1           1   0   0   0
2           1   1   0   0
3           1   0   1   0
4           1   0   0   1
...

跳过细节它与OneHotEncoderSpark 中执行的转换类型相同。

import org.apache.spark.mllib.linalg.Vector
import org.apache.spark.ml.feature.{OneHotEncoder, StringIndexer}

val df = sqlContext.createDataFrame(Seq(
    Tuple1("a"), Tuple1("b"), Tuple1("c"), Tuple1("d")
)).toDF("x").repartition(1)

val indexer = new StringIndexer()
  .setInputCol("x")
  .setOutputCol("xIdx")
  .fit(df)

val indexed = indexer.transform(df)

val encoder = new OneHotEncoder()
    .setInputCol("xIdx")
    .setOutputCol("xVec")

val encoded = encoder.transform(indexed)

encoded
    .select($"xVec")
    .map(_.getAs[Vector]("xVec").toDense)
    .foreach(println)

Spark 更进一步,所有特征,即使算法允许名义/有序自变量,也必须Double使用spark.mllib.linalg.Vector. 如果spark.ml它是一DataFrame列,则spark.mllibspark.mllib.regression.LabeledPoint.

但是,根据模型对特征向量的解释可能会有所不同。如上所述,对于线性模型,这些将被解释为数值变量。因为Naive Bayes这些被认为是名义上的。如果模型同时接受数值变量和名义变量 Spark 并以不同的方式处理每个组,例如决策/回归树,您可以提供categoricalFeaturesInfo参数。

值得指出的是,因变量也应进行编码,Double但与自变量不同,可能需要正确处理额外的元数据。如果您查看indexedDataFrame,您会发现StringIndexer不仅 transforms x,而且还添加了属性:

scala> org.apache.spark.ml.attribute.Attribute.fromStructField(indexed.schema(1))
res12: org.apache.spark.ml.attribute.Attribute = {"vals":["d","a","b","c"],"type":"nominal","name":"xIdx"}

最后,一些Transformersfrom ML,如VectorIndexer,可以根据不同值的数量自动检测和编码分类变量。

于 2015-09-05T04:51:42.973 回答
0

在评论中复制 zero323 的说明:

在传递给 MLlib/ML 估计器之前的分类值必须编码为Double. 有很多内置的转换器,例如StringIndexerOneHotEncoder在这里可以提供帮助。如果算法以不同于数字特征的方式处理分类特征,例如DecisionTree,您可以使用 来识别哪些变量是分类的categoricalFeaturesInfo

最后,一些转换器使用列上的特殊属性来区分不同类型的属性。

于 2015-09-04T17:32:27.160 回答