apache-spark - 如何使用spark-ml处理分类特征?

标签 apache-spark categorical-data apache-spark-ml apache-spark-mllib

如何使用 spark-ml 而不是 spark-mllib 处理分类数据?

认为文档不是很清楚,似乎分类器例如RandomForestClassifierLogisticRegression 有一个 featuresCol 参数,它指定 DataFrame 中特征列的名称,和一个 labelCol 参数,它指定 DataFrame 中标记类的列的名称。

显然,我想在预测中使用多个特征,因此我尝试使用 VectorAssembler 将所有特征放入 featuresCol 下的单个向量中。

但是,VectorAssembler 仅接受数字类型、 bool 类型和向量类型(根据 Spark 网站),因此我无法将字符串放入特征向量中。

我应该如何进行?

最佳答案

我只是想完成霍尔顿的回答。

Spark 2.3.0 起,OneHotEncoder 已被弃用,并将在 3.0.0 中删除。请改用 OneHotEncoderEstimator

Scala中:

import org.apache.spark.ml.Pipeline
import org.apache.spark.ml.feature.{OneHotEncoderEstimator, StringIndexer}

val df = Seq((0, "a", 1), (1, "b", 2), (2, "c", 3), (3, "a", 4), (4, "a", 4), (5, "c", 3)).toDF("id", "category1", "category2")

val indexer = new StringIndexer().setInputCol("category1").setOutputCol("category1Index")
val encoder = new OneHotEncoderEstimator()
  .setInputCols(Array(indexer.getOutputCol, "category2"))
  .setOutputCols(Array("category1Vec", "category2Vec"))

val pipeline = new Pipeline().setStages(Array(indexer, encoder))

pipeline.fit(df).transform(df).show
// +---+---------+---------+--------------+-------------+-------------+
// | id|category1|category2|category1Index| category1Vec| category2Vec|
// +---+---------+---------+--------------+-------------+-------------+
// |  0|        a|        1|           0.0|(2,[0],[1.0])|(4,[1],[1.0])|
// |  1|        b|        2|           2.0|    (2,[],[])|(4,[2],[1.0])|
// |  2|        c|        3|           1.0|(2,[1],[1.0])|(4,[3],[1.0])|
// |  3|        a|        4|           0.0|(2,[0],[1.0])|    (4,[],[])|
// |  4|        a|        4|           0.0|(2,[0],[1.0])|    (4,[],[])|
// |  5|        c|        3|           1.0|(2,[1],[1.0])|(4,[3],[1.0])|
// +---+---------+---------+--------------+-------------+-------------+

Python中:

from pyspark.ml import Pipeline
from pyspark.ml.feature import StringIndexer, OneHotEncoderEstimator

df = spark.createDataFrame([(0, "a", 1), (1, "b", 2), (2, "c", 3), (3, "a", 4), (4, "a", 4), (5, "c", 3)], ["id", "category1", "category2"])

indexer = StringIndexer(inputCol="category1", outputCol="category1Index")
inputs = [indexer.getOutputCol(), "category2"]
encoder = OneHotEncoderEstimator(inputCols=inputs, outputCols=["categoryVec1", "categoryVec2"])
pipeline = Pipeline(stages=[indexer, encoder])
pipeline.fit(df).transform(df).show()
# +---+---------+---------+--------------+-------------+-------------+
# | id|category1|category2|category1Index| categoryVec1| categoryVec2|
# +---+---------+---------+--------------+-------------+-------------+
# |  0|        a|        1|           0.0|(2,[0],[1.0])|(4,[1],[1.0])|
# |  1|        b|        2|           2.0|    (2,[],[])|(4,[2],[1.0])|
# |  2|        c|        3|           1.0|(2,[1],[1.0])|(4,[3],[1.0])|
# |  3|        a|        4|           0.0|(2,[0],[1.0])|    (4,[],[])|
# |  4|        a|        4|           0.0|(2,[0],[1.0])|    (4,[],[])|
# |  5|        c|        3|           1.0|(2,[1],[1.0])|(4,[3],[1.0])|
# +---+---------+---------+--------------+-------------+-------------+

Spark 1.4.0 起,MLLib 还提供 OneHotEncoder特征,它将一列标签索引映射到一列二进制向量,最多只有一个单值。

这种编码允许需要连续特征的算法(例如逻辑回归)使用分类特征

让我们考虑以下DataFrame:

val df = Seq((0, "a"),(1, "b"),(2, "c"),(3, "a"),(4, "a"),(5, "c"))
            .toDF("id", "category")

第一步是使用 StringIndexer 创建索引的 DataFrame:

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|
// +---+--------+-------------+

然后,您可以使用 OneHotEncodercategoryIndex 进行编码:

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])|
// +---+-------------+

关于apache-spark - 如何使用spark-ml处理分类特征?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32277576/

相关文章:

r - Sparklyr - 如何更改 Parquet 数据类型

r - 为数据框中的因子添加额外的级别

Python pandas 字符串处理来自 SQL 数据库的分类数据

r - 如何在 Spark 中训练带有稀疏矩阵的随机森林?

scala - 如何在朴素贝叶斯模型的 BinaryClassificationMetrics 评估中给出预测列和标签列

scala - Spark中 double 值的精度

python - Spark MLlib - trainImplicit 警告

apache-spark - 写入 CSV 时 Spark 对向量值做了什么?

python - 在 Python 中对不同类别的 n 长度数组中的分类数据进行编码

apache-spark - Hive 相当于创建表时的 Spark Vector