2017-09-05 3 views
0

Ich habe eine Feature-Spalte, die in einem Vektor von Vektoren mit Spark VectorAssembler Spark verpackt ist, wie folgt. data ist der Input-Datenrahmen (vom Typ spark.sql.DataFrame).Konvertieren Sie einen Spark Vector von Features in ein Array

val featureCols = Array("feature_1","feature_2","feature_3") 
val featureAssembler = new VectorAssembler().setInputCols(featureCols).setOutputCol("features") 
val dataWithFeatures = featureAssembler.transform(data) 

Ich entwickle einen benutzerdefinierten Classifier des Classifier und ClassificationModel Entwickler-API. ClassificationModel erfordert die Entwicklung einer -Funktion, die einen Vektor vorhergesagter Etiketten aus dem Modell ausgibt.

def predictRaw(features: FeaturesType) : Vector 

Diese Funktion wird durch die API-Satz und einen Parameter, Eigenschaften von FeaturesType und gibt einen Vektor (die in meinem Fall I ein Funke DenseVector als DenseVector verlängert den Vector trait sein nehmen).

Aufgrund der Verpackung durch VectorAssembler ist die Spalte features vom Typ Vector und jedes Element ist selbst ein Vektor der ursprünglichen Merkmale für jedes Trainingsbeispiel. Zum Beispiel:

verfügt Spalte - vom Typ Vector
[1,0, 2,0, 3,0] - element1, selbst ein Vektor
[3.5, 4.5, 5.5] - element2, selbst ein Vektor

Ich muß Extrahieren Sie diese Features in eine Array[Double], um meine Logik predictRaw() zu implementieren. Idealerweise würde ich folgendes Ergebnis mag, um die Kardinalität zu erhalten:

`val result: Array[Double] = Array(1.0, 3.5, 2.0, 4.5, 3.0, 4.5)` 

das heißt in Spaltenhauptordnung wie ich diese in eine Matrix verwandeln.

Ich habe versucht:

val array = features.toArray // this gives an array of vectors and doesn't work 

ich auch zur Eingabe der Funktionen als Dataframe-Objekt versucht haben, eher als ein Vektor aber die API eine Vektor erwartet, aufgrund der Verpackung der Merkmale von VectorAssembler . Zum Beispiel arbeitet diese Funktion von Natur aus, sondern auf die API nicht konform ist, wie es FeaturesType ist erwartet Vektor zu sein, wie zu Datenrahmen gegen:

def predictRaw(features: DataFrame) :DenseVector = { 
    val featuresArray: Array[Double] = features.rdd.map(r => r.getAs[Vector](0).toArray).collect 
//rest of logic would go here 
} 

Mein Problem ist, dass features vom Typ Vector, nicht DataFrame. Die andere Möglichkeit könnte sein, das Paket features als DataFrame zu verpacken, aber ich weiß nicht, wie das geht, ohne VectorAssembler zu verwenden.

Alle Vorschläge geschätzt, danke! Ich habe mir Access element of a vector in a Spark DataFrame (Logistic Regression probability vector) angesehen, aber das ist in Python und ich benutze Scala. Dadurch erhalten Sie eine neue Spalte

import org.apache.spark.ml.linalg.DenseVector 
val toArr: Any => Array[Double] = _.asInstanceOf[DenseVector].toArray 
val toArrUdf = udf(toArr) 
val dataWithFeaturesArr = dataWithFeatures.withColumn("features_arr",toArrUdf('features)) 

:

Antwort

2

Wenn Sie nur DenseVector in Array [Double] das ist ziemlich einfach mit der UDF konvertieren

|-- features_arr: array (nullable = true) 
| |-- element: double (containsNull = false) 
+0

Hallo - Ich bin nicht sicher, ob eine dieser wirklich tun, ganz das, was ich will. Mit der obigen UDF-Funktion extract_features bekomme ich scheinbar die gleiche Spalte wie die Feature-Spalte: + -------------------- + -------- ------------ + | Eigenschaften | extrahierte_features | + -------------------- + -------------------- + | [-9.5357, 0.016682 ... | [-9.5357, 0.01668 ... | + -------------------- + -------------------- + – LucieCBurgess

+0

Mit anderen Worten die Funktionen Spalte und extrahierte Features sehen genau gleich aus. Ich kann zu jedem Element so kommen: nur Top 1 Reihe. Wenn ich dann folgendes mache: 'val featuresArray1: Array [Double] = temp.rdd.map (r => r.getAs [Double] (0)) .collect' (mit den Indexelementen 1 und 2) - fragt einen anderen Frage, wie der Raum ausgeht – LucieCBurgess

+0

Ich denke, das Problem ist, Array gibt ein Array mit 3 Elementen für jede Zeile und dann habe ich schwer auf diese zuzugreifen. Ich werde eine separate Frage stellen, damit das klarer ist. Bitte sehen Sie, danke – LucieCBurgess

0

Hier ist ein Weg, (ohne udf) um einen Datagram (String, Array) aus einem Dataframe (String, Vector) zu erhalten.Hauptidee ist, eine Zwischen RDD zu verwenden als Vektor zu werfen, und verwenden Sie seine toArray Methode:

val arrayDF = vectorDF.rdd 
    .map(x => x.getAs[String](0) -> x.getAs[Vector](1).toArray) 
    .toDF("word","array") 
Verwandte Themen