Spark學習筆記

本文整理自《Spark快速大數據分析》,其中SparkSQL還沒學習,日後補上

第二章 Spark入門
RDD(彈性分佈式數據集)是Spark對分佈式數據和計算的基本抽象。

每個Spark應用都有一個驅動器程序來發起集羣上的並行操作。驅動器程序包含應用的main函數,並且定義了集羣上的分佈式數據集,還對數據集應用了相關操作。驅動器程序一般要管理多個執行器。如果是本地模式下,則所有的工作都會在單個節點上進行。

驅動器程序通過一個SparkContext對象來訪問Spark,是一個叫做sc的變量。調用sc.textFile()來創建一個代表文件中各行文本的RDD。

Spark也可以在java、Scala、python的獨立程序中被連接使用,與shell中的區別在於需要自行初始化SparkContext。可以先創建一個SparkConf對象來配置應用,基於SparkConf創建一個SparkContext對象。

構建工程可以使用maven包管理工具,也可以使用其他能夠訪問maven倉庫的工具,比如scala的sbt或者gradle工具。

new SparkConf().setMaster("local").setAppName("as")
創建SparkContext最基本的方法,只需傳遞兩個參數:
1.集羣URL:告訴spark如何連接到集羣上,local表示運行在單機單線程上無需連接到集羣。
2.應用名:as,當連接到一個集羣時,這個值可以幫助在管理器中找到你的應用。


第三章:RDD編程
RDD創建方式兩種:讀取外部數據集和在驅動器程序中對一個集合進行並行化,後者可以用sc.parallelize()方法

RDD創建之後支持兩種類型的操作:轉化和行動。轉化操作返回的是RDD類型,行動操作是其他類型。

take(N)獲取少量元素,collect()獲取整個數據,但不適用於大規模,top()獲取前幾個元素。

轉化操作:
map()操作接受一個函數,用於RDD的每一個元素,將函數的返回結果作爲結果RDD中對應元素的值;map的返回值類型不需要和輸入類型一樣。
filter()操作接受一個函數,並將RDD中滿足該函數的元素放入新的RDD中返回。
flatMap()操作和map類似,應用到每一個元素上,但是返回的是一個返回值序列的迭代器,最終得到的是一個包含各個迭代器可以訪問的所有的元素的RDD。

distinct()轉化成只含有不同元素的RDD,但是開銷很大;
union()操作返回包含兩個RDD中所有元素的RDD,不會去掉重複的;
intersection()操作返回兩個RDD中都有的元素,會去掉重複的元素;
subtract()函數返回只存在於第一個RDD不存在於第二個RDD中的元素,去掉重複的。
cartesian()計算兩個RDD的笛卡爾積,開銷巨大。

管道(pipe)操作:

spark在RDD上提供了 pipe() 方法。通過pipe(),你可以使用任意語言將RDD中的各元素從標準輸入流中以字符串形式讀出,並將這些元素執行任何你需要的操作,然後把結果以字符串形式寫入標準輸出,這個過程就是RDD的轉化操作過程。

使用pipe()的方法很簡單,假如我們有一個用其他語言寫成的從標準輸入接收數據並將處理結果寫入標準輸出的可執行腳本,我們只需要將該腳本分發到各個節點相同路徑下,並將其路徑作爲pipe()的參數傳入即可。



