web-dev-qa-db-fra.com

Comment convertir un RDD avec une colonne SparseVector en un DataFrame avec une colonne en tant que vecteur

J'ai unRDDavec un tuple de valeurs (String, SparseVector) et je veux créer un DataFrame en utilisant leRDD. Pour obtenir un (libellé: chaîne, caractéristiques: vecteur) DataFrame qui est le schéma requis par la plupart des bibliothèques de l'algorithme ml. Je sais que cela peut être fait parce que HashingTF ml Library génère un vecteur lorsque la colonne features d’un DataFrame .

temp_df = sqlContext.createDataFrame(temp_rdd, StructType([
        StructField("label", DoubleType(), False),
        StructField("tokens", ArrayType(StringType()), False)
    ]))

#assumming there is an RDD (double,array(strings))

hashingTF = HashingTF(numFeatures=COMBINATIONS, inputCol="tokens", outputCol="features")

ndf = hashingTF.transform(temp_df)
ndf.printSchema()

#outputs 
#root
#|-- label: double (nullable = false)
#|-- tokens: array (nullable = false)
#|    |-- element: string (containsNull = true)
#|-- features: vector (nullable = true)

Ma question est donc la suivante: puis-je, en quelque sorte, faire en sorte que leRDDde (String, SparseVector) soit converti en un DataFrame de (String, vector). J'ai essayé avec le sqlContext.createDataFrame habituel mais il n'y a pas de DataType qui correspond à mes besoins.

df = sqlContext.createDataFrame(rdd,StructType([
        StructField("label" , StringType(),True),
        StructField("features" , ?Type(),True)
    ]))
13
Orangel Marquez

Vous devez utiliser VectorUDT ici:

# In Spark 1.x
# from pyspark.mllib.linalg import SparseVector, VectorUDT
from pyspark.ml.linalg import SparseVector, VectorUDT

temp_rdd = sc.parallelize([
    (0.0, SparseVector(4, {1: 1.0, 3: 5.5})),
    (1.0, SparseVector(4, {0: -1.0, 2: 0.5}))])

schema = StructType([
    StructField("label", DoubleType(), True),
    StructField("features", VectorUDT(), True)
])

temp_rdd.toDF(schema).printSchema()

## root
##  |-- label: double (nullable = true)
##  |-- features: vector (nullable = true)

Juste pour être complet, équivalent Scala:

import org.Apache.spark.sql.Row
import org.Apache.spark.rdd.RDD
import org.Apache.spark.sql.types.{DoubleType, StructType}
// In Spark 1x.
// import org.Apache.spark.mllib.linalg.{Vectors, VectorUDT}
import org.Apache.spark.ml.linalg.Vectors
import org.Apache.spark.ml.linalg.SQLDataTypes.VectorType

val schema = new StructType()
  .add("label", DoubleType)
   // In Spark 1.x
   //.add("features", new VectorUDT())
  .add("features",VectorType)

val temp_rdd: RDD[Row]  = sc.parallelize(Seq(
  Row(0.0, Vectors.sparse(4, Seq((1, 1.0), (3, 5.5)))),
  Row(1.0, Vectors.sparse(4, Seq((0, -1.0), (2, 0.5))))
))

spark.createDataFrame(temp_rdd, schema).printSchema

// root
// |-- label: double (nullable = true)
// |-- features: vector (nullable = true)
19
zero323

Alors que @ zero323 répond https://stackoverflow.com/a/32745924/1333621 a un sens, et que cela fonctionne pour moi - le rdd sous-jacent à la trame de données, sqlContext.createDataFrame (temp_rdd, schéma), toujours contenu Types de SparseVectors que j'ai dû effectuer les opérations suivantes pour convertir en types DenseVector - si quelqu'un souhaite utiliser une méthode plus courte/meilleure

temp_rdd = sc.parallelize([
    (0.0, SparseVector(4, {1: 1.0, 3: 5.5})),
    (1.0, SparseVector(4, {0: -1.0, 2: 0.5}))])

schema = StructType([
    StructField("label", DoubleType(), True),
    StructField("features", VectorUDT(), True)
])

temp_rdd.toDF(schema).printSchema()
df_w_ftr = temp_rdd.toDF(schema)

print 'original convertion method: ',df_w_ftr.take(5)
print('\n')
temp_rdd_dense = temp_rdd.map(lambda x: Row(label=x[0],features=DenseVector(x[1].toArray())))
print type(temp_rdd_dense), type(temp_rdd)
print 'using map and toArray:', temp_rdd_dense.take(5)

temp_rdd_dense.toDF().show()

root
 |-- label: double (nullable = true)
 |-- features: vector (nullable = true)

original convertion method:  [Row(label=0.0, features=SparseVector(4, {1: 1.0, 3: 5.5})), Row(label=1.0, features=SparseVector(4, {0: -1.0, 2: 0.5}))]


<class 'pyspark.rdd.PipelinedRDD'> <class 'pyspark.rdd.RDD'>
using map and toArray: [Row(features=DenseVector([0.0, 1.0, 0.0, 5.5]), label=0.0), Row(features=DenseVector([-1.0, 0.0, 0.5, 0.0]), label=1.0)]

+------------------+-----+
|          features|label|
+------------------+-----+
| [0.0,1.0,0.0,5.5]|  0.0|
|[-1.0,0.0,0.5,0.0]|  1.0|
+------------------+-----+
4
meyerson

ceci est un exemple dans scala pour spark 2.1

import org.Apache.spark.ml.linalg.Vector

def featuresRDD2DataFrame(features: RDD[Vector]): DataFrame = {
    import sparkSession.implicits._
    val rdd: RDD[(Double, Vector)] = features.map(x => (0.0, x))
    val df = rdd.toDF("label","features").select("features")
    df
  }

la toDF() n'a pas été reconnue par le compilateur dans le dossier d'entités

1
cipri.l