Existe uma maneira de usar a validação cruzada para fazer a seleção de variáveis ​​/ recursos no R?

10

Eu tenho um conjunto de dados com cerca de 70 variáveis ​​que eu gostaria de reduzir. O que estou procurando fazer é usar o CV para encontrar as variáveis ​​mais úteis da seguinte maneira.

1) Selecione aleatoriamente digamos 20 variáveis.

2) Use stepwise/ LASSO/ lars/ etc para escolher as variáveis ​​mais importantes.

3) Repita ~ 50x e veja quais variáveis ​​são selecionadas (não eliminadas) com mais freqüência.

Isso é parecido com o que um randomForestfaria, mas o rfVarSelpacote parece funcionar apenas para fatores / classificação e eu preciso prever uma variável dependente contínua.

Eu estou usando R, então qualquer sugestão seria idealmente implementada lá.

Coruja
fonte
Todos os recursos são importantes? Quantas amostras você tem? Se eu entendi o problema corretamente, você pode tentar fazer alguma variante de reforço - selecione repetidamente subconjunto de amostras e ajuste todas as variáveis ​​a elas e veja quais aparecem com mais frequência.
Ofelia
11
Acho que é improvável que seu procedimento melhore no LASSO, cujas implementações em R (por exemplo, glmnet e penalizadas) empregam por padrão a validação cruzada para encontrar o parâmetro "ideal" de regularização. Uma coisa que você pode considerar é repetir a pesquisa do LASSO várias vezes para lidar com a variação potencialmente grande da validação cruzada (CV repetido). Obviamente, nenhum algoritmo pode superar o seu conhecimento prévio específico da matéria.
Miura

Respostas:

9

Eu acredito que o que você descreve já está implementado no caretpacote. Veja a rfefunção ou a vinheta aqui: http://cran.r-project.org/web/packages/caret/vignettes/caretSelection.pdf

Agora, tendo dito isso, por que você precisa reduzir o número de recursos? De 70 a 20 não é realmente uma ordem de magnitude decrescente. Eu acho que você precisaria de mais de 70 recursos antes de ter uma firme convicção de que alguns deles realmente e verdadeiramente não importam. Mas, novamente, é aí que entra um prior subjetivo, suponho.

Shea Parkes
fonte
5

Não há razão para que a frequência de seleção de variáveis ​​forneça informações que você ainda não obtém da aparente importância das variáveis ​​no modelo inicial. Isso é essencialmente uma repetição da significância estatística inicial. você também está adicionando um novo nível de arbitrariedade ao tentar decidir um ponto de corte para a frequência de seleção. A seleção de reamostragem de variáveis ​​está seriamente danificada pela colinearidade, além de outros problemas.

Frank Harrell
fonte
2

Revisei minha resposta hoje cedo. Agora eu gerei alguns dados de exemplo nos quais executar o código. Outros sugeriram, com razão, que você use o pacote de intercalação, com o qual eu concordo. Em alguns casos, no entanto, você pode achar necessário escrever seu próprio código. Abaixo, tentei demonstrar como usar a função sample () em R para atribuir observações aleatoriamente às dobras de validação cruzada. Também uso loops para executar pré-seleção variável (usando regressão linear univariada com um valor de corte branda de 0,1) e construção de modelo (usando regressão stepwise) nos dez conjuntos de treinamento. Em seguida, você pode escrever seu próprio código para aplicar os modelos resultantes às dobras de validação. Espero que isto ajude!

################################################################################
## Load the MASS library, which contains the "stepAIC" function for performing
## stepwise regression, to be used later in this script
library(MASS)
################################################################################


################################################################################
## Generate example data, with 100 observations (rows), 70 variables (columns 1
## to 70), and a continuous dependent variable (column 71)
Data <- NULL
Data <- as.data.frame(Data)

for (i in 1:71) {
for (j in 1:100) {
Data[j,i]  <- rnorm(1) }}

names(Data)[71] <- "Dependent"
################################################################################


################################################################################
## Create ten folds for cross-validation. Each observation in your data will
## randomly be assigned to one of ten folds.
Data$Fold <- sample(c(rep(1:10,10)))

## Each fold will have the same number of observations assigned to it. You can
## double check this by typing the following:
table(Data$Fold)

## Note: If you were to have 105 observations instead of 100, you could instead
## write: Data$Fold <- sample(c(rep(1:10,10),rep(1:5,1)))
################################################################################


################################################################################
## I like to use a "for loop" for cross-validation. Here, prior to beginning my
## "for loop", I will define the variables I plan to use in it. You have to do
## this first or R will give you an error code.
fit <- NULL
stepw <- NULL
training <- NULL
testing <- NULL
Preselection <- NULL
Selected <- NULL
variables <- NULL
################################################################################