行動操作:
無輸出:
foreach()    操作對RDD的每個元素進行操作,而不需要把RDD發回本地(驅動器程序)。
HDFS:
saveAsTextFile()    函數將數據輸出,存儲到HDFS的指定目錄。
saveAsObjectFile()    將分區中的每10個元素組成一個Array,然後將這個Array序列化,寫入HDFS爲SequenceFile的格式。
Scala集合和數據類型:
collect()    相當於toArray,toArray已經過時不推薦使用,collect將分佈式的RDD返回爲一個單機的scala Array數組, 在這個數組上運用scala的函數式操作。
collectAsMap()    對(K,V)型的RDD數據返回一個單機HashMap。對於重複K的RDD元素,後面的元素覆蓋前面的元素。
Lookup()    對(Key,Value)型的RDD操作,返回指定Key對應的元素形成的Seq。
count()    返回整個RDD的元素個數。 
top()    返回最大的k個元素。
take()    返回最小的k個元素。
takeOrdered()    返回最小的k個元素, 並且在返回的數組中保持元素的順序。
reduce()    操作接受一個函數作爲參數,操作兩個相同元素類型的RDD數據並返回一個同樣類型的新元素。
fold()    和reduce類似,接收函數之外,還提供一個初始值來作爲每個分區第一次調用時的結果,應當是單位元素,比如+則是0,*則是1,拼接操作則是空列表。
aggregate()    不限制返回類型必須與RDD相同,但同樣需要提供返回類型的初始值。
aggregate先對每個分區的所有元素進行aggregate操作,再對分區的結果進行fold操作。 
aggreagate與fold和reduce的不同之處在於,aggregate相當於採用歸併的方式進行數據聚集,這種聚集是並行化的。 而在fold和reduce函數的運算過程中,每個分區中需要進行串行處理,每個分區串行計算完結果,結果再按之前的方式進行聚集,並返回最終聚集結果。
countByValue()返回各個元素在RDD中出現的次數,映射表形式。


第四章:鍵值對操作
PairRDD操作:
reduceByKey()合併具有相同鍵的值。
mapValues()對pair中每個值應用一個函數而不改變鍵,flatMapValues類似。
keys()返回包含鍵的RDD;values()返回包含值的RDD。Scala中不用括號。
sortByKey()返回根據鍵排序的RDD。
join()操作內連接,只有在兩個pair RDD鍾都存在的鍵才能輸出。
leftOuterJoin和rightOuterJoin()都會根據鍵連接兩個RDD,但是允許結果中存在其中一個RDD所缺失的鍵。

並行度調優:Spark提供repartition()函數創建分區,但是代價相對較大,更優化版的是coalesce()函數,可以用rdd.paritions.size查看分區數,默認情況下spark嘗試根據集羣的大小推斷出一個有意義的分區默認值。 
Spark可以確保同一組的鍵出現在同一個節點上。


第五章:數據讀取與保存
Spark可以訪問多種不同的文件格式,包括文本文件、JSON、SequenceFile以及protocol buffer。
如果多個輸入文件以一個包含數據所有部分的目錄的形式出現,可以仍使用textFile函數,傳遞目錄作爲參數,這樣會把各部分都讀取到RDD中。或者可以在輸入路徑中使用通配字符,例如part-*.txt,大規模數據集通常存放在多個文件中,因此這一特性很有用,尤其是在同一目錄中存在一些別的文件(比如成功標記文件)的時候。

saveAsTextFile()方法接受一個路徑,並將RDD中的內容都輸入到路徑對應的文件中。Spark將傳入的路徑作爲目錄看待,會在那個目錄下輸出多個文件。

對於大多數Hadoop輸出格式來說,我們可以指定一種壓縮編解碼器來壓縮數據,Spark原聲的輸入方式(textFile和sequenceFile)可以自動處理一些類型的壓縮。這些壓縮選項只適用於支持壓縮的Hadoop格式,也就是寫出到文件系統的格式。寫入數據庫的Hadoop格式一般沒有實現壓縮支持。
對於像Spark這樣的分佈式系統,通常會嘗試從多個不同機器上一起讀入數據,但有些壓縮數據使這變得不太可能,而必須要從單個節點來讀入所有數據,可以很容易的從多個節點並行讀取的格式被稱爲“可分割”的格式。
gzip    不可分割、壓縮速度快、壓縮效率高 org.apache.hadoop.io.compress.GzipCodec
bzip2  可分割、壓縮速度慢、壓縮效率非常高、org.apache.hadoop.io.compress.Bzip2Codec
zlib     不可分割、壓縮速度慢、壓縮效率中等、org.apache.hadoop.io.compress.DefaultCodec 是Hadoop的默認壓縮編解碼器

