My goal is to identify the best n-feature linear model, i.e. pick the model with only n-feature from total N features (n < N) and lowest Mean-Squared-Error (MSE). The experiment is on the Lasso and Ridge regression from sklearn.liner_model. I thought Lasso will do a better job as it tends to eliminate redundant variables, but it turns out to be the opposite in the following experiment.
Here is what I did:
- Generated some data where the dependent variable is a linear combination of a bunch of other variables, i.e. $Y = 0.1X_5 + 0.2X_6 + 0.3X_7 + 0.4X_8 + 0.5X_9$, and $X_1$ to $X_4$ are correlated to $Y$.
df = pd.DataFrame(np.random.randint(0, 100, size = [100, 10]))
df.columns = ['X' + str(i) for i in range(1, df.shape[1])] + ['Y']
df['Y'] = (df[['X' + str(i) for i in [5, 6, 7, 8, 9]]] * [0.1, 0.2, 0.3, 0.4, 0.5]).sum(axis = 1)
df['X1'] = 0.5 * df.Y + np.random.randn(df.shape[0])
df['X2'] = 0.6 * df.Y + np.random.randn(df.shape[0])
df['X3'] = 0.7 * df.Y + np.random.randn(df.shape[0])
df['X4'] = 0.8 * df.Y + np.random.randn(df.shape[0])
X, y = df.drop(columns='Y'), df.Y
- Use Lasso and Ridge model to select best 5 features based on importance weights. For Lasso and Ridge, I believe SelectFromModel function uses the absolute values of coefficients as importance weights.
# Lasso model selection
las_model = SelectFromModel(estimator = Lasso(), max_features = 5).fit(X, y)
print("Lasso Model")
print(pd.DataFrame({'feature':df.columns[:-1],
'coef' :abs(las_model.estimator_.coef_)}).sort_values('coef',ascending=False)[:5].sort_index())
print("R-squared = " + str(sm.OLS(df.Y, sm.add_constant(las_model.transform(X))).fit().rsquared.round(2)))
Lasso missed X5 but got X4 and the coefficients are off by a big margin:
Lasso Model
feature coef
3 X4 0.327149
5 X6 0.129456
6 X7 0.197254
7 X8 0.262760
8 X9 0.328964
R-squared = 1.0
# Ridge model selection
rid_model = SelectFromModel(estimator = Ridge(), max_features = 5).fit(X, y)
print("Ridge Model")
print(pd.DataFrame({'feature':df.columns[:-1],
'coef' :abs(rid_model.estimator_.coef_)}).sort_values('coef',ascending=False)[:5].sort_index())
print("R-squared = " + str(sm.OLS(df.Y, sm.add_constant(rid_model.transform(X))).fit().rsquared.round(2)))
Ridge model shows decent results:
Ridge Model
feature coef
4 X5 0.098881
5 X6 0.197748
6 X7 0.296673
7 X8 0.395516
8 X9 0.494395
R-squared = 0.98
Note that the defualt alpha for both Lasso and Ridge in Sklearn are 1. Lowering alpha for Lasso doesn't seem to help. In an extreme case, when setting alpha = 0, the result is still not correct.
Lasso Model
feature coef
3 X4 0.199773
5 X6 0.160934
6 X7 0.243271
7 X8 0.323027
8 X9 0.404394
On the other hand, Ridge model results are surprisingly robust across a range of alphas, from 0 to 10, as well as data of different scales.
My questions are:
- why Ridge regression is so robust in selecting the best n-feature model while Lasso isn't?
- Is Ridge regression always more robust in this kind task? If not, under what condition Lasso will outperform?