2017-09-05 70 views
0

我有一個使用Spark的VectorAssembler打包成矢量向量的特徵列,如下所示。 data是輸入數據幀(類型spark.sql.DataFrame)。將特徵的Spark向量轉換爲數組

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

我開發使用ClassifierClassificationModel開發API的自定義分類。 ClassificationModel需要開發一個predictRaw()函數,該函數從模型輸出預測標籤的向量。

def predictRaw(features: FeaturesType) : Vector 

這個功能是通過該API集和需要一個參數,的FeaturesType特徵,並輸出向量(這在我的情況下,我要帶去是火花DenseVector作爲DenseVector延伸Vector性狀)。

由於VectorAssembler的包裝,features列的類型爲Vector,每個元素本身就是一個向量,它是每個訓練樣本的原始特徵的向量。例如:

設有柱 - 型的矢量
[1.0,2.0,3.0] - 元素1,本身的矢量
[3.5,4.5,5.5] - element2的,本身的載體

我需要將這些功能提取到Array[Double]以實現我的predictRaw()邏輯。理想情況下,我想下面的結果,以保持基數:

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

即在列優先的順序,我會變成一個矩陣。

我已經試過:

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

我也試着輸入功能作爲一個數據幀的對象,而不是一個向量,但API期待一個向量,由於特徵從VectorAssembler包裝。例如,該功能本身的工作原理,但並不符合API,因爲它的預期FeaturesType是矢量,而不是數據幀:

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 
} 

我的問題是features的類型Vector,不DataFrame的。另一種選擇可能是打包features作爲DataFrame,但我不知道如何做到這一點,而不使用VectorAssembler

所有建議表示感謝,謝謝!我看過Access element of a vector in a Spark DataFrame (Logistic Regression probability vector),但這是在python中,我正在使用Scala。

回答

2

如果你只是想DenseVector轉換成數組[雙]這與UDF相當簡單:

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)) 

這會給你一個新的列:

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

你好 - 我不知道。如果這些真的做我所需的東西。使用上面的extract_features UDF,我似乎獲得了與features列相同的列,如下所示:+ -------------------- + -------- ------------ + |功能| extracted_features | + + -------------------- + 0.016682 ... | [-9.5357,0.01668 ... | + -------------------- + -------------------- + – LucieCBurgess

+0

換句話說,功能列和提取的功能看起來完全一樣。我可以像這樣得到每個元素:只顯示前1行。如果我然後執行以下操作:'val featuresArray1:Array [Double] = temp.rdd.map(r => r.getAs [Double](0))。collect'(使用索引元素1和2)問題如空間不足 – LucieCBurgess

+0

我認爲問題是Array給每行3個元素的數組,然後我努力訪問它們。我要問一個單獨的問題,這更清楚。請看一下,謝謝 – LucieCBurgess

0

這裏是一個辦法(沒有udf)從數據框(字符串,矢量)獲取數據框(字符串,數組)。主要想法是使用一箇中間RDD投作爲一個載體,並利用其指定者方法:

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