Spark支持從本地文件系統讀取文件,要求文件在集羣中所有節點的相同路徑下都能找到,只需指定輸入一個file://路徑 
例如:”file:///home/holden/happy.gz“
推薦的方法是將文件先放到像HDFS這樣的共享文件系統上。

Hadoop分佈式文件系統(HDFS)是一種廣泛使用的文件系統。Spark和HDFS可以部署在同一批機器上,這樣Spark可以利用數據分佈來儘量避免一些網絡開銷。使用HDFS只需要將輸入輸出路徑指定爲:hdfs://master:port/path


第六章:Spark編程進階
累加器的用法:
累加器是僅僅被相關操作累加的變量,因此可以在並行中被有效地支持。它可以被用來實現計數器和總和。
1.SparkContext.accumulator(initialValue)方法,創建累加器,返回值爲org.apache.spark.Accumulator[T]對象
2.Spark閉包裏的執行器代碼可以使用累加器的+=方法
3.驅動器程序可以調用累加器的value屬性來訪問累加器的值。
Spark原生地只支持數字類型的累加器Int,但是開發人員也可以通過繼承AccumulatorParam類來創建它們自己的累加器類型。

AccumulatorParam接口有兩個方法:

zero方法爲你的類型提供一個0值。

addInPlace方法將兩個值相加。

累加器是一個只寫變量,工作節點上的任務不能訪問累加器的值,只有在驅動器程序中可以訪問。
累加器並沒有改變Spark的惰性求值模型。如果它們被RDD上的操作更新,它們的值只有當RDD因爲動作操作被計算時才被更新。因此,當執行一個惰性的轉換操作,比如map時,不能保證對累加器值的更新被實際執行了。

廣播變量用法:
廣播變量允許程序員將一個只讀的變量緩存在每臺機器上,而不用在任務之間傳遞變量。當我們需要在多個階段的任務之間使用相同的數據,或者以反序列化形式緩存數據是十分重要的時候,顯式地創建廣播變量纔有用。在創建了廣播變量之後,在集羣上的所有函數中應該使用它來替代使用v,這樣v就不會不止一次地在節點之間傳輸了。另外爲了確保所有的節點獲得相同的變量,對象v在被廣播之後就不應該再修改。
1.通過對一個類型T的對象調用SparkContext.broadcast創建一個Broadcast[T]對象
2.通過value屬性訪問該對象的值
3.變量只會背發到各個節點一次,應作爲只讀值處理。(修改這個值不會影響到別的節點)

數值RDD操作:
Spark的數值操作是通過流式算法實現,允許以每次一個元素的方式構建模型,統計數據會在調用stats()時通過一次遍歷數據計算而來,並以StatsCounter對象返回。
count() RDD中元素個數
mean() 元素平均值
sum() 總和
max()min() 最大最小值
variance() sampleVariance() 方差 採樣中計算的方差
stdev() sampleStdec() 標準差 採樣中計算的標準差
具體的:
val dist = ...
val stats = dist.stats()
val stddev = stats.stdev
val mean = stats.mean
...


第七章:在集羣上運行Spark
不論使用哪種集羣管理器,都可以使用統一腳本spark-submit將應用提交到集羣管理器上。
在集羣上運行Spark應用的詳細過程:
1.通過spark-submit提交應用
2.腳本啓動驅動器程序,調用用戶定義的main()方法
3.驅動器程序與集羣管理器通信,申請資源以啓動執行器節點
4.集羣管理器爲驅動器程序啓動執行器節點
5.驅動器進程執行用戶應用的操作,根據所定義的對RDD的轉化操作和行動操作,驅動器節點把工作以任務的形式發送到執行器進程
6.任務在執行器程序中進行計算並保存結果
7.如果main方法退出,或者調用了SparkContext.stop(),驅動器程序會中止執行器進程,並通過集羣管理器釋放資源。

