Spark ML 基礎:DataFrame、Dataset、feature

Spark ML 是基於DataFrame/ Dataset進行機器學習API的開發,隨着Spark 2.0的發展,Dataset將成爲主流,會逐步取代RDD、DataFrame,當然這個取代只是在Dataset實現已有RDD、DataFrame的API,大家以後就可以用Dataset的API來實現計算邏輯,所以大家不用擔心之前學會的RDD、DataFrame沒有用處。

博主一般喜歡從源碼的角度來看問題和分析問題,也許不太適合你們的口味,所以請大家見諒。

1.1 DataFrame/Dataset

首先看下DataFrame/Dataset的API。


DataFrame/Dataset都是在org.apache.spark.sql,因爲都是結構化的數據,所以都是從sql這裏來的,具體怎麼創建DataFrame和Dataset就不細說了,比較簡單的事情。

對於大家平常工作中,重點關注:DataFrame、Dataset、functions這三個的API接口,基本上都能滿足大家的工作需要。DataFrame/Dataset的API類似於RDD的,大家可以去看下。對於functions的API大家要重點關注,這裏麪包括:聚合操作函數、集合操作函數、時間日期函數、數學函數、排序函數、字符串處理函數等等,可支持的函數太多,大家一定要好好細看。

綜合上所述,還是寫幾個實例代碼,要不大家就得吐槽我了。

import org.apache.spark.SparkConf

import org.apache.spark.SparkContext

import org.apache.spark.sql.SQLContext

import org.apache.spark.sql.functions._

 

case classEmployee(id: Int, name: String)

 

// 創建DataFrame

   vallistOfEmployees= List(Employee(1," huangmeiling  "), Employee(2," sunbow  "), Employee(3," json  "))

   valempFrame= sqlContext.createDataFrame(listOfEmployees)

   empFrame.show()

 

// 聚合操作

   valaa1= empFrame.groupBy().agg(max(empFrame("name")), avg(empFrame("id")))

 

// 字符串操作

   valdf2= empFrame.select(empFrame("id"), trim(empFrame("name")))

   val df3= empFrame.select(empFrame("id"), split(empFrame("name"), "o"))

 

// 其它操作

   valbb = empFrame.select(cos(empFrame("id")), empFrame("id"), empFrame("id") + 10, empFrame("name").substr(0, 3))

   val cc = empFrame.select(max(empFrame("id")), max(empFrame("name")))

 

1.2 ML feature解析

DataFrame/Dataset只是鋪墊,因爲我覺得和RDD差不多,只是底層不一樣,對開發者來說大同小異,所以重點進入feature的講解。這裏拿第一個特徵處理的API:Binarizer進行講解。

源碼解析如下:

/**
 * :: Experimental ::
 * 二元化,根據指定的閾值對連續特徵列生成0\1二元值.
 */
@Experimental
final class Binarizer(override val uid: String)
  extends Transformer with HasInputCol with HasOutputCol with DefaultParamsWritable {

  def this() = this(Identifiable.randomUID("binarizer"))

  /**
   * 參數閾值.
   * 如果特性大於該閾值,二元值爲1.
   * 如果特性小於等於該閾值,二元值爲0.
   * 默認值: 0.0
   * @group param
   */
  val threshold: DoubleParam =
    new DoubleParam(this, "threshold", "threshold used to binarize continuous features")

  /** 取參數閾值 */
  def getThreshold: Double = $(threshold)

  /** 設置參數閾值 */
  def setThreshold(value: Double): this.type = set(threshold, value)

  setDefault(threshold -> 0.0)

  /** 設置輸入列 */
  def setInputCol(value: String): this.type = set(inputCol, value)

  /** 設置輸出列 */
  def setOutputCol(value: String): this.type = set(outputCol, value)

  // 計算部分,對輸入列的每個元素進行二元值計算
  override def transform(dataset: DataFrame): DataFrame = {
    // DataFrame的結構變化,增加輸出列
    transformSchema(dataset.schema, logging = true)
    // 取閾值
    val td = $(threshold)
    // 計算核心部分:二元值的計算過程,這裏採用的用戶自定義sql函數方法的接口,該函數可以直接對DataFrame的列進行操作。
    val binarizer = udf { in: Double => if (in > td) 1.0 else 0.0 }
    // 輸出的結果列
    val outputColName = $(outputCol)
    // DataFrame的元數據更新,增加了結果輸出列
    val metadata = BinaryAttribute.defaultAttr.withName(outputColName).toMetadata()
    // 根據指定的輸入列,進行函數操作,其中函數操作是自定義的函數
    dataset.select(col("*"),
      binarizer(col($(inputCol))).as(outputColName, metadata))
  }

  // DataFrame的結構變化,增加輸出列
  override def transformSchema(schema: StructType): StructType = {
    SchemaUtils.checkColumnType(schema, $(inputCol), DoubleType)

    val inputFields = schema.fields
    val outputColName = $(outputCol)

    require(inputFields.forall(_.name != outputColName),
      s"Output column $outputColName already exists.")

    val attr = BinaryAttribute.defaultAttr.withName(outputColName)
    val outputFields = inputFields :+ attr.toStructField()
    StructType(outputFields)
  }

  override def copy(extra: ParamMap): Binarizer = defaultCopy(extra)
}

@Since("1.6.0")
object Binarizer extends DefaultParamsReadable[Binarizer] {

  @Since("1.6.0")
  override def load(path: String): Binarizer = super.load(path)
}

其中重點是transform,該方法就是主要實現特徵處理的邏輯計算,該方法中最主要部分就是用戶自定義函數:

   valbinarizer = udf { in: Double => if (in > td) 1.0else0.0}

該自定義函數是我們特徵的邏輯處理過程的實現。

其中udf就是UserDefinedFunction,說個例子:

我自定義了一個函數:

 val predict = udf((score: Double) => if(score > 0.5) true else false)

該函數可以直接應用在DataFrame對列進行處理:

df.select(predict(df("score")) )

 

所以綜上所述,如果我們需要自己寫一個ML 特徵處理API接口或者需要修改源碼什麼的,重點部分在transform方法上的實現,以及需要自已定義一個sql用戶自定義函數udf。

 

ML 的feature特徵處理API有好多:


大家自己一個個去看吧。

今天就講解個Demo,希望對大家有所幫助。

等有時間,我把DataFrame、Dataset、feature所有API接口整理一個說明文檔吧。哎,每天太多事,忙不過來。


轉載請註明出處:

http://blog.csdn.net/sunbow0

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章