如何使用 Scala 运行具有分类特征集的 Spark 决策树?

Posted

技术标签:

【中文标题】如何使用 Scala 运行具有分类特征集的 Spark 决策树?【英文标题】:How do I run the Spark decision tree with a categorical feature set using Scala? 【发布时间】:2014-09-22 04:21:47 【问题描述】:

我有一个具有相应 categoricalFeaturesInfo 的功能集:Map[Int,Int]。但是,对于我的生活,我无法弄清楚我应该如何让 DecisionTree 类工作。它不会接受任何东西,而是接受 LabeledPoint 作为数据。但是,LabeledPoint 需要 (double, vector) 而向量需要双精度。

val LP = featureSet.map(x => LabeledPoint(classMap(x(0)),Vectors.dense(x.tail)))

// Run training algorithm to build the model
val maxDepth: Int = 3
val isMulticlassWithCategoricalFeatures: Boolean = true
val numClassesForClassification: Int = countPossibilities(labelCol) 
val model = DecisionTree.train(LP, Classification, Gini, isMulticlassWithCategoricalFeatures, maxDepth, numClassesForClassification,categoricalFeaturesInfo)

我得到的错误:

scala> val LP = featureSet.map(x => LabeledPoint(classMap(x(0)),Vectors.dense(x.tail)))
<console>:32: error: overloaded method value dense with alternatives:
  (values: Array[Double])org.apache.spark.mllib.linalg.Vector <and>
  (firstValue: Double,otherValues: Double*)org.apache.spark.mllib.linalg.Vector
 cannot be applied to (Array[String])
       val LP = featureSet.map(x => LabeledPoint(classMap(x(0)),Vectors.dense(x.tail)))

到目前为止我的资源: tree config,decision tree,labeledpoint

【问题讨论】:

【参考方案1】:

您可以先将类别转换为数字,然后像所有特征都是数字一样加载数据。

当您在 Spark 中构建决策树模型时,您只需要通过指定从特征索引到其特征索引的映射 Map[Int, Int]() 来告诉 spark 哪些特征是分类特征以及特征的数量(该特征的不同类别的数量) arity。

例如,如果您有以下数据:

1,a,add
2,b,more
1,c,thinking
3,a,to
1,c,me

您可以先将数据转换为数字格式:

1,0,0
2,1,1
1,2,2
3,0,3
1,2,4

以这种格式,您可以将数据加载到 Spark。那么如果你想告诉 Spark 第二列和第三列是分类的,你应该创建一个映射:

categoricalFeaturesInfo = Map[Int, Int]((1,3),(2,5))

地图告诉我们,索引为 1 的特征具有 3,而索引为 2 的特征具有 5。当我们构建决策树模型时,它们将被视为分类模型,将该地图作为训练函数的参数传递:

val model = DecisionTree.trainClassifier(trainingData, numClasses, categoricalFeaturesInfo, impurity, maxDepth, maxBins)

【讨论】:

一个尴尬且看似脆弱的事情是,您必须将 LabeledPoint 中的类别编号存储为 Double 类型。【参考方案2】:

LabeledPoint 不支持字符串,将其放入 LabeledPoint 的一种方法是将数据拆分为多列,考虑到您的字符串是分类的。

例如,如果您有以下数据集:

id,String,Intvalue
1,"a",123
2,"b",456
3,"c",789
4,"a",887

然后您可以拆分字符串数据,将字符串的每个值放入一个新列

a -> 1,0,0
b -> 0,1,0
c -> 0,0,1

由于您有 3 个不同的字符串值,您会将字符串列转换为 3 个新列,每个值将由这些新列中的一个值表示。

现在您的数据集将是

id,String,Intvalue
1,1,0,0,123
2,0,1,0,456
3,0,0,1,789
4,1,0,0,887

现在您可以将其转换为 Double 值并将其用于您的 LabeledPoint。

将字符串转换为 LabeledPoint 的另一种方法是为每列创建一个不同的值列表,并将字符串的值转换为该列表中该字符串的索引。不建议这样做,因为如果是这样,在这个假设的数据集中它将是

a = 0
b = 1
c = 2

但在这种情况下,算法会认为 a 更接近 b 而不是 c,这是无法确定的。

【讨论】:

如何在 spark 中创建 map 函数来为分类内容分配数值?我从一个有 5 个分类列的 excel 文件生成了一个 RDD。我想为每列中可用的每个唯一类别分配数字。我该怎么做?【参考方案3】:

您需要确认数组 x 的类型。 从错误日志中,它说数组 x 中的项目是 spark 不支持的字符串。 当前 spark Vectors 只能用 Double 填充。

【讨论】:

以上是关于如何使用 Scala 运行具有分类特征集的 Spark 决策树?的主要内容,如果未能解决你的问题,请参考以下文章

用于分类的多个不同大小的特征集

nltk:使用自定义特征集的文本分类

基于单个特征集的分类精度

如何重新设计这个 SQL 数据结构?

如何缩放 SVM 分类的输入特征?

用于在 Python 中匹配具有相似 ID 字符串的两个集合的分类器