################################################################################
## Now we can begin the ten-fold cross validation. First, we open the "for loop"
for (CV in 1:10) {

## Now we define your training and testing folds. I like to store these data in
## a list, so at the end of the script, if I want to, I can go back and look at
## the observations in each individual fold
training[[CV]] <- Data[which(Data$Fold != CV),]
testing[[CV]]  <- Data[which(Data$Fold == CV),]

## We can preselect variables by analyzing each variable separately using
## univariate linear regression and then ranking them by p value. First we will
## define the container object to which we plan to output these data.
Preselection[[CV]] <- as.data.frame(Preselection[CV])

## Now we will run a separate linear regression for each of our 70 variables.
## We will store the variable name and the coefficient p value in our object
## called "Preselection".
for (i in 1:70) {
Preselection[[CV]][i,1]  <- i
Preselection[[CV]][i,2]  <- summary(lm(Dependent ~ training[[CV]][,i] , data = training[[CV]]))$coefficients[2,4]
}

## Now we will remove "i" and also we will name the columns of our new object.
rm(i)
names(Preselection[[CV]]) <- c("Variable", "pValue")

## Now we will make note of those variables whose p values were less than 0.1.
Selected[[CV]] <- Preselection[[CV]][which(Preselection[[CV]]$pValue <= 0.1),] ; row.names(Selected[[CV]]) <- NULL

## Fit a model using the pre-selected variables to the training fold
## First we must save the variable names as a character string
temp <- NULL
for (k in 1:(as.numeric(length(Selected[[CV]]$Variable)))) {
temp[k] <- paste("training[[CV]]$V",Selected[[CV]]$Variable[k]," + ",sep="")}
variables[[CV]] <- paste(temp, collapse = "")
variables[[CV]] <- substr(variables[[CV]],1,(nchar(variables[[CV]])-3))

## Now we can use this string as the independent variables list in our model
y <- training[[CV]][,"Dependent"]
form <- as.formula(paste("y ~", variables[[CV]]))

## We can build a model using all of the pre-selected variables
fit[[CV]] <- lm(form, training[[CV]])

## Then we can build new models using stepwise removal of these variables using
## the MASS package
stepw[[CV]] <- stepAIC(fit[[CV]], direction="both")

## End for loop
}

## Now you have your ten training and validation sets saved as training[[CV]]
## and testing[[CV]]. You also have results from your univariate pre-selection
## analyses saved as Preselection[[CV]]. Those variables that had p values less
## than 0.1 are saved in Selected[[CV]]. Models built using these variables are
## saved in fit[[CV]]. Reduced versions of these models (by stepwise selection)
## are saved in stepw[[CV]].

## Now you might consider using the predict.lm function from the stats package
## to apply your ten models to their corresponding validation folds. You then
## could look at the performance of the ten models and average their performance
## statistics together to get an overall idea of how well your data predict the
## outcome.
################################################################################

Antes de executar a validação cruzada, é importante que você leia sobre o uso adequado. Essas duas referências oferecem excelentes discussões sobre validação cruzada:

  1. Simon RM, Subramanian J, Li MC, Menezes S. Usando validação cruzada para avaliar a precisão preditiva dos classificadores de risco de sobrevivência com base em dados de alta dimensão. Breve Bioinform. 2011 maio; 12 (3): 203-14. Epub 2011 15 de fevereiro. Http://bib.oxfordjournals.org/content/12/3/203.long
  2. Richard Simon, Michael D. Radmacher, Kevin Dobbin e Lisa M. McShane. Armadilhas no Uso de Dados de Microarray de DNA para Classificação Diagnóstica e Prognóstica. JNCI J Natl Cancer Inst (2003) 95 (1): 14-18. http://jnci.oxfordjournals.org/content/95/1/14.long

Esses documentos são voltados para bioestatísticos, mas seriam úteis para qualquer pessoa.

Além disso, lembre-se de que o uso da regressão passo a passo é perigoso (embora o uso da validação cruzada deva ajudar a aliviar o ajuste excessivo). Uma boa discussão sobre regressão gradual está disponível aqui: http://www.stata.com/support/faqs/stat/stepwise.html .

Deixe-me saber se você tiver quaisquer perguntas adicionais!

Alexander
fonte
0

Acabei de encontrar algo legal por aqui: http://cran.r-project.org/web/packages/Causata/vignettes/Causata-vignette.pdf

Tente isso talvez ao usar o pacote glmnet

# extract nonzero coefficients
coefs.all <- as.matrix(coef(cv.glmnet.obj, s="lambda.min"))
idx <- as.vector(abs(coefs.all) > 0)
coefs.nonzero <- as.matrix(coefs.all[idx])
rownames(coefs.nonzero) <- rownames(coefs.all)[idx]
Simon Nehls
fonte