2015-05-20 7 views
9

Sto usando Spark 1.3.1 con Hive e ho un oggetto row che è una lunga serie di double da passare a un costruttore Vecors.dense, comunque quando converto una Row in una array viaConverti Spark Row in Array of Doubles dattilografato

SparkDataFrame.map{r => r.toSeq.toArray} 

Tutte le informazioni sul tipo vengono perse e viene restituito un array di tipo [Qualsiasi]. Non sono in grado di lanciare questo oggetto per raddoppiare usando

SparkDataFrame.map{r => 
    val array = r.toSeq.toArray 
    array.map(_.toDouble) 
} // Fails with value toDouble is not a member of any 

come fa

SparkDataFrame.map{r => 
     val array = r.toSeq.toArray 
     array.map(_.asInstanceOf[Double]) 
    } // Fails with java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Double 

vedo che l'oggetto Row ha un'API che supporta ottenere elementi specifici come un tipo, tramite:

SparkDataFrame.map{r => 
    r.getDouble(5)} 

Tuttavia, questo evento non riesce con java.lang.Integer non può essere lanciato su java.lang.Double

Il Lavoro solo intorno ho trovato è il seguente:

SparkDataFrame.map{r => 
    doubleArray = Array(r.getInt(5).toDouble, r.getInt(6).toDouble) 
    Vectors.dense(doubleArray) } 

Tuttavia questo è eccessivamente noioso quando l'indice 5 a 1000 bisogno di essere convertito in una serie di doppie.

Un modo per indicizzare esplicitamente l'oggetto riga? sguardo

risposta

9

Let a portata di blocchi di codice 1 da 1

SparkDataFrame.map{r => 
    val array = r.toSeq.toArray 
    val doubleArra = array.map(_.toDouble) 
} // Fails with value toDouble is not a member of any 

Mappa restituisce l'ultima affermazione come tipo (cioè v'è una sorta di ritorno implicita su qualsiasi funzione a Scala che l'ultimo risultato è il tuo valore di ritorno). La tua ultima affermazione è di tipo Unit (come Void) .. perché l'assegnazione di una variabile a una val non ha alcun ritorno. Per risolverlo, estrai il compito (questo ha il vantaggio di essere meno codice da leggere).

SparkDataFrame.map{r => 
    val array = r.toSeq.toArray 
    array.map(_.toDouble) 
} 

_.toDouble non è un cast..you può farlo on a String o nel tuo caso un intero, e cambierà l'istanza del tipo di variabile. Se chiami _.toDouble su un Int, è più come fare Double.parseDouble(inputInt).

_.asInstanceOf[Double] sarebbe un cast .. che se i dati sono davvero un doppio, cambierebbe il tipo. Ma non sei sicuro di aver bisogno di lanciare qui, evita il casting se puoi.

Aggiornamento

Così è stato modificato il codice a questo

SparkDataFrame.map{r => 
    val array = r.toSeq.toArray 
    array.map(_.toDouble) 
} // Fails with value toDouble is not a member of any 

Si sta chiamando toDouble su un nodo del vostro SparkDataFrame. Apparentemente non è qualcosa che ha un metodo toDouble .. cioè non è un Int o una stringa o un lungo.

Se funziona

SparkDataFrame.map{r => 
    doubleArray = Array(r.getInt(5).toDouble, r.getInt(6).toDouble) 
    Vectors.dense(doubleArray) } 

Ma è necessario fare 5-1000 .. Perché non

SparkDataFrame.map{r => 
    val doubleArray = for (i <- 5 to 1000){ 
     r.getInt(i).toDouble 
    }.toArray 
    Vectors.dense(doubleArray) 
} 
+0

Ciò non riesce ancora con gli stessi errori. Correzione del codice per non rispecchiare questo problema – user2726995

+0

@ user2726995 dare a qualcuno un -1 che sta cercando di rispondere alla tua domanda non è un buon modo per ottenere aiuto – bwawok

+0

Apprezzo qualsiasi tipo di assistenza, un downvote non è personale, solo che il soluzione non risponde alla domanda diretta a portata di mano – user2726995

2

si dovrebbe utilizzare il Double.parseDouble da Java.

import java.lang.Double 

SparkDataFrame.map{r => 
    val doubleArray = for (i <- 5 to 1000){ 
     Double.parseDouble(r.get(i).toString) 
    }.toArray 
    Vectors.dense(doubleArray) 
} 
0

Aveva un problema simile, più difficile, in quanto le mie funzionalità non sono tutte doppie. Ecco come sono riuscito a convertire dal mio DataFrame (estratto dalla tabella Hive) a un RDD LabeledPoint:

val loaff = oaff.map(r => 
    LabeledPoint(if (r.getString(classIdx)=="NOT_FRAUD") 0 else 1, 
    Vectors.dense(featIdxs.map(r.get(_) match {case null => Double.NaN 
              case d: Double => d 
              case l: Long => l}).toArray)))