0

最近我要准备一些实验材料,让学生使用 Spark/MLlib/Scala 学习机器学习。我熟悉机器学习,但对 Spark 不熟悉。

机器学习的一个“教科书”技巧是添加原始特征的更高阶项以允许非线性模型。假设,在我从 LIBSVM 文件加载训练数据后,我想添加除原始特征之外的所有特征的平方。我目前有限的知识产生以下实现:

// Load training data in LIBSVM format.
val data = MLUtils.loadLibSVMFile(sc, "data/mllib/sample_libsvm_data.txt")
val data_add_square = data.map(s => {
  val tmp = sc.parallelize(s.features.toArray)
  val tmp_sqr = tmp.map(x => x*x)
  new LabeledPoint(s.label, Vectors.dense(s.features.toArray ++ tmp_sqr.collect))
})

不知何故,我觉得这个实现太“重量级”了,看起来不是正确的方法。任何人都可以对这个问题有所了解吗?

4

1 回答 1

0

它定义了并行化每个特征向量的过度杀伤力,为每个 LabeledPoint 创建 RDD 会非常慢,你只会杀死你的 Spark 集群。

另外我建议分别使用稀疏和密集向量。如果您最初拥有稀疏向量,我强烈建议您也为平方特征构建稀疏向量。

代码看起来有点重,甚至比你的更重,但在特征向量很大的情况下应该会更好

  val data = MLUtils.loadLibSVMFile(sc, "data/mllib/sample_libsvm_data.txt")
  val dataWithSquares = data map { labeledPoint =>

    val featuresWithSquared = labeledPoint.features match {
      case denseVector: DenseVector =>
        val original = denseVector.values
        val squared = original.map(v => v * v)
        Vectors.dense(original ++ squared)

      case sparseVector: SparseVector =>
        val builder = collection.mutable.ListBuffer.empty[(Int, Double)]
        // Collect original values firsts
        sparseVector foreachActive { case (idx, v) => builder += idx -> v}
        // Collect squared
        sparseVector foreachActive { case (idx, v) => builder += idx -> v * v}
        Vectors.sparse(sparseVector.size * 2, builder)
    }

    LabeledPoint(labeledPoint.label, featuresWithSquared)
  }
于 2015-01-09T16:19:11.133 回答