In R, how does cv.glmnet (or glmnet) scale the test data when using the predict function?

Viewed 162

In the cv.glmnet function, there is an option to automatically standardize the data. If you select this, how does the predict function scale the test data?

Example:

cvob1 = cv.glmnet(x_train, y, standardize = TRUE)
# Note standardize = TRUE is the default option and just added here for illustration
predict(cvob1, newx = x_test, s = "lambda.min")

In normal train test analysis, you fit the scaler to the train data and then use it to transform both the train and test sets. Does glmnet do the same? Or does it use the parameters from the test set (newx in the predict function) to scale the test set?

# Python code - does the R package do the same under the hood?
scaler = StandardScaler()
scaler.fit(train)
scaler.transform(train)
scaler.transform(test)

Thanks for any help!

1 Answers

Yes, glmnet basically does the same, but in a different way. The help function for glmnet says about standardize:

The coefficients are always returned on the original scale.

This is equivalent to scaling the test data the same way as the train data. You can make a quick test:

library(glmnet)
#> Loading required package: Matrix
#> Loaded glmnet 4.1

set.seed(4)
train_data <- matrix(rnorm(100 * 10, mean = 1.5, sd = 1.3),
                     nrow = 100, ncol = 10)

means <- apply(train_data, 2, mean)
sds <- apply(train_data, 2, sd)

outcome <- train_data %*% matrix(c(0.5, -1, 0, 2, 0, 0, 3, 2.5, -2, 0), ncol = 1) +
  rnorm(100)

train_data_scaled <- train_data
for (i in seq_len(ncol(train_data))) {
  train_data_scaled[, i] <- (train_data_scaled[, i] - means[i]) / sds[i]
}

test_data <- matrix(rnorm(100 * 10, mean = 1.5, sd = 1.3),
                    nrow = 100, ncol = 10)

test_data_scaled <- test_data
for (i in seq_len(ncol(train_data))) {
  test_data_scaled[, i] <- (test_data_scaled[, i] - means[i]) / sds[i]
}
set.seed(4)
glmnet_res <- cv.glmnet(train_data, outcome)
set.seed(4)
glmnet_res_prescaled <- cv.glmnet(train_data_scaled, outcome, standardize = FALSE)

test_1 <- predict(glmnet_res, newx = test_data, s = "lambda.1se")
test_2 <- predict(glmnet_res_prescaled, newx = test_data_scaled, s = "lambda.1se")
all.equal(test_1, test_2)
#> [1] TRUE

Created on 2022-01-31 by the reprex package (v1.0.0)

Related