我正在查看Spark 1.5
dataframe/row api和implementation进行逻辑回归。据我了解,其中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
答案 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.ml
为DataFrame
列,则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
。有很多内置的变换器,如StringIndexer
或OneHotEncoder
,在这里可以提供帮助。如果算法以不同于数字的方式处理分类要素,例如DecisionTree
,则使用categoricalFeaturesInfo
确定哪些变量是分类的。
最后,一些变换器在列上使用特殊属性来区分不同类型的属性。