Spark-submit部署應用:
當調用submit時除了腳本或JAR包的名字之外沒有別的參數,那麼程序只會在本地執行。當希望將應用提交到集羣上的時候,可以講集羣地址和希望啓動的每個執行器進程的大小作爲附加標記。
--master指定要連接的集羣url:
spark://host:port 指定端口的Spark獨立集羣上 默認7077
mesos://host:port 指定端口的Mesos集羣,默認5050
yarn:連接到YARN集羣
local 本地模式,單核
local[n] 本地模式,N核
local[*] 本地模式,儘可能多核

spark-submit的一般格式:
bin/spark-submit [option] <app jar | python file> [app option]
[option]是標記列表:
--master 集羣管理器
--deploy-mode 選擇在本地啓動(client)驅動器程序還是集羣中的一臺工作節點機器(cluster)上啓動
--class 運行Scala程序時應用的主類
--name 應用的顯示名
--jars 需要上傳並放到應用的CLASSPATH中的JAR包的列表
--files 需要放到應用工作目錄中的文件的列表,這個參數一般用來放需要分發到各節點的數據文件。
--executor-memory 執行器進程使用的內存量,512m或15g
--driver-memory 驅動器進程使用的內存兩

<app jar | python file> 表示包含應用入口的JAR包或python腳本
[app option] 傳給應用的選項

代碼打包通常使用構建工具生成單個大JAR包,使用最廣泛的構建工具是Maven(通常用於java)和sbt(通常用於scala)。
工程的根目錄中,需要創建一個叫做build.sbt的構建文件,源代碼放在src/main/scala中。

YARN是hadoop2.0中引入的集羣管理器,他可以讓多種數據處理框架運行在一個共享的資源池上,並且通常安裝在與hadoop文件系統相同的物理節點上,在這樣配置的YARN集羣上運行spark是很有意義的,可以讓spark在存儲數據的物理節點上運行,快速訪問hdfs數據。
需要找到你的hadoop配置目錄,並把它設置爲環境變量HADOOP_CONF_DIR

如果從0開始,可以選擇獨立集羣管理器,安裝簡單。
如果要使用sprk的同時使用其他應用,用yarn,對於大多數的hadoop發行版,yarn已經裝好了
任何時候,最好把spark運行在運行hdfs的節點上,能快速訪問存儲。如果使用yarn,大多數發行版已經把yarn和hdfs裝在一起了。


第八章:Spark調優與調試
對Spark進行性能調優,通常就是修改Spark應用的運行時配置選項,最主要的配置機制就是通過SparkConf類進行配置。
Spark中每個配置選項都是基於字符串形式的鍵值對,可以調用set()方法添加配置項,也有一些工具方法例如setAppname、setMaster()
Spark允許通過spark-submit工具動態設置配置項。--master --name --conf --properties-file 
同一個配置項可能在多個地方設置,spark有特定的優先級:代碼顯示調用set > spark-submit > 配置文件 > 系統默認值

Spark執行時會有下面的流程:
1.用戶代碼定義RDD的有向無環圖
    RDD上的操作會創建出新的RDD,並引用它們的父節點,這樣就創建了一個圖。
2.行動操作把有向無環圖強制轉譯爲執行計劃
    當調用RDD的行動操作時,這個RDD就必須被計算。這也要求計算該RDD的父節點。Spark調度器提交一個作業來計算所有必要的RDD。這個作業會包含一個或者多個步驟,每個步驟也就是一波並行執行的計算任務。一個步驟對應有向無環圖中的一個或多個RDD,一個步驟對應多個RDD是因爲發生了流水線執行。
3.任務於集羣中調度並執行
    步驟是按順序處理的,任務則獨立的啓動來計算出RDD的一部分。一旦作業的最後一個步驟結束,一個行動操作也就執行完畢。

日誌文件:
調試:
yarn-container-logs application_ID
殺死:
yarn application -kill application_ID

