apache-spark - one - spark ml pca
¿Cómo manejar las características categóricas con spark-ml? (4)
Hay un componente de la línea ML llamado StringIndexer
que puede usar para convertir sus cadenas a Double de manera razonable. http://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.ml.feature.StringIndexer tiene más documentación, y http://spark.apache.org/docs/latest/ml-guide.html muestra cómo construir tuberías.
¿Cómo manejo datos categóricos con spark-ml
y no spark-mllib
?
Aunque la documentación no es muy clara, parece que los clasificadores, por ejemplo RandomForestClassifier
, LogisticRegression
, tienen un argumento featuresCol
, que especifica el nombre de la columna de características en el DataFrame
, y un argumento labelCol
, que especifica el nombre de la columna de clases etiquetadas en el DataFrame
Obviamente, quiero usar más de una característica en mi predicción, así que traté de usar el VectorAssembler
para poner todas mis características en un único vector en featuresCol
.
Sin embargo, VectorAssembler
solo acepta tipos numéricos, tipo booleano y tipo de vector (de acuerdo con el sitio web de Spark), por lo que no puedo poner cadenas en mi vector de características.
¿Cómo debo proceder?
Puede convertir un tipo de columna de cadena en un marco de datos de chispa en un tipo de datos numéricos utilizando la función de conversión.
from pyspark.sql import SQLContext
from pyspark.sql.types import DoubleType, IntegerType
sqlContext = SQLContext(sc)
dataset = sqlContext.read.format(''com.databricks.spark.csv'').options(header=''true'').load(''./data/titanic.csv'')
dataset = dataset.withColumn("Age", dataset["Age"].cast(DoubleType()))
dataset = dataset.withColumn("Survived", dataset["Survived"].cast(IntegerType()))
En el ejemplo anterior, leemos en un archivo csv como un marco de datos, convertimos los tipos de datos de cadena por defecto en enteros y dobles, y sobrescribimos el marco de datos original. Luego podemos usar el VectorAssembler para combinar las características en un solo vector y aplicar su algoritmo favorito de Spark ML.
Solo quería completar la respuesta de Holden.
Desde Spark 1.4.0 , MLLib también proporciona la función OneHotEncoder , que asigna una columna de índices de etiquetas a una columna de vectores binarios, con un valor único como máximo.
Esta codificación permite algoritmos que esperan funciones continuas, como la Regresión logística, para usar características categóricas
Consideremos el siguiente DataFrame
:
val df = Seq((0, "a"),(1, "b"),(2, "c"),(3, "a"),(4, "a"),(5, "c"))
.toDF("id", "category")
El primer paso sería crear el DataFrame
indexado con el StringIndexer
:
import org.apache.spark.ml.feature.StringIndexer
val indexer = new StringIndexer()
.setInputCol("category")
.setOutputCol("categoryIndex")
.fit(df)
val indexed = indexer.transform(df)
indexed.show
// +---+--------+-------------+
// | id|category|categoryIndex|
// +---+--------+-------------+
// | 0| a| 0.0|
// | 1| b| 2.0|
// | 2| c| 1.0|
// | 3| a| 0.0|
// | 4| a| 0.0|
// | 5| c| 1.0|
// +---+--------+-------------+
A continuación, puede codificar el categoryIndex
con OneHotEncoder
:
import org.apache.spark.ml.feature.OneHotEncoder
val encoder = new OneHotEncoder()
.setInputCol("categoryIndex")
.setOutputCol("categoryVec")
val encoded = encoder.transform(indexed)
encoded.select("id", "categoryVec").show
// +---+-------------+
// | id| categoryVec|
// +---+-------------+
// | 0|(2,[0],[1.0])|
// | 1| (2,[],[])|
// | 2|(2,[1],[1.0])|
// | 3|(2,[0],[1.0])|
// | 4|(2,[0],[1.0])|
// | 5|(2,[1],[1.0])|
// +---+-------------+
Voy a proporcionar una respuesta desde otra perspectiva, ya que también me preguntaba sobre las características categóricas con respecto a los modelos basados en árboles en Spark ML (no MLlib), y la documentación no es tan clara sobre cómo funciona todo.
Cuando transforma una columna en su marco de datos utilizando pyspark.ml.feature.StringIndexer
los metadatos adicionales se almacenan en el marco de datos que marca específicamente la característica transformada como una característica categórica.
Cuando imprima el marco de datos, verá un valor numérico (que es un índice que se corresponde con uno de sus valores categóricos) y, si observa el esquema, verá que su nueva columna transformada es de tipo double
. Sin embargo, esta nueva columna que creó con pyspark.ml.feature.StringIndexer.transform
no es solo una doble columna normal, sino que tiene meta-datos adicionales asociados que son muy importantes. Puede inspeccionar estos metadatos mirando la propiedad de metadata
del campo apropiado en el esquema de su marco de datos (puede acceder a los objetos de esquema de su marco de datos mirando su esquema de marco de datos)
Este metadato adicional tiene dos implicaciones importantes:
Cuando llame a
.fit()
cuando utilice un modelo basado en árbol, escaneará los metadatos de su marco de datos y reconocerá los campos codificados como categóricos con transformadores comopyspark.ml.feature.StringIndexer
(como se indicó anteriormente, hay otros transformadores que también tendrán este efecto, comopyspark.ml.feature.VectorIndexer
). Debido a esto, NO es necesario codificar sus características en caliente después de haberlas transformado con StringIndxer cuando se usan modelos basados en árboles en spark ML (sin embargo, aún tiene que realizar una codificación en caliente cuando se usan otros modelos que no lo hacen). Manejar categóricamente categorías como la regresión lineal, etc.).Debido a que estos metadatos se almacenan en el marco de datos, puede usar
pyspark.ml.feature.IndexToString
para revertir los índices numéricos a los valores categóricos originales (que a menudo son cadenas) en cualquier momento.