2016-07-28 66 views
0

我從一本書中讀了一段關於二元決策樹的代碼。它在原始數據中只有一個分類特徵,即字段(3),並被轉換爲一個k(單熱編碼)。如何處理決策樹中的多個分類特徵?

def PrepareData(sc: SparkContext): (RDD[LabeledPoint], RDD[LabeledPoint], RDD[LabeledPoint], Map[String, Int]) = { 

    val rawDataWithHeader = sc.textFile("data/train.tsv") 
    val rawData = rawDataWithHeader.mapPartitionsWithIndex { (idx, iter) => if (idx == 0) iter.drop(1) else iter } 
    val lines = rawData.map(_.split("\t")) 


    val categoriesMap = lines.map(fields => fields(3)).distinct.collect.zipWithIndex.toMap 
    val labelpointRDD = lines.map { fields => 
    val trFields = fields.map(_.replaceAll("\"", "")) 
    val categoryFeaturesArray = Array.ofDim[Double](categoriesMap.size) 
    val categoryIdx = categoriesMap(fields(3)) 
    categoryFeaturesArray(categoryIdx) = 1 
    val numericalFeatures = trFields.slice(4, fields.size - 1).map(d => if (d == "?") 0.0 else d.toDouble) 
    val label = trFields(fields.size - 1).toInt 
    LabeledPoint(label, Vectors.dense(categoryFeaturesArray ++ numericalFeatures)) 
    } 

    val Array(trainData, validationData, testData) = labelpointRDD.randomSplit(Array(8, 1, 1)) 
    return (trainData, validationData, testData, categoriesMap) 
} 

不知如何,如果有原始數據幾個類別特徵修改代碼,讓我們說現場(3),現場(5),現場(7)全部類別特徵。

我修改的第一行:

def PrepareData(sc: SparkContext): (RDD[LabeledPoint], RDD[LabeledPoint], RDD[LabeledPoint], Map[String, Int], Map[String, Int], Map[String, Int], Map[String, Int]) =...... 

然後,我轉換另一兩個字段成1-的k值編碼,因爲它是像完成:

val categoriesMap5 = lines.map(fields => fields(5)).distinct.collect.zipWithIndex.toMap 
val categoriesMap7 = lines.map(fields => fields(7)).distinct.collect.zipWithIndex.toMap 
val categoryFeaturesArray5 = Array.ofDim[Double](categoriesMap5.size) 
val categoryFeaturesArray7 = Array.ofDim[Double](categoriesMap7.size) 
val categoryIdx3 = categoriesMap5(fields(5)) 
val categoryIdx5 = categoriesMap7(fields(7)) 
categoryFeaturesArray5(categoryIdx5) = 1 
categoryFeaturesArray7(categoryIdx7) = 1 

最後,我修改LabeledPoint和返回像:

LabeledPoint(label, Vectors.dense(categoryFeaturesArray ++ categoryFeaturesArray5 ++ categoryFeaturesArray7 ++ numericalFeatures)) 
return (trainData, validationData, testData, categoriesMap, categoriesMap5, categoriesMap7) 

它是正確的嗎?

============================================== ====

我遇到的第二個問題是:從書下面的代碼,在trainModel,它採用

DecisionTree.trainRegressor(trainingData, categoricalFeaturesInfo, impurity, maxDepth, maxBins) 

下面是代碼:

def trainModel(trainData: RDD[LabeledPoint], impurity: String, maxDepth: Int, maxBins: Int): (DecisionTreeModel, Double) = { 
    val startTime = new DateTime() 
    val model = DecisionTree.trainClassifier(trainData, 2, Map[Int, Int](), impurity, maxDepth, maxBins) 
    val endTime = new DateTime() 
    val duration = new Duration(startTime, endTime) 
    (model, duration.getMillis()) 
} 

的問題是:如果它具有前面提到的三個分類特徵,我該如何將categoricalFeaturesInfo傳遞到此方法中?

我只想按照書中的步驟通過使用決策樹自行建立預測系統。更具體地講,我選擇的是數據集有幾個分類的功能,如: 性別:男,女

教育:HS-畢業,學士,碩士,博士,......

國家:美國,加拿大,英國,澳大利亞,......

但我不知道如何將它們合併成一個單一的categoryFeatures ++ numericalFeatures投入Vector.dense(),和一個單一的categoricalFeaturesInfo投入DecisionTree.trainRegressor()

回答

2

我不清楚你到底在做什麼,但看起來像從一開始就是錯誤的。

忽略了一個事實,即通過從零開始實現單熱編碼重新發明輪子,整個編碼點就是將分類變量轉換爲數字變量。這對於線性模型是必需的,但可以說使用決策樹時沒有意義。

牢記這一點,你有兩個選擇:

  • 指數分類字段沒有編碼,並通過索引功能categoricalFeaturesInfo
  • 一次性編碼分類特徵並將其視爲數值變量。

我相信前一種方法是正確的做法。後者應該在實踐中起作用,但它只是人爲地增加了維度而沒有提供任何好處。它也可能與Spark實現使用的一些啓發式相沖突。

您應該考慮使用ML管道來提供所有必需的索引編碼和合並工具。

+0

哼哼......我只是想按照書中的步驟,通過使用決策樹自己建立預測系統。 更具體地說,我選擇的數據集有幾個明確的特徵,如: 性別:男性,女性; 學歷:HS-grad,Bachelors,Master,PH.D,......; 國家:美國,加拿大,英國,澳大利亞......; ...等等。 但我不知道如何將它們合併成一個單獨的「categoryFeatures ++ numericalFeatures」放入「Vector.dense()」,並將一個單獨的「categoricalFeaturesInfo」放入「DecisionTree.trainRegressor()」 –

+0

If您使用ML Pipelines,您將獲得所需的所有工具,包括編碼器,分度器和組裝器。 – zero323

+0

@ C.Y.Wu我贊同zero323,但是如果我問這本書的標題是什麼?我想看看它。 – eliasah