並行度:
判斷並行度是否過高的標準包括任務是否是幾乎在瞬間完成,或者是否觀察到任務沒有讀寫任何數據
兩種並行度調優的方法:1.在數據混洗操作時,使用參數的方式爲混洗後的RDD指定並行度,2.對任何已有的RDD,重新分區(repartition())

內存管理:
默認情況下,Spark會使用60%的空間存儲RDD,20%的空間存儲數據混洗操作產生的數據,20%的空間留給用戶程序。用戶可以自行調節這些選項來追求更好的表現性能。

硬件供給:
提供給Spark的硬件資源會顯著影響應用的完成時間。影響集羣規模的主要參數包括
1.分配給每個執行器節點的內存大小 --executor-memory
2.每個執行器節點佔用的核心數        --executor-cores
3.執行器節點總數                            --num-executors
4.用來存儲臨時數據的本地磁盤數量
一般來說,更大的內存和更多的計算核心對Spark應用會更有用處。
除了內存和CPU核心,Spark還要用到本地磁盤來存儲數據混洗操作的中間數據以及溢寫到磁盤中的RDD分區數據。因此使用大量的本地磁盤可以幫助提升Spark應用的性能。YARN模式下,提供了指定目錄的機制,Spark本地磁盤配置項會直接從YARN的配置中讀取。
切記“越多越好”的原則在設置執行器節點內存時並不一定適用,使用巨大的堆空間可能會導致垃圾回收的長時間暫停,從而影響Spark作業的吞吐量。有時使用較小內存(比如不超過64GB)的執行器實例可以緩解該問題。


第十章:Spark Streaming
Spark Streaming使用離散化流做抽象表示,叫做DStream。可以從各種輸入源創建,比如Flume、Kafka或者HDFS。支持轉化操作和輸出操作。

import聲明:
import org.apache.spark.streaming.(StreamingContext | StreamingContext._ | dstream.Dstream | Duration | Seconds)

StreamingContext除了會在底層創建出SparkContext之外,構造函數還接受一個批次間隔處理新數據。要開始接收數據,必須顯示調用StreamingContext的start()方法,這樣SparkStreaming會開始把Spark作業不斷交給底層的SparkContext調度執行。執行會在另一個線程中進行,所以需要調用awaitTermination來等待流計算完成,防止應用退出。500ms已經被證實爲對許多應用是比較好的最小批次大小。

架構與抽象
SparkStreaming使用微批次的架構,把流式計算當作一系列連續的小規模批處理來對待,從各個數據源讀入數據,按時間間隔創建小批次數據,每個批次形成一個RDD,這樣一系列的RDD序列就是DStream。

轉化操作
分爲無狀態和有狀態兩種
無狀態:
批次處理不依賴與之前批次數據,例如map、flatmap、filter、reducebykey、repartition、groupbykey等
針對鍵值對的DStream,需要import org.apache.spark.streaming.StreamingContext._才能使用。
無狀態轉化操作是分別應用到DStream中的每個RDD上,也即會規約每個時間區間但是不會規約不同區間的數據;也可以整合多個DStream數據,但也是同一時間區間。
transform()高級函數,提供一個任意RDD到RDD的函數即可轉化。

有狀態:
需要使用之前批次數據或者中間結果,主要包括基於滑動窗口和追蹤狀態變化的操作。
是跨越時間區間跟蹤數據的操作。並且需要在StreamingContext中打開檢查點機制來確保容錯性。
基於窗口:
需要兩個參數,窗口時長和滑動步長,都必須是StreamingContext的批次間隔的整數倍。
最簡單的操作是window()函數,其生成的DStream中每個RDD會包含多個批次中的數據,可以對這些數據進行count、transform的操作。
儘管wndow可以寫出所有窗口操作,但Streaming還提供了一些其他的窗口操作,方便高效使用,例如reducebywindow、reducebykeyandwindow等。並且可以提供一個規約函數的逆函數,用於增量計算規約結果,即只計算新加入和剛離開的窗口數據。
追蹤狀態:
updateStateByKey()函數提供了一個對狀態變量的訪問,用於鍵值對形式的DStream。給定一個由(鍵、事件)對構成的DStream,並傳遞一個制定如何根據新的事件更新每個鍵對應狀態的函數,它可以構建出一個新的DStream,內部數據爲(鍵、狀態)對。
使用該函數,需要提供一個update(events,oldstate)函數,接受與某個鍵相關的事件以及該鍵之前的狀態,返回新狀態。events表示當前批次收到的事件列表,可以爲空;oldstate、newstate存放在option內。

