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接口整理一個說明文檔吧。哎,每天太多事,忙不過來。
轉載請註明出處: