Tại sao lasso không hội tụ về một tham số hình phạt?


7

Để khám phá cách LASSOhồi quy hoạt động, tôi đã viết một đoạn mã nhỏ để tối ưu hóa LASSOhồi quy bằng cách chọn tham số alpha tốt nhất.

Tôi không thể hiểu tại sao LASSOhồi quy lại cho tôi kết quả không ổn định như vậy đối với tham số alpha sau khi xác thực chéo.

Đây là mã Python của tôi:

from sklearn.linear_model import Lasso
from sklearn.cross_validation import KFold
from matplotlib import pyplot as plt

# generate some sparse data to play with
import numpy as np
import pandas as pd 
from scipy.stats import norm
from scipy.stats import uniform

### generate your own data here

n = 1000

x1x2corr = 1.1
x1x3corr = 1.0
x1 = range(n) + norm.rvs(0, 1, n) + 50
x2 =  map(lambda aval: aval*x1x2corr, x1) + norm.rvs(0, 2, n) + 500
y = x1 + x2 #+ norm.rvs(0,10, n)

Xdf = pd.DataFrame()
Xdf['x1'] = x1
Xdf['x2'] = x2

X = Xdf.as_matrix()

# Split data in train set and test set
n_samples = X.shape[0]
X_train, y_train = X[:n_samples / 2], y[:n_samples / 2]
X_test, y_test = X[n_samples / 2:], y[n_samples / 2:]

kf = KFold(X_train.shape[0], n_folds = 10, )
alphas = np.logspace(-16, 8, num = 1000, base = 2)

e_alphas = list()
e_alphas_r = list()  # holds average r2 error
for alpha in alphas:
    lasso = Lasso(alpha=alpha, tol=0.004)
    err = list()
    err_2 = list()
    for tr_idx, tt_idx in kf:
        X_tr, X_tt = X_train[tr_idx], X_test[tt_idx]
        y_tr, y_tt = y_train[tr_idx], y_test[tt_idx]
        lasso.fit(X_tr, y_tr)
        y_hat = lasso.predict(X_tt)

        # returns the coefficient of determination (R^2 value)
        err_2.append(lasso.score(X_tt, y_tt))

        # returns MSE
        err.append(np.average((y_hat - y_tt)**2))
    e_alphas.append(np.average(err))
    e_alphas_r.append(np.average(err_2))

## print out the alpha that gives the minimum error
print 'the minimum value of error is ', e_alphas[e_alphas.index(min(e_alphas))]
print ' the minimizer is ',  alphas[e_alphas.index(min(e_alphas))]

##  <<< plotting alphas against error >>>

plt.figsize = (15, 15)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(alphas, e_alphas, 'b-')
ax.plot(alphas, e_alphas_r, 'g--')
ax.set_ylim(min(e_alphas),max(e_alphas))
ax.set_xlim(min(alphas),max(alphas))
ax.set_xlabel("alpha")
plt.show()

Nếu bạn chạy mã này nhiều lần, nó mang lại kết quả cực kỳ khác nhau cho alpha:

>>> 
the minimum value of error is  3.99254192539
 the minimizer is  1.52587890625e-05
>>> ================================ RESTART ================================
>>> 
the minimum value of error is  4.07412455842
 the minimizer is  6.45622425334
>>> ================================ RESTART ================================
>>> 
the minimum value of error is  4.25898253597
 the minimizer is  1.52587890625e-05
>>> ================================ RESTART ================================
>>> 
the minimum value of error is  3.79392968781
 the minimizer is  28.8971008254
>>> 

Tại sao giá trị alpha không hội tụ đúng? Tôi biết rằng dữ liệu của tôi là tổng hợp, nhưng phân phối là như nhau. Ngoài ra, các biến thể là rất nhỏ trong x1x2.

Điều gì có thể gây ra điều này là không ổn định?

Điều tương tự được viết bằng R cho kết quả khác nhau - nó luôn trả về giá trị cao nhất có thể cho alpha là "tối ưu_alpha".

Tôi cũng đã viết điều này trong R, nó cho tôi một câu trả lời hơi khác, mà tôi không biết tại sao?

library(glmnet)
library(lars)
library(pracma)

set.seed(1)
k = 2 # number of features selected 

n = 1000

x1x2corr = 1.1
x1 = seq(n) + rnorm(n, 0, 1) + 50
x2 =  x1*x1x2corr + rnorm(n, 0, 2) + 500
y = x1 + x2 

filter_out_label <- function(col) {col!="y"}

alphas = logspace(-5, 6, 100)

for (alpha in alphas){
  k = 10
  optimal_alpha = NULL
  folds <- cut(seq(1, nrow(df)), breaks=k, labels=FALSE)
  total_mse = 0
  min_mse = 10000000
  for(i in 1:k){
    # Segement your data by fold using the which() function
    testIndexes <- which(folds==i, arr.ind=TRUE)
    testData <- df[testIndexes, ]
    trainData <- df[-testIndexes, ]

    fit <- lars(as.matrix(trainData[Filter(filter_out_label, names(df))]),
                trainData$y,
                type="lasso")
    # predict
    y_preds <- predict(fit, as.matrix(testData[Filter(filter_out_label, names(df))]),
                       s=alpha, type="fit", mode="lambda")$fit # default mode="step"

    y_true = testData$y
    residuals = (y_true - y_preds)
    mse=sum(residuals^2)
    total_mse = total_mse + mse
  }
  if (total_mse < min_mse){
    min_mse = total_mse
    optimal_alpha = alpha
  }
}

print(paste("the optimal alpha is ", optimal_alpha))

Đầu ra từ mã R ở trên là:

> source('~.....')
[1] "the optimal alpha is  1e+06"

Trên thực tế, bất kể tôi đặt gì cho dòng " alphas = logspace(-5, 6, 100)", tôi luôn nhận được giá trị cao nhất cho alpha.

Tôi đoán thực sự có 2 câu hỏi khác nhau ở đây:

  1. Tại sao giá trị alpha không ổn định cho phiên bản được viết bằng Python?

  2. Tại sao phiên bản viết bằng R cho tôi một kết quả khác? (Tôi nhận ra rằng logspacehàm này khác Rvới python, nhưng phiên bản được viết bằng Rluôn mang lại cho tôi giá trị lớn nhất alphacho giá trị alpha tối ưu, trong khi phiên bản python thì không).

Thật tuyệt khi biết những điều này ...


2
Không chắc đây có phải là nguyên nhân gây ra sự cố không, nhưng mô hình Lasso của scikit-learn (khi bạn đang gọi nó) yêu cầu dữ liệu phải được căn giữa, điều này không giống như bạn đang làm. Bạn phải trừ giá trị trung bình của x và y trên tập huấn luyện, sau đó trừ các giá trị tương tự này khỏi tập kiểm tra (không căn giữa dữ liệu trước khi xác thực chéo hoặc căn giữa tập kiểm tra bằng giá trị trung bình của chính nó!). Một cách khác là sử dụng fit_intercepttham số khi bạn xây dựng mô hình Lasso.
dùng20160

Tôi không thể tưởng tượng điều này ảnh hưởng đến sự bất ổn, nhưng tôi có thể thử nó ...
Candic3

3
(1) Trong tập lệnh Python, bạn đang tạo một số dữ liệu ngẫu nhiên mỗi lần, phải không? Tại sao bạn mong đợi rằng tham số chính quy tối ưu sẽ giống nhau cho tất cả các lần rút ngẫu nhiên của bạn? Dữ liệu khác nhau có thể có các tham số chính quy tối ưu khác nhau. (2) Tập lệnh R sử dụng dữ liệu nào? Theo nghĩa nào thì kết quả từ tập lệnh R khác với Python? Bạn không cung cấp bất kỳ đầu ra hoặc so sánh.
amip

1
Tôi nghĩ rằng câu hỏi hầu như không có chủ đề ở đây vì nó liên quan đến mã đọc bằng chứng là một phần thiết yếu của bài tập. Có lẽ một số kết quả "lạ" chỉ đơn giản là do lỗi mã hóa? Nhưng câu hỏi là thú vị nói chung. Ngoài ra, alpha là gì? Ví dụ, tôi đã quen vớiλ là cường độ hình phạt trong LASSO hoặc hồi quy sườn và sau đó αlà trọng lượng của LASSO so với sườn trong hồi quy mạng đàn hồi. Alpha của bạn có tương ứng với tôi khôngλ?
Richard Hardy

1
Ngoài ra, sự khác biệt giữa Python và R có thực sự phù hợp với câu hỏi chính của bạn về tính không ổn định của alpha tối ưu không? Bằng cách bao gồm sự so sánh giữa Python và R, bạn sẽ đưa ra thêm sự phức tạp và các vấn đề mới, và do đó phần nào che giấu bản chất của câu hỏi, IMHO. Sự khác biệt giữa các triển khai LASSO trong Python và R có lẽ nên được đặt ra như một câu hỏi riêng biệt.
Richard Hardy

Câu trả lời:


14

Tôi không biết nhiều về python, nhưng tôi đã tìm thấy một vấn đề với mã R của bạn.

Bạn có 2 dòng:

residuals = sum(y_true - y_preds)
mse=residuals^2

Mà tính tổng số dư, sau đó bình phương chúng. Điều này rất khác với bình phương số dư, sau đó tổng hợp chúng (có vẻ như mã python thực hiện chính xác). Tôi nghi ngờ rằng đây có thể là một phần lớn của sự khác biệt giữa mã R và mã python. Sửa mã R và chạy lại để xem nó có hoạt động giống mã python hơn không.

Tôi cũng sẽ đề nghị thay vì chỉ lưu alpha "tốt nhất" và mse tương ứng mà bạn lưu trữ tất cả chúng và vẽ mối quan hệ. Có thể là đối với thiết lập của bạn, có một khu vực khá bằng phẳng do đó sự khác biệt giữa mse ở các điểm khác nhau không lớn lắm. Nếu đây là trường hợp, thì những thay đổi rất nhỏ đối với dữ liệu (ngay cả thứ tự trong xác thực chéo) có thể thay đổi điểm nào, trong số nhiều điểm cơ bản giống nhau, đưa ra mức tối thiểu. Có một tình huống dẫn đến một vùng phẳng xung quanh tối ưu thường sẽ dẫn đến những gì bạn đang thấy và âm mưu của tất cả các giá trị alpha với các giá trị mse tương ứng có thể được khai sáng.


Nhận xét đầu tiên của bạn là một bắt tuyệt vời - cảm ơn bạn. Vấn đề vẫn còn tồn tại sau khi tôi sửa lỗi đó. Hãy để tôi thử đề nghị thứ hai của bạn.
Candic3

@ Candic3 đây là một gợi ý tuyệt vời. Ngoài ra, vì cả hai thuật toán đều mang tính xác định, nếu bạn sửa hạt giống sẽ có thể tái tạo đường dẫn giải pháp góc nhỏ nhất chính xác với phiên bản DIY của bạn.
Shadowtalker

Cả hai sẽ tạo ra cùng một đường dẫn giải pháp chỉ khi kích thước bước hoàn toàn giống nhau. Ngoài ra, sklearnphiên bản có xác nhận chéo tích hợp, như @JennyLu đã chỉ ra, do đó, nó sẽ tạo ra một lỗi hơi khác một chút.
Candic3

6

sklearn có một ví dụ gần giống với những gì bạn đang cố gắng thực hiện ở đây: http://scikit-learn.org/urdy/auto_examples/exercises/plot_cv_dpat.html

Thật vậy, ví dụ này cho thấy rằng bạn nhận được các kết quả khác nhau cho alpha cho mỗi trong ba lần thực hiện trong ví dụ đó. Điều này có nghĩa là bạn không thể tin tưởng vào việc lựa chọn alpha vì rõ ràng nó phụ thuộc rất nhiều vào phần dữ liệu bạn đang sử dụng để đào tạo và chọn alpha.

Tôi không nghĩ bạn nên nghĩ về xác nhận chéo là thứ gì đó sẽ 'hội tụ' để cho bạn một câu trả lời hoàn hảo. Thật ra, tôi nghĩ rằng về mặt khái niệm nó gần như ngược lại với sự hội tụ. Bạn đang tách dữ liệu của mình và cho mỗi lần gấp bạn sẽ đi theo một 'hướng riêng biệt'. Thực tế là bạn nhận được các kết quả khác nhau tùy thuộc vào cách bạn phân vùng dữ liệu kiểm tra và đào tạo của bạn sẽ cho bạn biết rằng việc hội tụ một kết quả hoàn hảo là không thể - và cũng không mong muốn. Cách duy nhất bạn sẽ nhận được một giá trị alpha nhất quán mọi lúc là nếu bạn sử dụng tất cả dữ liệu của mình để đào tạo. Tuy nhiên, nếu bạn làm điều này, bạn sẽ nhận được kết quả học tập tốt nhất nhưng kết quả xác nhận tồi tệ nhất.


1
Nhận xét của bạn về xác thực x rất thú vị - Tôi không hoàn toàn làm theo. Tôi nghĩ rằng xác thực x sẽ được sử dụng để chọn một siêu tham số. Nếu xác thực x không hội tụ, vậy bạn sẽ sử dụng gì để chọn một siêu tham số?
Candic3

Trong sklearnví dụ bạn đã trích dẫn trên plot_cv_dzheim, nó có quá ít điểm dữ liệu (150) đến mức tôi không thể tin được rằngαSẽ không ổn định nếu chỉ dựa vào ví dụ đó.
Candic3

Đây thực sự là một cách tốt đẹp để xác nhận chéo. @ Candic3 nếu nó không hội tụ, bạn thử thứ khác. Điều đó giống như tôi nói với bạn rằng bạn không thể lái xe qua hồ, và sau đó bạn phàn nàn "nhưng tôi cần phải vượt qua!" Tìm một cây cầu, hoặc đi xung quanh
Shadowtalker

@ Candic3 Tôi đã chạy nó một cách nhanh chóng với tất cả dữ liệu từ bộ dữ liệu bệnh tiểu đường (438 điểm) và đây là các kết quả: [gấp 0] alpha: 0,00010, điểm: 0,50126 [lần 1] alpha: 0,10405, điểm: 0,48495 [lần 2] alpha: 0,04520, điểm: 0,5032
Jenny Lu

1
@JennyLu Cách tôi hiểu k folds cross-validationvà (cách tôi đã làm trong ví dụ trên) giá trị củaαnên giống nhau cho tất cả các nếp gấp. Giá trị của bất kỳ tham số nào bạn ước tính (lỗi, điểm hoặcR2, MSE, v.v.), là những gì nên thay đổi giữa các nếp gấp. Bởi vì, k folds cross-validationvề cơ bản là cố gắng tính giá trị trung bình có điều kiện của tham số bạn ước tính (ước tính). Vì vậy, tôi không nghĩ rằng giá trị củaαnên được thay đổi giữa các nếp gấp.
Candic3

5

Sự đa cộng tuyến trong x1x2là điều tạo nênαgiá trị không ổn định trong mã Python. Phương sai rất nhỏ đối với các phân phối tạo ra các biến này, do đó phương sai của các hệ số bị thổi phồng. Yếu tố lạm phát phương sai (VIF) có thể được tính toán để minh họa điều này. Sau khi phương sai được tăng từ

x1 = range(n) + norm.rvs(0, 1, n) + 50
x2 =  map(lambda aval: aval*x1x2corr, x1) + norm.rvs(0, 2, n) + 500

....đến....

x1 = range(n) + norm.rvs(0, 100, n) + 50
x2 =  map(lambda aval: aval*x1x2corr, x1) + norm.rvs(0, 200, n) + 500

sau đó α giá trị ổn định.

Vấn đề với Rmã khác với mã Python vẫn còn là một bí ẩn tuy nhiên ...


Cảm ơn bạn - đó là nó. Hãy để tôi khám phá sự khác biệt giữa RPythonmột chút nữa.
Candic3

@ Candic3 vì họ sử dụng các triển khai khác nhau, có các chế độ thất bại khác nhau trong các vấn đề không có điều kiện. Nếu bạn đọc tài liệu, Python lasso sử dụng gốc tọa độ, mà bạn đang so sánh với một giải pháp LAR trong R
Shadowtalker

2

Tôi sẽ bình luận về mã R:

Bạn đang đặt lại các biến ở những vị trí sai, nghĩa là các biến min_msenên được khởi tạo Infở bên ngoài forvòng lặp và optimal_alphanên được khởi tạo như NULLở đó. Điều này trở thành:

library(glmnet)
library(lars)
library(pracma)

set.seed(1)
k = 2 # number of features selected 

n = 100

x1x2corr = 1.1
x1 = seq(n) + rnorm(n, 0, 1) + 50
x2 =  x1*x1x2corr + rnorm(n, 0, 2) + 500
y = x1 + x2 +rnorm(n,0,0.5)
df = data.frame(x1 = x1, x2 = x2, y = y)
filter_out_label <- function(col) {col!="y"}

alphas = logspace(-5, 6, 50)

###
# INITIALIZE here before loop
###
min_mse = Inf
optimal_alpha = NULL
# Let's store the mse values for good measure
my_mse = c()

for (alpha in alphas){
  k = 10
  folds <- cut(seq(1, nrow(df)), breaks=k, labels=FALSE)
  # DO NOT INITIALIZE min_mse and optimal_alpha here, 
  # then you cannot find them...
  total_mse = 0
  for(i in 1:k){
    # Segement your data by fold using the which() function
    testIndexes <- which(folds==i, arr.ind=TRUE)
    testData <- df[testIndexes, ]
    trainData <- df[-testIndexes, ]

    fit <- lars(as.matrix(trainData[Filter(filter_out_label, names(df))]),
                trainData$y,
                type="lasso")
    # predict
    y_preds <- predict(fit, as.matrix(testData[Filter(filter_out_label,
                       names(df))]),
                       s=alpha, type="fit", mode="lambda")$fit 

    y_true = testData$y
    residuals = (y_true - y_preds)
    mse=sum(residuals^2)
    total_mse = total_mse + mse
  }
  # Let's store the MSE to see the effect
  my_mse <- c(my_mse, total_mse)
  if (total_mse < min_mse){
    min_mse = total_mse
    optimal_alpha = alpha
    # Let's observe the output
    print(min_mse)
  }
}

print(paste("the optimal alpha is ", optimal_alpha))
# Plot the effect of MSE with varying alphas
plot(my_mse)

Đầu ra bây giờ phải luôn là các giá trị alpha nhỏ nhất, bởi vì có các thông số mạnh trong các yếu tố dự đoán và phản hồi chỉ được xây dựng từ các yếu tố dự đoán có sẵn, tức là không có biến dự phòng nào mà chúng tôi muốn LASSO đặt về 0, trong trường hợp này chúng tôi muốn không muốn thực hiện chính quy, tức là nhỏ nhất alphanên là tốt nhất. Bạn có thể thấy tác dụng của MSE tại đây:

ảnh hưởng đến mse

Lưu ý rằng tôi đang sử dụng 50 bảng chữ cái trên cùng một tỷ lệ với bạn. Xung quanh alpha được lập chỉ mục 35 cả hai biến được giảm xuống 0, có nghĩa là mô hình luôn luôn làm điều tương tự và mse bị đình trệ.

Một vấn đề tốt hơn để nghiên cứu MSE, CV và LASSO

Vấn đề trên không thú vị lắm đối với LASSO. LASSO thực hiện lựa chọn mô hình, vì vậy chúng tôi muốn thấy nó thực sự chọn ra các tham số quan tâm. Điều ấn tượng hơn khi thấy rằng mô hình thực sự đang chọn ra một bản alpha thực sự làm giảm MSE, tức là cho chúng ta dự đoán tốt hơn bằng cách đưa ra một số biến. Dưới đây là một ví dụ tốt hơn, nơi tôi thêm một loạt các dự đoán dự phòng.

set.seed(1)
k = 100 # number of features selected 

n = 100

x1x2corr = 1.1
x1 = seq(n) + rnorm(n, 0, 1) + 50
x2 =  x1*x1x2corr + rnorm(n, 0, 2) + 500
# Rest of the variables are just noise
x3 = matrix(rnorm(k-2,0,(k-2)*n),n,k-2)
y = x1 + x2 +rnorm(n,0,0.5)
df = data.frame(x1 = x1, x2 = x2, y = y)
df <- cbind(df,x3)
filter_out_label <- function(col) {col!="y"}

alphas = logspace(-5, 1.5, 100)
min_mse = Inf
optimal_alpha = NULL
my_mse = c()

Sau đó, bạn chỉ cần chạy vòng lặp for như trong đoạn mã trên! Lưu ý rằng tôi đặt tối đa alphasxuống 1,5 từ 6, chỉ để xem hiệu ứng trong cốt truyện bên dưới. Bây giờ alphagiá trị tốt nhất không phải là giá trị thấp nhất, nhưng bạn có thể thấy trong cốt truyện rằng MSE xác thực chéo đang giảm và cuối cùng lại tăng vọt. Điểm thấp nhất trên biểu đồ đó, tương ứng với chỉ số alpha có lỗi CV thấp nhất.

Vấn đề CV tốt hơn cho LASSO

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.