輸出操作(同RDD行動操作)
print、save()、foreachRDD,同樣是惰性求值

輸入源
所有用來從核心數據源創建DStream的方法都位於StreamingContext中。
還有附加數據源,這些數據源接收器都作爲Streaming的組件進行獨立打包,現有的接收器包括twitter、kafka、amazon kinesis、flume等,可以通過添加與Spark版本匹配的Maven工件
spark-streaming-[projectname]_2.10來引入。

24/7不間斷運行
要不間斷運行SparkStreaming應用,需要一些特別的配置。第一步是設置好諸如HDFS或者Amazon s3等可靠系統的檢查點機制,還需要考慮驅動器程序的容錯性以及對不可靠輸入源的處理。

檢查點機制主要爲以下兩個目的服務:
1.控制發生失敗時需要重算的狀態數。SparkStreaming可以通過轉化圖的譜系圖來重算狀態,檢查點機制可以控制需要在轉化圖中回溯多遠。
2.提供驅動器程序容錯。如果流計算應用中驅動器程序奔潰了,可以重啓驅動器並讓驅動器從檢查點恢復,這樣Streaming可以讀取之前處理進度並繼續。
通過ssc.checkpoint("路徑")

驅動器程序容錯要求我們以特殊的方式創建StreamingContext。我們需要把檢查點目錄提供給StreamingContext,與直接調用new StreamingContext不同,應該使用StreamingContext.getOrCreate函數。也即如果第一次運行,則需要創建檢查點,之後失敗後重啓,由於檢查點存在,因此直接從檢查點目錄中初始化StreamingContext即可。

除了用getOrCreate實現初始化代碼之外,還需要編寫在驅動器程序崩潰時重啓驅動器進程的代碼。Spark在集羣管理器中提供了支持,在提交驅動器程序時使用--supervise標記來讓Spark重啓失敗的驅動器程序。


第十一章:MLlib機器學習
MLlib設計理念非常簡單:把數據以RDD的形式表示,然後再分佈式數據集上調用各種算法。大致的步驟如下:
1.首先用字符串RDD來表示消息
2.運行MLlib中一個特徵提取算法把文本數據轉化成數值特徵,該操作返回一個向量RDD
3.對向量RDD調用分類算法,返回一個模型對象,可以使用該對象對新的數據點進行分類
4.使用MLlib的評估函數在測試數據集上評估模型

注意:MLlib只包含能夠在集羣上運行良好的並行算法,沒有包含的算法是不能並行執行的。如果要在許多小規模數據集上訓練各機器學習模型,最好是在各節點上用單節點的機器學習算法庫。
類似的,在機器學習流水線中也常常用同一算法的不同參數對小規模數據集分別訓練來選出一組最好的參數。在Spark中可以通過把參數列表傳給parallelize()來在不同節點上分別運行不同的參數,而在每個節點上則使用單節點的機器學習庫萊實現。

系統要求:
MLlib需要預裝一些線性代數庫,首先需要安裝gfortran運行庫,參考網站:http://spark.apache.org/docs/latest/mllib-guide.html
其次如果要在python中使用MLlib,需要安裝Numpy。

數據類型:
MLlib包含一些特有的數據類型,位於org.apache.spark.mllib包中
1.Vector
    數學向量。可以通過mllib.linalg.Vectors類創建出來
2.LabeledPoint
    用來表示帶標籤的數據點。包含一個特徵向量與一個標籤,位置在mllib.regression包中
3.Rating
    用戶對一個產品的評分,在mllib.recommendation包中,用於產品推薦
4.各種Model類
    每個Model都是訓練算法的結果,一般有一個predict()方法可以用來對新的數據點或數據點組成的RDD應用該模型進行預測

python中傳遞Numpy數組都是稠密向量,也可以用vector類創建,但是java和scala中需要使用mllib.linalg.Vectors類創建稠密或稀疏向量。
Vectors.dense(一串值或一個數組)
Vectors.sparse(4, Array(0,2), Array(1.0,2.0)) <1.0,0.0,2.0,0.0>

Vector類只用來表示數據,而不提供算數操作,可以使用一些第三方庫來進行向量運算,比如Breeze。

特徵提取:
mllib.feature包中包含一些用來進行常見特徵轉化的類。

TF-IDF:
詞頻-逆文檔頻率 是一種用來從文本文檔中生成特徵向量的簡單方法。它爲文檔中的每個詞計算兩個統計值:
1.詞頻:在文檔中出現的次數
2.逆文檔頻率:衡量一個詞在整個文檔語料庫中出現的(逆)頻繁程度
TF*IDF展示了一個詞與特定文檔的相關程度。有兩個算法可以用來計算TF-IDF:HashingTF和IDF。
1.HashingTF要求每個文檔都使用對象的可迭代序列來表示。
    val tf=new HashingTF(numFeatures = $)
    val tfvectors = tf.transform($).
2.IDF基於TF
    val idf = new IDF()
    val idfmodel = idf.fit(tfvectors)
    val tfIdfVectors = idfmodel.transform(tfvectors)
由於調用了兩次tfvectors,可以將其調用cache()方法緩存。

縮放:
在構建好特徵向量後,可以使用StandardScaler類來進行縮放,同時控制均值和標準差。
首先創建一個StandardScaler對象,對數據集調用fit()函數來獲取一個StandardScalerModel(也即爲每一列計算平均值和標準差),然後使用transform()方法縮放一個數據集。

正規化:
Normalize.transform(RDD)即可,默認使用L2歸一化,也可以傳遞一個參數P來使用LP歸一化

Word2vec:
在mllib.feature.Word2Vec引入了該算法的實現,具體用法和上面差不多。

統計:
mllib.stat.Statistics包中提供了很多方法。
1.Statistics.colStats(RDD)
計算向量組成的RDD的統計性綜述,包含向量集合每列的最小值、最大值、平均值和方差。
2.Statistics.corr(RDD,method)
計算向量組成的RDD列間的相關矩陣,使用皮爾森相關活斯皮爾曼相關的一種(method必須是pearson或spearman)
3.Statistics.corr(RDD1,RDD2,method)
計算兩個由浮點值組成的RDD的相關矩陣
4.Statistics.chiSqTest(RDD)
計算由LabeledPoint對象組成的RDD中每個特徵與標籤的皮爾森獨立性測試結果。其中有p值、測試統計和每個特徵的自由度。
除此之外,RDD還支持sample()和sampleByKey(),可以構建出簡單而分層的數據樣本。

分類與迴歸:
分類和迴歸都使用labeledpoint類,一個labeledpoint是由一個label(label總是一個double值)和一個feature組成
二分類,預期標籤爲0和1,多分類,預期標籤範圍是從0~C-1
1.線性迴歸
使用mllib.regression.LinearRegressionWithSGD、LassoWithSGD以及RidgeRegressionWithSGD。
調優參數:
numIterations(默認100次)
stepSize(默認1.0 梯度下降的步長)
intercept(默認false,是否給數據加上一個干擾特徵或者偏差特徵,也就是一個值始終爲1的特徵)
regParam(默認1.0,Lasso和ridge的正則化參數)
調用:
創建一個對象,調用setter方法設置各種參數,調用run()方法來訓練模型。run返回的model會帶有predict()函數預測單個特徵向量。

