繁体   English   中英

如何用对象突变Scala方式编写for循环?

[英]How to write for loop with object mutation Scala way?

我需要在Scala中编写一个带有对象突变的for循环。 在机器学习中,当进行聚类(将样本分配到最佳的独立组中)时,为了确定一组中的最佳组数,将使用不同的组号运行聚类算法,并为每个组号计算一些误差度量。 最佳组数是组数图使误差度量成为弯头的地方。 在Spark ML库中, KMeans对象用于集群,其中组号作为参数传递。 因此,我计算误差度量以绘制肘图,如下所示:

var baseClusterer = new KMeans()
                   .setFeaturesCol("scaledFeatures")
                   .setPredictionCol("clusters")
                   .setSeed(0)


2 to 10 map {
   baseClusterer = baseClusterer.setK(k)
   baseClusterer.fit(scaledDF).computeCost(scaledDF)
}

我必须将Clusterer对象声明为var,并在每次迭代时对其进行变异。 有没有更多的scala方式来写这个?

您可以避免var这样做:

2 to 10 map { k =>
     baseClusterer.setK(k).fit(scaledDF).computeCost(scaledDF)
}

注意:此版本是根据注释从原始版本修改而来的

如果要对其他数据重复此操作,则可能需要考虑创建一个集群列表,然后使用该列表:

val clusterers = (2 to 10).map(k =>
  new KMeans()
    .setFeaturesCol("scaledFeatures")
    .setPredictionCol("clusters")
    .setSeed(0)
    .setk(k)
)

val costs = clusterers.map(_.fit(scaledDF).computeCost(scaledDF))

但是请参阅@BogdanVakulenko的答案,以找到重写原始版本的好方法。

还要注意,最好将相同的k多次与不同的setSeed值一起使用,以避免局部最小值。

如果我正确理解您的逻辑,也许您可​​以使用foldLeft,在该方法中,每个循环都将返回修改/更新的对象,如下所示:

val finalClusterer = (2 to 10).foldLeft(baseClusterer) { (accum, elem) =>
    val newClusterer = accum.copy(k = k)
    newClusterer.fit(scaledDF).computeCost(scaledDF)
}

这样一来,您最终将获得一个“ finalClusterer”,在其中始终以基数为原点进行操作。

编辑:我的代码使用baseClusterer作为案例类,因此复制方法。 如果您没有它,因为它似乎是一个Java类,也许您可​​以创建一个充当包装器的隐式类,然后可以在其中定义这样的方法,如下所示:

implicit class ClustererWrapper {
    def copy {
    ...
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM