2016-06-21 6 views
2

Ich versuche, die org.apache.spark.ml.clustering.KMeans-Klasse zu erweitern, oder Proxy, so dass K = 1 autorisiert ist.Wie zu erweitern (oder Proxy) eine Scala-Klasse mit privaten Konstruktor

class K1Means extends Estimator{ 

    final val kmeans = new KMeans() 
    val k = 1 

    override def setK(value:Int) { 
     if(value >1){ 
      this.kmeans.setK(value) 
     } 
    } 

    override def fit(dataset: DataFrame): KMeansModel = { 
     if(this.k == 1){ 
      /* super specific to my case */ 
      val avg_sample = Vectors.zeros(
       dataset 
       .select("scaledFeatures") 
       .take(1)(0)(0) // first row 
       .asInstanceOf[DenseVector] // was of type Any 
       .size 
      ) // with the scaling the average value of each column is 0 
      var centers_local = Array(avg_sample) 
      return new KMeansModel(centers_local) 
     } 
     else{ 
      return this.kmeans.fit(dataset) 
     } 
    } 
// every method then calls this.kmeans.method() 
} 

ich das versucht habe, aber new KMeansModel(centers_local) ist nicht berechtigt, da KMeansModel einen privaten Konstruktor hat. Hier ist die Fehlermeldung:

constructor KMeansModel in class KMeansModel cannot be accessed in class K1Means

Ich habe auch versucht KMeansModel zu verlängern, so kann ich meine eigene erstellen und senden Sie es:

class K1MeansModel(centers: Array[DenseVector]) extends KMeansModel{} 

Aber es scheitert auch: constructor KMeansModel in class KMeansModel cannot be accessed in class K1MeansModel

+0

Die Dokumente scheint nicht mit Ihnen zu stimmen: https://spark.apache.org/docs/1.6.0/api/java/org/apache/spark/ml/clustering/KMeansModel.html sieht mir öffentlich –

+0

Können Sie Ihre Frage bearbeiten und die eigentliche Fehlermeldung ausgeben? –

+0

Ok, ich muss neu formulieren. Der Konstruktor ist privat, vielleicht ist es der richtige Weg, es zu sagen.Es kann nur von KMeans instanziiert werden. – Borbag

Antwort

2

Es gibt mehrere Probleme hier, beginnend mit KMeansModel ist privat: https://github.com/apache/spark/blob/4f83ca1059a3b580fca3f006974ff5ac4d5212a1/mllib/src/main/scala/org/apache/spark/ml/clustering/KMeans.scala#L102

Warum ist das ein Problem? Sie könnten Ihren eigenen Proxy auf die von Ihnen vorgeschlagene Weise schreiben, aber um die "Fit" -Methode zu überschreiben, muss der von dieser Funktion zurückgegebene Datentyp ein KMeansModel oder kompatibel sein (sagen wir "K1MeansModel"), wie folgt:

class K1MeansModel extends KMeansModel{ 
    // ... 
} 

class K1Means extends KMeans{ 

    final val kmeans = new KMeans() 
    // ... 

    override def fit(dataset: DataFrame): KMeansModel = { 
     if(this.k == 1){ 
      // ... 
      return new K1MeansModel(centers_local) 
     } 
     else{ 
      return this.kmeans.fit(dataset) 
     } 
    } 
} 

Aber ja, weil KMeansModel privat ist, dann ist das nicht möglich. Sie könnten also denken: "Warum nicht neu implementieren?". In der Tat könnten Sie einfach kopieren & fügen Sie den gesamten Code von KMeansModel, von GitHub.

Die Definition von KMeansModel sieht wie folgt aus:

class KMeansModel (
     override val uid: String, 
     private val parentModel: MLlibKMeansModel) 
    extends Model[KMeansModel] with KMeansParams { } 

Aber ja, weil KMeansParams ist privat, das ist nicht möglich. Sie könnten also denken: "Warum nicht neu implementieren?". In der Tat könnten Sie einfach kopieren & fügen Sie den gesamten Code KMeansParams, von GitHub.

Die Definition von KMeansParams sieht wie folgt aus:

trait K1MeansParams 
    extends Params 
     with HasMaxIter 
     with HasFeaturesCol 
     with HasSeed 
     with HasPredictionCol 
     with HasTol { } 

Aber ja, weil HasMaxIter, HasFeaturesCol, HasSeed, HasPredictionCol, HasTol alle privat sind, das nicht möglich ist. ... Du hast die Idee.


TL; DR ja, könnten Sie gehen und neu implementieren (kopieren & Paste) eine Tonne Funken Klassen in das Projekt, um nur KMeans außer Kraft setzen. Ich zähle mindestens 7 Klassen, die Kopie & einfügen erfordern würde. Das fühlt sich für mich beschissen an. Stattdessen würde ich empfehlen, den Code direkt zu Apache Spark hinzuzufügen. Fork the Spark GitHub repo, fügen Sie Ihren Code für K = 1 direkt in die ml.KMeans-Klasse und damit fertig sein.

Verwandte Themen