2.邏輯迴歸
使用mllib.classification.LogisticRegressionWithLBFGS/SGD
接口和線性迴歸一樣。
可以通過setThreshold()改變閾值輸出0和1(默認爲0.5),也可以通過clearThreshold()去除閾值設置,這樣predict()返回的是原始得分。

3.支持向量機
SVMWithSGD。
參數和線性迴歸差不多,一樣可以使用閾值的方式進行預測。

4.樸素貝葉斯
mllib.classification.NaiveBayes
支持一個參數lambda,用來平滑化。

5.決策樹與隨機森林
mllib.tree.DecisionTree中的trainClassifier()和trainRegressor()方法來訓練決策樹。
參數:
data:RDD
numClasses:要使用的類別數量
impurity:節點的不純淨度度量,分類可以用gini或entropy,迴歸必須variance
maxDepth:樹的最大深度(默認5)
maxBins:在構建各節點時將數據分到多少個箱子中(推薦32)
categoricalFeaturesInfo:一個映射表,指定哪些特徵是分類的,以及他們各有多少個分類。

除了predict之外可以使用toDebugString()來輸出這棵樹。

隨機森林RandomForest.trainClassifier()和trainRegressor()來使用。
除了決策樹的參數外還接受:
numTrees:樹的數量
featureSubsetStrategy:每個節點上需要考慮的特徵數量。可以使auto、all、sqrt、log2以及onethird。
seed:隨機數種子

聚類:
kmeans:創建mllib.clustering.KMeans對象,返回一個KMeansModel對象,可以訪問聚類中心也可以預測新向量所屬聚類
參數:
initializationMode:初始化中心的方法,可以是k-means||、random,前者結果更好但開銷更大
maxIterations:最大迭代次數(默認100)
runs:算法併發運行的數目

協同過濾及推薦:
交替最小二乘(ALS):是協同過濾的常用算法,位於mllib.recommendation.ALS類中
ALS爲每個用戶和產品都設一個特徵向量,這樣用戶向量和產品向量的點積接近於他們的得分。
參數:
rank:特徵向量大小(默認10)
iterations:迭代次數(默認10)
lambda:正則化參數(默認0.01)
alpha:用來在隱式ALS中計算置信度的常量(默認值1.0)
numUserBlocks,numProductBlocks:切分用戶和產品數據的塊的數目,用來控制並行度。(默認-1自動決定)

需要有一個由mllib.recommendation.Rating對象組成的RDD,其中每個包含一個用戶ID,一個產品ID和一個評分。
ALS返回一個MatrixFactorizationModel對象,可以調用predict來對一個由(userid,productid)組成的RDD進行預測評分。也可以用model.recommendProducts(userid, numProducts)來爲給定用戶找到前num個推薦產品。

對於顯式評分數據,調用ALS.train(),隱式反饋調用ALS.trainImplicit()。顯式預測出來的也是評分,隱式評分代表的是用戶與產品發生交互的置信度。

降維:
要使用PCA,首先使用mllib.linalg.distributed.RowMatrix來表示矩陣,存儲由vector組成的RDD,每行一個。
調用computePrincipalComponents()返回mllib.linalg.Matrix對象,得到投影係數。可以調用toArray方法獲取底層數據。
接着調用multiply()將原始的RowMatrix投影到低維空間。

奇異值分解,調用RowMatrix類的computeSVD方法。

模型評估:
mllib.evaluation包中,根據問題的不同,它們在BinaryClassificationMetrics和MulticlassMetrics等不同類中。使用這些類,可以從由(預測、事實)對組成的RDD上創建一個Metrics對象,然後計算精確率、召回率、接受者操作特性ROC曲線下的面積等指標。

緩存RDD:
MLlib大多數算法都是迭代的,對數據進行反覆操作。因此把數據集傳給MLlib前使用cache()將其緩存起來是很重要的。即使數據在內存中放不下,也應該嘗試persist(StorageLevel.DISK_ONLY)

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