tutorial spark org kmeans examples ejemplo clustering scala apache-spark apache-spark-mllib apache-spark-ml

scala - org - pyspark ml clustering



Adjuntar metadatos a la columna vectorial en Spark (1)

Contexto: tengo un marco de datos con dos columnas: etiqueta y características.

org.apache.spark.sql.DataFrame = [label: int, features: vector]

Donde características es un mllib.linalg.VectorUDT de tipo numérico creado con VectorAssembler.

Pregunta: ¿Hay alguna manera de asignar un esquema al vector de características? Quiero hacer un seguimiento del nombre de cada característica.

Intentado hasta ahora:

val defaultAttr = NumericAttribute.defaultAttr val attrs = Array("feat1", "feat2", "feat3").map(defaultAttr.withName) val attrGroup = new AttributeGroup("userFeatures", attrs.asInstanceOf[Array[Attribute]])

scala> attrGroup.toMetadata res197: org.apache.spark.sql.types.Metadata = {"ml_attr":{"attrs":{"numeric":[{"idx":0,"name":"f1"},{"idx":1,"name":"f2"},{"idx":2,"name":"f3"}]},"num_attrs":3}}

Pero no estaba seguro de cómo aplicar esto a un marco de datos existente.


Hay al menos dos opciones:

  1. En DataFrame existente puede usar as método con argumento de metadata :

    import org.apache.spark.ml.attribute._ val rdd = sc.parallelize(Seq( (1, Vectors.dense(1.0, 2.0, 3.0)) )) val df = rdd.toDF("label", "features") df.withColumn("features", $"features".as("_", attrGroup.toMetadata))

  2. Cuando crea un nuevo DataFrame convierte AttributeGroup toStructField y lo usa como un esquema para una columna determinada:

    import org.apache.spark.sql.types.{StructType, StructField, IntegerType} val schema = StructType(Array( StructField("label", IntegerType, false), attrGroup.toStructField() )) spark.createDataFrame( rdd.map(row => Row.fromSeq(row.productIterator.toSeq)), schema)

Si se ha creado VectorAssembler columna VectorAssembler utilizando la columna VectorAssembler , los metadatos que describen las columnas principales ya deben estar adjuntos.

import org.apache.spark.ml.feature.VectorAssembler val raw = sc.parallelize(Seq( (1, 1.0, 2.0, 3.0) )).toDF("id", "feat1", "feat2", "feat3") val assembler = new VectorAssembler() .setInputCols(Array("feat1", "feat2", "feat3")) .setOutputCol("features") val dfWithMeta = assembler.transform(raw).select($"id", $"features") dfWithMeta.schema.fields(1).metadata // org.apache.spark.sql.types.Metadata = {"ml_attr":{"attrs":{"numeric":[ // {"idx":0,"name":"feat1"},{"idx":1,"name":"feat2"}, // {"idx":2,"name":"feat3"}]},"num_attrs":3}

No se puede acceder directamente a los campos de vectores utilizando la sintaxis de punto (como $features.feat1 ) pero pueden ser utilizados por herramientas especializadas como VectorSlicer :

import org.apache.spark.ml.feature.VectorSlicer val slicer = new VectorSlicer() .setInputCol("features") .setOutputCol("featuresSubset") .setNames(Array("feat1", "feat3")) slicer.transform(dfWithMeta).show // +---+-------------+--------------+ // | id| features|featuresSubset| // +---+-------------+--------------+ // | 1|[1.0,2.0,3.0]| [1.0,3.0]| // +---+-------------+--------------+

Para PySpark, consulte ¿Cómo puedo declarar una columna como una característica categórica en un DataFrame para su uso en ml