下麵是章節線性模型的目錄(其他內容參見全文目錄)
數學公式
很多標準的機器學習方法都可以歸結為凸優化問題。例如,尋找凸函數f(w)極小值的任務(w[weights]為d維權值向量,它是函數f的自變量)。比較正式地,我們可以將之寫作優化問題:min f(w), w∈Rd,其目標函數如下:
這裏向量xi∈Rd(1<=i<=n)是訓練樣本,yi∈R是相應的標簽,標簽也是訓練出模型之後需要預測的值。當用到的損失函數L(w; x, y)表示為wTx和y(wT是w的轉置,轉置之後才能和x做矩陣乘法),機器學習方法就可以認為是線性的。MLlib中的幾個分類和回歸算法就是這個線性類型,是我們這裏要討論的。
目標函數f分為兩部分:正則化部分控製模型的複雜度,損失函數部分評估模型在訓練數據上的錯誤率。損失函數L(w;.)一般是w的凸函數。固定的正則化參數(λ>=0)用於調節最小化損失函數和最小化模型複雜段這兩個目標之間的平衡(例如,避免過擬合)。
損失函數
下表匯總了MLlib支持的損失函數和對應的梯度或者次梯度[1](次梯度可用於不可微函數,沒有梯度的限製嚴格)。
正則化是為了約束訓練過程,使其向生成簡單模型的方向收斂,從而避免過擬合。MLlib目前支持下麵的正則化方法:Here sign(w)
is the vector consisting of the signs (±1
) of all the entries of w
.
注:提到正則化,必須要說一下數學中範數(norm)的概念。範數是具有“長度”概念的函數。最常用的範數是p-範數,其定義為:若x = [x1, x2, x3, …, xn]T,那麽||x||p = (|x1| p+ |x2|p + |x3|p + … + |xn|p)1/p 。當p取值為1和2時,就是我們的L1和L2【2-範數的平方除以2】正則化:
由於平滑的特性,L2正則化問題比L1正則化更容易解決。但是,L1正則可以促進產生稀疏的權值,從而產生簡單可解釋的模型。並且,L1由於產生稀疏的權值(即大部分取值為0),相當於做了特征選擇。不建議做沒有正則化的模型訓練,特別是訓練樣本特別少的時候。
優化
線性模型底層使用凸函數優化方法來優化目標函數。MLlib中使用了兩種方法,SGD和L-BFGS,章節 optimization section會有具體介紹。當前,絕大多數MLlib的算法API支持隨機梯度下降法(SGD),部分支持L-BFGS。
分類
分類旨在將多個條目分到不同的類別。最常見的分類類型是二分類,兩個類型通常被比較為正和負。 如果多於兩個類型的話,就是多分類。MLlib提供兩種線性方法用於分類:線性支持向量機(SVM)和邏輯回歸。SVM隻支持二分類,而邏輯回歸既支持二分類又支持多分類。這兩種方法,都提供了L1和L2正則化。訓練數據集用RDD[LabeledPoint]表示,其中label是分類類型的索引,從0開始,即0, 1, 2, …。注意在上文的數學公式部分,二分類標簽y使用+1和-1標記,這個是為了方便公式化。實際再MLlib中,使用0代替了-1,從而更多分類保持一致。
線性支持向量機(SVMs)
線性SVM是用於大規模分類任務的一種標準方法。它用到的線性方法上文的等式(1)中已經有說明,使用的損失函數為hinge loss:
默認情況下,線性SVM使用L2正則化做訓練。也可以替換為L1正則化,這樣就成了線性優化問題。
線性SVM算法輸出的是SVM模型。給定一個新的數據點(用x表示),模型基於wTx的值做預測。默認情況下, 如果wTx>=0則結果為正例,否則為負例。
下麵的代碼片(Spark Pthon SVM)段說明了如何導入一個樣本數據集,進行模型訓練,並做出預測。(Python中的SVMModel目前還不支持load和save數據)
#!/usr/bin/python
from pyspark import SparkContext;
from pyspark.mllib.util import MLUtils;
from pyspark.mllib.classification import SVMWithSGD;
sc = SparkContext(appName="svmTesting");
# Load training data in LIBSVM format.
data = MLUtils.loadLibSVMFile(sc, 'data/mllib/sample_libsvm_data.txt');
print "FirstRecord:", data.take(1);
# Split data into training (70%) and test (30%).
splits = data.randomSplit([0.7, 0.3], seed = 11L);
training = splits[0].cache();
print "TrainingCount:[%d]"%training.count();
test = splits[1];
print "TestingCount:[%d]"%test.count();
# Run training algorithm to build the model
numIterations = 100;
model = SVMWithSGD.train(training, numIterations);
# Clear the default threshold.
model.clearThreshold();
# Compute raw scores on the test set.
scoreAndLabels = test.map(lambda point : (model.predict(point.features), point.label));
# output score and label.
for score, label in scoreAndLabels.collect():
print score, label;
附SVMWithSGD.train(data, iterations=100, step=1.0, regParam=0.01, miniBatchFraction=1.0, initialWeights=None, regType=’l2′, intercept=False)的參數說明:
Parameters: |
|
---|
邏輯回歸(Logistic regression)
邏輯回歸廣泛應用於二分類問題。它是線性分類方法(參見公式(1)),損失函數是logistic loss:
其中exp是以自然常數e為底的指數函數。對二分類問題來說,這個算法輸出一個二分邏輯回歸模型。給定一個新的數據點(x),模型應用下麵的邏輯函數給出預測:
二分邏輯回歸可以泛化為多項式邏輯回歸 ,用於訓練和預測多分類問題。例如,對於K個可能的輸出,其中一個輸出可被選作“中心點”(pivot),另外的K-1個輸出可以分別跟中心點輸出進行回歸。在MLlib中,第一個類0被選作“中心點”類。可以參考《The Elements of Statistical Learning》的章節4.4了解詳情。
對於多分類問題,算法會輸出一個多項式回歸模型,它包含K-1個跟第一類配對的二元回歸模型。給定一個新的數據點,K-1個模型都會被執行,概率最大的類會被選作預測的類型。
我們實現了兩種算法用於解決邏輯回歸問題:min-batch梯度下降和L-BFGS。推薦使用L-BFGS,因為它收斂更快。
下麵的例子說明了怎樣導入樣本數據集,建立邏輯回歸模型,使用結果模型進行預測並計算訓練的錯誤率。
from pyspark.mllib.classification import LogisticRegressionWithLBFGS
from pyspark.mllib.regression import LabeledPoint
from numpy import array
# Load and parse the data
def parsePoint(line):
values = [float(x) for x in line.split(' ')]
return LabeledPoint(values[0], values[1:])
data = sc.textFile("data/mllib/sample_svm_data.txt")
parsedData = data.map(parsePoint)
# Build the model
model = LogisticRegressionWithLBFGS.train(parsedData)
# Evaluating the model on training data
labelsAndPreds = parsedData.map(lambda p: (p.label, model.predict(p.features)))
trainErr = labelsAndPreds.filter(lambda (v, p): v != p).count() / float(parsedData.count())
print("Training Error = " + str(trainErr))
回歸
線性最小二乘法,Lasso,嶺回歸(Linear least squares, Lasso, and ridge regression)
線性最小二乘法是回歸問題中最常用的公式,如公式(1)所述它是一個線性方法,損失函數是squared loss:
from pyspark.mllib.regression import LabeledPoint, LinearRegressionWithSGD
from numpy import array
# Load and parse the data
def parsePoint(line):
values = [float(x) for x in line.replace(',', ' ').split(' ')]
return LabeledPoint(values[0], values[1:])
data = sc.textFile("data/mllib/ridge-data/lpsa.data")
parsedData = data.map(parsePoint)
# Build the model
model = LinearRegressionWithSGD.train(parsedData)
# Evaluate the model on training data
valuesAndPreds = parsedData.map(lambda p: (p.label, model.predict(p.features)))
MSE = valuesAndPreds.map(lambda (v, p): (v - p)**2).reduce(lambda x, y: x + y) / valuesAndPreds.count()
print("Mean Squared Error = " + str(MSE))
流式線性回歸(Streaming linear regression)
當數據以流的方式到達時,就很有必要使回歸模型適應在線環境,每當有新的數據到來時就得更新模型參數。MLlib當前支持普通最小二乘法的流式線性回歸。擬合過程跟離線情況類似,但是要實時擬合每一批數據,使得模型能夠及時持續更新從而能夠預測流式數據。(目前隻有Scala支持流式線性回歸)
實現 (developer)
幕後,MLlib實現了一個簡單分布式版本的隨機梯度下降算法,建立在底層的梯度下降優化原語上(參見 optimization )。所有算法都會接受一個正則化參數(regParam)和多個其他的梯度下降相關的參數(stepSize
, numIterations
, miniBatchFraction
)。每種算法都支持三種可能的正則化(none, L1或者L2)。
對於邏輯回歸,L-BFGS 版本在LogisticRegressionWithLBFGS中實現。這個版本支持二分邏輯回歸和多項式邏輯回歸,而SGD版本隻能支持二分邏輯回歸。但是,L-BFGS版本不支持L1正則化,SGD版本支持L1正則化。當L1不是必須的時候,強烈推薦用L-BFGS版本,因為相對於SGD來說,它通過擬牛頓近似逆Hessian矩陣收斂得更快更準。
算法都是使用Scala語言實現的:
- SVMWithSGD
- LogisticRegressionWithLBFGS
- LogisticRegressionWithSGD
- LinearRegressionWithSGD
- RidgeRegressionWithSGD
- LassoWithSGD
Python通過 PythonMLLibAPI 調用Scala的實現。
參考:
[1] http://zh.wikipedia.org/wiki/%E6%AC%A1%E5%AF%BC%E6%95%B0
[2] http://baike.baidu.com/link?url=x8hkYh5wI-5wQItUQTbMUwPTkNhCBFqPzh7DTaSf8z8cUZgxGrnviVvPeBEPbgQ_3AjiX7gtwtQ_defHP_r22K