Apache spark Spark.ml LogisticReturnal是否仅假设数字特征?

Apache spark Spark.ml LogisticReturnal是否仅假设数字特征?,apache-spark,apache-spark-sql,apache-spark-ml,apache-spark-mllib,Apache Spark,Apache Spark Sql,Apache Spark Ml,Apache Spark Mllib,我在查看Spark 1.5和逻辑回归的数据。据我所知,其中的train方法首先将dataframe转换为RDD[LabeledPoint]As override protected def train(dataset: DataFrame): LogisticRegressionModel = { // Extract columns from data. If dataset is persisted, do not persist oldDataset. val ins

我在查看Spark 1.5和逻辑回归的数据。据我所知,其中的
train
方法首先将
dataframe
转换为
RDD[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)
     }
...
然后进行特征标准化等

我感到困惑的是,
数据帧
的类型是
RDD[Row]
可以有任何
值类型
,例如
(1,true,“a string”,null)
似乎是数据帧的有效行。如果是这样的话,上面的
提取标记点是什么意思?它似乎只选择了
Array[Double]
作为
Vector
中的特征值。如果数据框中的列是
字符串
,会发生什么情况?另外,整型分类值会发生什么变化

提前感谢,,
Nikhil在评论中复制zero323的澄清:


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


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

让我们暂时忽略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  
...
跳过细节,这与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更进一步,所有特征,即使算法允许标称/顺序自变量,也必须使用
Spark.mllib.linalg.Vector
存储为
Double
。在
spark.ml
的情况下,它是
spark.mllib
中的
DataFrame
列,
spark.mllib.regression.LabeledPoint
中的字段

但是,根据模型的不同,特征向量的解释可能会有所不同。如上所述,对于线性模型,这些将被解释为数值变量。对于
朴素贝叶斯
而言,这些被认为是名义上的。若模型同时接受数值变量和名义变量,并以不同的方式处理每个组,如决策树/回归树,则可以提供参数

值得指出的是,因变量也应编码为
Double
,但与自变量不同,可能需要正确处理额外的元数据。如果查看
索引的
数据帧,您将看到
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"}

最后,来自
ML
的一些
转换器可以根据不同值的数量自动检测和编码分类变量。

分类值在传递给MLlib/ML估计器之前必须编码为
。有相当多的内置变压器,如或,可以在这里有所帮助。如果算法以与数字特征不同的方式处理分类特征,例如
DecisionTree
,您可以使用
categoricalFeaturesInfo
来确定哪些变量是分类变量。最后,一些转换器在列上使用特殊属性来区分不同类型的属性。@zero323我认为您的这两个答案是公认的答案。介意回答吗(不是评论)?@zero323,因此似乎用户有责任在处理之前调整数据帧。这是有意义的,因为没有特别的方法可以知道某个变量是否是分类变量(特别是在整数类标签的情况下)。只是他们的API并不清楚。在一个地方,他们展示了一个带有
任何
valueType列的行示例,在其他地方,他们只说
train(dataset)
@NikhilJJoshi这是可能的,ML的一些工具可以为您处理这一点,但这不是应该隐式完成的事情。
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"}