1. 程式人生 > >LASSO和L1正則包liblinear,glmnet使用和對比

LASSO和L1正則包liblinear,glmnet使用和對比

LASSO演算法有很多包,今天我就兩個常用包liblinear和glmnet做一下分析,並給出我做分類的例子。

liblinear

LIBLINEAR是一個簡單的求解大規模規則化線性分類和迴歸的軟體包。 Liblinear是國立臺灣大學的Chih-Jen Lin博士開發的,主要應對large-scale的data classification。liblinear包提供的演算法包括:
這裡寫圖片描述
我們要使用的lasso就是L1正則的logistic regression。
首先,liblinear的官方網站是:
https://www.csie.ntu.edu.tw/~cjlin/liblinear/


裡面使用的lasso演算法newGLMNET解法涉及到的論文是:
http://www.csie.ntu.edu.tw/~cjlin/papers/l1_glmnet/long-glmnet.pdf.

求解問題
liblinear中的lasso要求解的問題是:
這裡寫圖片描述
使用的newGLMNET是改進後的座標下降,
這裡寫圖片描述
這裡做了泰勒展開,因為求解二階導涉及到hessian矩陣,而H未必滿足正定條件,因此,newGLMNET增加了一個微小項:
這裡寫圖片描述
並將原來glmnet演算法中的log計算進行了近似和簡化。

演算法使用
主要引數如下:

-c cost : 設定引數 C(預設是1
-p epsilon :
設定epsilon-SVR的損失函式的引數epsilon(預設是0.1
-e epsilon : 設定迭代終止條件的容忍度tolerance -B bias : 如果bias >= 0,那樣樣本x變為[x; bias],如果小於0,則不增加bias項(預設是-1 -wi weight: 調整不同類別的引數C的權值(具體見README -v n: n-fold交叉檢驗模式。它隨機的將資料劃分為n個部分,然後計算它們的交叉檢驗準確率。 -q : 安靜模式(無輸出資訊)

liblinear實現了matlab、Java、R、Python等多種介面,具體程式碼不再詳述。

glmnet

求解問題
這裡寫圖片描述
這裡寫圖片描述
這裡的P可以通過控制α引數實現Elastic Net和L2正則的求解
由上述表示式可以看出,相比liblinear,二者的lambda權重一個加在損失函式上,一個加在正則項上,使用前一定要弄清楚這一點。
LASSO迴歸複雜度調整的程度由引數λ來控制,λ越大對變數較多的線性模型的懲罰力度就越大,從而最終獲得一個變數較少的模型。 LASSO迴歸與Ridge迴歸同屬於一個被稱為Elastic Net的廣義線性模型家族。 這一家族的模型除了相同作用的引數λ之外,還有另一個引數α來控制應對高相關性(highly correlated)資料時模型的性狀。 LASSO迴歸α=1,Ridge迴歸α=0,一般Elastic Net模型0<α<1。

演算法使用
glmnet主要變數和引數如下:
這裡寫圖片描述
引數family規定了迴歸模型的型別:

  family="gaussian"適用於一維連續因變數(univariate)
  family="mgaussian"適用於多維連續因變數(multivariate)
  family="poisson"適用於非負次數因變數(count)
  family="binomial"適用於二元離散因變數(binary)
  family="multinomial"適用於多元離散因變數(category)

這裡的type.measure是用來指定交叉驗證選取模型時希望最小化的目標參量,對於Logistic迴歸有以下幾種選擇:
 

 type.measure=deviance 使用deviance,即-2倍的Log-likelihood
  type.measure=mse 使用擬合因變數與實際應變數的mean squred error
  type.measure=mae 使用mean absolute error
  type.measure=class 使用模型分類的錯誤率(missclassification error)
  type.measure=auc 使用area under the ROC curve,是現在最流行的綜合考量模型效能的一種引數

預測時的type有以下幾種選擇:

type=link 給出線性預測值,即進行Logit變換之前的值
  type=response 給出概率預測值,即進行Logit變換之後的值
  type=class 給出0/1預測值
  type=coefficients 羅列出給定λ值時的模型係數
  type=coefficients 羅列出給定λ值時,不為零模型係數的下標

引數nlambda=50讓演算法自動挑選50個不同的λ值,擬合出50個係數不同的模型。 alpha=1輸入α值,1是它的預設值。 值得注意的是,glmnet只能接受數值矩陣作為模型輸入,如果自變數中有離散變數的話,需要把這一列離散變數轉化為幾列只含有0和1的向量,這個過程叫做One Hot Encoding。

最後附上我使用glmne進行二分類的完整程式碼,包括資料讀入,資料預處理,模型構建,評價和預測:

library(Matrix)
library(glmnet) 
library(SDMTools)


data <- read.csv('test.csv',header = FALSE)
index_nominal <- c(2,137,138,139,140,176,177,206)
index_numeric <- setdiff(c(1:206),index_nominal)
#上述兩個是對資料中離散值和連續值列下標進行標記
#資料歸一化
for (i in index_numeric){
  data[,i] <- scale(data[,i],center = TRUE,scale = TRUE)
}
#資料one hot encode
for (i in index_nominal){
  data[,i] <- factor(data[,i])
}

#資料取樣
set.seed(2)
split <- sample(nrow(data), floor(0.5*nrow(data)))
train <-data[split,]
test <- data[-split,]
#構建測試集和訓練集
train_x = train[,1:(ncol(train)-1)]
train_y = train[,ncol(train)]
matrix_train <- data.matrix(train_x)
matrix_train_y <- data.matrix(train_y)
#處理缺失值空值
matrix_train[is.na(matrix_train )] <-0
matrix_train [is.null(matrix_train )] <-0
matrix_train_y[is.na(matrix_train_y )] <-0
matrix_train_y [is.null(matrix_train_y )] <-0
#rapply( matrix_train , f=function(x) ifelse(is.nan(x),0,x), how="replace" )
#rapply( matrix_train , f=function(x) ifelse(is.infinite(x),0,x), how="replace" )

table(matrix_train_y)
#轉換成matrix
test_x = test[,1:(ncol(test)-1)]
test_y = test[,ncol(test)]
matrix_test <- data.matrix(test_x)
matrix_test_y <- data.matrix(test_y)

matrix_test[is.na(matrix_test )] <-0
matrix_test [is.null(matrix_test )] <-0
matrix_test_y[is.na(matrix_test_y )] <-0
matrix_test_y [is.null(matrix_test_y )] <-0


table(matrix_test_y)

#訓練模型
fit <- glmnet(matrix_train,matrix_train_y,family="binomial")
print(fit)
#交叉驗證選最好的引數
cv <- cv.glmnet(matrix_train,matrix_train_y,type.measure='auc', family = "binomial")
best_lambda <- cv.glmmod$lambda.min
print(best_lambda)
#進行預測
pred<- predict(fit,newx=matrix_test,s=best_lambda,type = 'response')
confusion.matrix(matrix_test_y,pred,threshold=0.5)