簡體   English   中英

Spark多類分類示例

[英]Spark Multiclass Classification Example

你們知道我在哪里可以找到Spark中的多類分類示例。 我花了很多時間在書籍和網絡上搜索,到目前為止,我只知道從文檔的最新版本開始是可能的。

ML

在Spark 2.0+中推薦

我們將使用與下面的MLlib中相同的數據。 有兩個基本選項。 如果Estimator支持開箱即用的多類分類(例如隨機森林),則可以直接使用它:

val trainRawDf = trainRaw.toDF

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

import org.apache.spark.ml.classification.RandomForestClassifier

val transformers = Array(
  new StringIndexer().setInputCol("group").setOutputCol("label"),
  new Tokenizer().setInputCol("text").setOutputCol("tokens"),
  new CountVectorizer().setInputCol("tokens").setOutputCol("features")
)


val rf = new RandomForestClassifier() 
  .setLabelCol("label")
  .setFeaturesCol("features")

val model = new Pipeline().setStages(transformers :+ rf).fit(trainRawDf)

model.transform(trainRawDf)

如果模型僅支持二進制分類(邏輯回歸)並擴展了oasml.classification.Classifier ,則可以使用one-vs-rest策略:

import org.apache.spark.ml.classification.OneVsRest
import org.apache.spark.ml.classification.LogisticRegression

val lr = new LogisticRegression() 
  .setLabelCol("label")
  .setFeaturesCol("features")

val ovr = new OneVsRest().setClassifier(lr)

val ovrModel = new Pipeline().setStages(transformers :+ ovr).fit(trainRawDf)

多層板

根據目前的官方文檔 (MLlib 1.6.0),以下方法支持多類分類:

  • 邏輯回歸
  • 決策樹,
  • 隨機森林
  • 朴素的貝葉斯

至少某些示例使用多類分類:

忽略方法特定參數的通用框架與MLlib中的所有其他方法幾乎相同。 您必須對輸入進行預處理,以創建帶有表示labelfeatures列的任一數據框:

root
 |-- label: double (nullable = true)
 |-- features: vector (nullable = true)

RDD[LabeledPoint]

Spark提供了廣泛的有用工具,旨在促進此過程,包括功能提取器功能轉換器管道

您會在下面找到一個使用“隨機森林”的簡單示例。

首先,讓我們導入所需的軟件包並創建虛擬數據:

import sqlContext.implicits._
import org.apache.spark.ml.feature.{HashingTF, Tokenizer} 
import org.apache.spark.mllib.regression.LabeledPoint
import org.apache.spark.ml.feature.StringIndexer
import org.apache.spark.mllib.tree.RandomForest
import org.apache.spark.mllib.tree.model.RandomForestModel
import org.apache.spark.mllib.linalg.{Vectors, Vector}
import org.apache.spark.mllib.evaluation.MulticlassMetrics
import org.apache.spark.sql.Row
import org.apache.spark.rdd.RDD

case class LabeledRecord(group: String, text: String)

val trainRaw = sc.parallelize(
    LabeledRecord("foo", "foo v a y b  foo") ::
    LabeledRecord("bar", "x bar y bar v") ::
    LabeledRecord("bar", "x a y bar z") ::
    LabeledRecord("foobar", "foo v b bar z") ::
    LabeledRecord("foo", "foo x") ::
    LabeledRecord("foobar", "z y x foo a b bar v") ::
    Nil
)

現在讓我們定義所需的變壓器和過程Dataset

// Tokenizer to process text fields
val tokenizer = new Tokenizer()
    .setInputCol("text")
    .setOutputCol("words")

// HashingTF to convert tokens to the feature vector
val hashingTF = new HashingTF()
    .setInputCol("words")
    .setOutputCol("features")
    .setNumFeatures(10)

// Indexer to convert String labels to Double
val indexer = new StringIndexer()
    .setInputCol("group")
    .setOutputCol("label")
    .fit(trainRaw.toDF)


def transfom(rdd: RDD[LabeledRecord]) = {
    val tokenized = tokenizer.transform(rdd.toDF)
    val hashed = hashingTF.transform(tokenized)
    val indexed = indexer.transform(hashed)
    indexed
        .select($"label", $"features")
        .map{case Row(label: Double, features: Vector) =>
            LabeledPoint(label, features)}
}

val train: RDD[LabeledPoint] = transfom(trainRaw)

請注意, indexer已“適合”火車數據。 它僅表示將用作標簽的分類值轉換為doubles 要對新數據使用分類器,必須首先使用此indexer對其進行轉換。

接下來我們可以訓練RF模型:

val numClasses = 3
val categoricalFeaturesInfo = Map[Int, Int]()
val numTrees = 10
val featureSubsetStrategy = "auto"
val impurity = "gini"
val maxDepth = 4
val maxBins = 16

val model = RandomForest.trainClassifier(
    train, numClasses, categoricalFeaturesInfo, 
    numTrees, featureSubsetStrategy, impurity,
    maxDepth, maxBins
)

最后測試一下:

val testRaw = sc.parallelize(
    LabeledRecord("foo", "foo  foo z z z") ::
    LabeledRecord("bar", "z bar y y v") ::
    LabeledRecord("bar", "a a  bar a z") ::
    LabeledRecord("foobar", "foo v b bar z") ::
    LabeledRecord("foobar", "a foo a bar") ::
    Nil
)

val test: RDD[LabeledPoint] = transfom(testRaw)

val predsAndLabs = test.map(lp => (model.predict(lp.features), lp.label))
val metrics = new MulticlassMetrics(predsAndLabs)

metrics.precision
metrics.recall

您使用的是Spark 1.6而不是Spark 2.1? 我認為問題在於,在spark 2.1中,transform方法返回一個數據集,該數據集可以隱式轉換為類型化的RDD,在此之前,它返回數據幀或行。

嘗試作為診斷,將轉換函數的返回類型指定為RDD [LabeledPoint],看看是否遇到相同的錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM