在 Spark 中将列标记为分类
Tagging columns as Categorical in Spark
我目前正在使用 StringIndexer 将大量列转换为唯一整数,以便在 RandomForestModel 中进行分类。我也在为 ML 过程使用管道。
一些查询是
RandomForestModel 如何知道哪些列是分类的。 StringIndexer 将非数字转换为数字,但它是否添加了某种元数据以表明它是一个分类列?在 mllib.tree.RF 中有参数调用 categoricalInfo,它指示分类列。 ml.tree.RF 如何知道哪些是因为它不存在。
此外,StringIndexer 根据出现频率将类别映射到整数。现在,当新数据进来时,我如何确保该数据与训练数据的编码一致?我可能会这样做,而无需再次对包括新数据在内的整个数据进行 StringIndexing?
我对如何实现这个很困惑。
Is it possible o do that without StringIndexing the whole data again including the new data?
是的,这是可能的。您只需要使用安装在训练数据上的索引器。如果您使用 ML 管道,它将为您处理,只需直接使用 StringIndexerModel
:
import org.apache.spark.ml.feature.StringIndexer
val train = sc.parallelize(Seq((1, "a"), (2, "a"), (3, "b"))).toDF("x", "y")
val test = sc.parallelize(Seq((1, "a"), (2, "b"), (3, "b"))).toDF("x", "y")
val indexer = new StringIndexer()
.setInputCol("y")
.setOutputCol("y_index")
.fit(train)
indexer.transform(train).show
// +---+---+-------+
// | x| y|y_index|
// +---+---+-------+
// | 1| a| 0.0|
// | 2| a| 0.0|
// | 3| b| 1.0|
// +---+---+-------+
indexer.transform(test).show
// +---+---+-------+
// | x| y|y_index|
// +---+---+-------+
// | 1| a| 0.0|
// | 2| b| 1.0|
// | 3| b| 1.0|
// +---+---+-------+
一个可能的警告是它不能优雅地处理看不见的标签,因此您必须在转换之前删除这些标签。
How does the RandomForestModel know which columns are categorical.
不同的 ML 转换器将特殊的特殊元数据添加到转换后的列,这些元数据指示列的类型、类 的数量等
import org.apache.spark.ml.attribute._
import org.apache.spark.ml.feature.VectorAssembler
val assembler = new VectorAssembler()
.setInputCols(Array("x", "y_index"))
.setOutputCol("features")
val transformed = assembler.transform(indexer.transform(train))
val meta = AttributeGroup.fromStructField(transformed.schema("features"))
meta.attributes.get
// Array[org.apache.spark.ml.attribute.Attribute] = Array(
// {"type":"numeric","idx":0,"name":"x"},
// {"vals":["a","b"],"type":"nominal","idx":1,"name":"y_index"})
或
transformed.select($"features").schema.fields.last.metadata
// "ml_attr":{"attrs":{"numeric":[{"idx":0,"name":"x"}],
// "nominal":[{"vals":["a","b"],"idx":1,"name":"y_index"}]},"num_attrs":2}}
我目前正在使用 StringIndexer 将大量列转换为唯一整数,以便在 RandomForestModel 中进行分类。我也在为 ML 过程使用管道。
一些查询是
RandomForestModel 如何知道哪些列是分类的。 StringIndexer 将非数字转换为数字,但它是否添加了某种元数据以表明它是一个分类列?在 mllib.tree.RF 中有参数调用 categoricalInfo,它指示分类列。 ml.tree.RF 如何知道哪些是因为它不存在。
此外,StringIndexer 根据出现频率将类别映射到整数。现在,当新数据进来时,我如何确保该数据与训练数据的编码一致?我可能会这样做,而无需再次对包括新数据在内的整个数据进行 StringIndexing?
我对如何实现这个很困惑。
Is it possible o do that without StringIndexing the whole data again including the new data?
是的,这是可能的。您只需要使用安装在训练数据上的索引器。如果您使用 ML 管道,它将为您处理,只需直接使用 StringIndexerModel
:
import org.apache.spark.ml.feature.StringIndexer
val train = sc.parallelize(Seq((1, "a"), (2, "a"), (3, "b"))).toDF("x", "y")
val test = sc.parallelize(Seq((1, "a"), (2, "b"), (3, "b"))).toDF("x", "y")
val indexer = new StringIndexer()
.setInputCol("y")
.setOutputCol("y_index")
.fit(train)
indexer.transform(train).show
// +---+---+-------+
// | x| y|y_index|
// +---+---+-------+
// | 1| a| 0.0|
// | 2| a| 0.0|
// | 3| b| 1.0|
// +---+---+-------+
indexer.transform(test).show
// +---+---+-------+
// | x| y|y_index|
// +---+---+-------+
// | 1| a| 0.0|
// | 2| b| 1.0|
// | 3| b| 1.0|
// +---+---+-------+
一个可能的警告是它不能优雅地处理看不见的标签,因此您必须在转换之前删除这些标签。
How does the RandomForestModel know which columns are categorical.
不同的 ML 转换器将特殊的特殊元数据添加到转换后的列,这些元数据指示列的类型、类 的数量等
import org.apache.spark.ml.attribute._
import org.apache.spark.ml.feature.VectorAssembler
val assembler = new VectorAssembler()
.setInputCols(Array("x", "y_index"))
.setOutputCol("features")
val transformed = assembler.transform(indexer.transform(train))
val meta = AttributeGroup.fromStructField(transformed.schema("features"))
meta.attributes.get
// Array[org.apache.spark.ml.attribute.Attribute] = Array(
// {"type":"numeric","idx":0,"name":"x"},
// {"vals":["a","b"],"type":"nominal","idx":1,"name":"y_index"})
或
transformed.select($"features").schema.fields.last.metadata
// "ml_attr":{"attrs":{"numeric":[{"idx":0,"name":"x"}],
// "nominal":[{"vals":["a","b"],"idx":1,"name":"y_index"}]},"num_attrs":2}}