2016-06-21 5 views
2

K = 1이 허가되도록 org.apache.spark.ml.clustering.KMeans 클래스를 확장하거나 프록시하려고합니다. KMeansModel 개인 생성자를 가지고 있기 때문에개인 생성자를 사용하여 scala 클래스를 확장 (또는 프록시)하는 방법

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() 
} 
나는이 시도했다

하지만 new KMeansModel(centers_local)는 권한이 없습니다. 여기 는 오류 메시지입니다 :

constructor KMeansModel in class KMeansModel cannot be accessed in class K1Means

가 나는 또한 KMeansModel을 확장하려고, 그래서 난 내 자신을 만들고 그것을 반환 할 수 있습니다

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

을 그러나 그것은 또한 실패 : constructor KMeansModel in class KMeansModel cannot be accessed in class K1MeansModel

+0

문서가 사용자의 의견에 어긋나는 것 같습니다. https://spark.apache.org/docs/1.6.0/api/java/org/apache/spark/ml/clustering/KMeansModel.html 공개적으로 보입니다. –

+0

질문을 편집하고 실제 오류 메시지를 제공 할 수 있습니까? –

+0

좋습니다. 다시 말해야합니다. 생성자가 비공개 인 것은 어쩌면 올바른 방법 일 수 있습니다.KMeans에 의해서만 인스턴스화 될 수 있습니다. – Borbag

답변

2

여기에 몇 가지 문제가 있습니다. KMeansModel이 개인적으로 시작됩니다. https://github.com/apache/spark/blob/4f83ca1059a3b580fca3f006974ff5ac4d5212a1/mllib/src/main/scala/org/apache/spark/ml/clustering/KMeans.scala#L102

왜 이것이 문제입니까? 제안한 방식으로 자신 만의 프록시를 작성할 수 있지만 "적합"메소드를 재정의하려면 해당 함수가 반환하는 데이터 유형이 KMeansModel 또는 호환 가능해야합니다 (예 : "K1MeansModel").

KMeansModel 개인이기 때문에
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) 
     } 
    } 
} 

하지만 그래 은, 그 수는 없습니다. 그래서 "왜 다시 구현하지 않습니까?"라고 생각할 수도 있습니다. 실제로 &을 복사하여 KMeans 모델의 전체 코드를 GitHub에서 붙여 넣을 수 있습니다.

KMeansModel의 정의는 다음과 같습니다 비공개

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

하지만 그래, KMeansParams 때문에, 그 수는 없습니다. 그래서 "왜 다시 구현하지 않습니까?"라고 생각할 수도 있습니다. 실제로 &을 KMeansParams의 전체 코드를 GitHub에서 붙여 넣을 수 있습니다.

KMeansParams의 정의는 다음과 같습니다

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

하지만 그래, HasMaxIter, HasFeaturesCol, HasSeed, HasPredictionCol, HasTol 모든 개인이기 때문에, 그 수는 없습니다. ... 당신은 아이디어를 얻습니다.


TL; DR이 그래, 당신이 가서 다시 구현할 수있는 단지 KMeans을 재정의, 프로젝트에 스파크 클래스의 톤 (& 붙여 넣기 복사). 나는 적어도 7 클래스를 셉니다. 복사하려면 & 붙여 넣기가 필요합니다. 제게 엿 같은 느낌입니다. 대신 Apache Spark에 직접 코드를 추가하는 것이 좋습니다. Spark GitHub repo을 포크하고, K = 1에 대한 코드를 ml.KMeans 클래스에 직접 추가하고 함께 완료하십시오.