Spark.ml LogisticRegression是否仅假定数字特征?

时间:2015-09-03 23:34:59

标签: apache-spark apache-spark-sql apache-spark-ml apache-spark-mllib

我正在查看Spark 1.5 dataframe/row apiimplementation进行逻辑回归。据我了解,其中train方法首先将dataframe转换为RDD[LabeledPoint]

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)
     }
...

然后它继续进行标准化等功能。

我感到困惑的是,DataFrame属于RDD[Row]类型,Row可以有valueTypes,例如(1, true, "a string", null)似乎是数据帧的有效行。如果是这样,上面extractLabeledPoints是什么意思?它似乎只选择Array[Double]作为Vector中的要素值。如果数据框中的列为strings,会发生什么?此外,整数分类值会发生什么?

提前致谢, NIKHIL

2 个答案:

答案 0 :(得分: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
...

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

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.mlDataFrame列,则spark.mllib spark.mllib.regression.LabeledPoint中的字段为Naive Bayes

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

值得指出的是,因变量也应编码为indexed,但与自变量不同,可能需要正确处理其他元数据。如果您查看StringIndexer数据框,您会看到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"} ,还会添加属性:

Transformers

最后,来自ML的{​​{1}} c:\users\mohit\appdata\local\enthought\canopy\user\lib\site- packages\IPython\utils\traitlets.py:5: UserWarning: IPython.utils.traitlets has moved to a top-level traitlets package. warn("IPython.utils.traitlets has moved to a top-level traitlets package.") c:\users\mohit\appdata\local\enthought\canopy\user\lib\site-packages\IPython\utils\pickleutil.py:3: UserWarning: IPython.utils.pickleutil has moved to ipykernel.pickleutil warn("IPython.utils.pickleutil has moved to ipykernel.pickleutil") c:\users\mohit\appdata\local\enthought\canopy\user\lib\site-packages\IPython\utils\jsonutil.py:3: UserWarning: IPython.utils.jsonutil has moved to jupyter_client.jsonutil warn("IPython.utils.jsonutil has moved to jupyter_client.jsonutil") VectorIndexer,可以根据不同值的数量自动检测和编码分类变量。

答案 1 :(得分:0)

在评论中复制来自zero323的澄清:

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

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