Gibt es eine Möglichkeit, die Kreuzvalidierung zu verwenden, um eine Variablen- / Merkmalsauswahl in R durchzuführen?

10

Ich habe einen Datensatz mit ungefähr 70 Variablen, die ich reduzieren möchte. Ich möchte den Lebenslauf verwenden, um die nützlichsten Variablen auf folgende Weise zu finden.

1) Wählen Sie zufällig etwa 20 Variablen aus.

2) Verwenden Sie stepwise/ LASSO/ lars/ etc, um die wichtigsten Variablen auszuwählen.

3) Wiederholen Sie ~ 50x und sehen Sie, welche Variablen am häufigsten ausgewählt (nicht eliminiert) werden.

Dies entspricht dem, was ein randomForesttun würde, aber das rfVarSelPaket scheint nur für Faktoren / Klassifizierung zu funktionieren, und ich muss eine kontinuierliche abhängige Variable vorhersagen.

Ich benutze R, damit alle Vorschläge dort idealerweise umgesetzt werden.

screechOwl
quelle
Sind alle Funktionen wichtig? Wie viele Proben haben Sie? Wenn ich das Problem richtig verstehe, können Sie versuchen, eine Variante des Boostings durchzuführen. Wählen Sie wiederholt eine Teilmenge der Samples aus, passen Sie alle Variablen an und sehen Sie, welche häufiger auftauchen.
Ofelia
1
Ich denke, es ist unwahrscheinlich, dass sich Ihr Verfahren gegenüber dem LASSO verbessert, dessen Implementierungen in R (z. B. glmnet und bestraft) standardmäßig eine Kreuzvalidierung verwenden, um den "optimalen" Regularisierungsparameter zu finden. Eine Sache, die Sie in Betracht ziehen könnten, ist die mehrmalige Wiederholung der LASSO-Suche nach diesem Parameter, um mit der potenziell großen Varianz der Kreuzvalidierung (wiederholter Lebenslauf) fertig zu werden. Natürlich kann kein Algorithmus Ihr fachspezifisches Vorwissen übertreffen.
Miura

Antworten:

9

Ich glaube, was Sie beschreiben, ist bereits im caretPaket implementiert . Schauen Sie sich die rfeFunktion oder die Vignette hier an: http://cran.r-project.org/web/packages/caret/vignettes/caretSelection.pdf

Warum müssen Sie nun die Anzahl der Funktionen reduzieren? Von 70 auf 20 ist nicht wirklich eine Größenordnung Abnahme. Ich würde denken, dass Sie mehr als 70 Funktionen benötigen würden, bevor Sie fest davon überzeugt wären, dass einige der Funktionen wirklich und wirklich keine Rolle spielen. Aber hier kommt wohl ein subjektiver Prior ins Spiel.

Shea Parkes
quelle
5

Es gibt keinen Grund, warum die Häufigkeit der Variablenauswahl Informationen liefert, die Sie nicht bereits aus der offensichtlichen Bedeutung der Variablen im ursprünglichen Modell erhalten. Dies ist im Wesentlichen eine Wiederholung von anfänglicher statistischer Signifikanz. Sie fügen auch eine neue Ebene der Willkür hinzu, wenn Sie versuchen, einen Grenzwert für die Auswahlhäufigkeit festzulegen. Die Auswahl der Resampling-Variablen wird zusätzlich zu den anderen Problemen durch Kollinearität stark beschädigt.

Frank Harrell
quelle
2

Ich habe meine Antwort von heute früher überarbeitet. Ich habe jetzt einige Beispieldaten generiert, auf denen der Code ausgeführt werden soll. Andere haben zu Recht vorgeschlagen, dass Sie die Verwendung des Caret-Pakets prüfen, dem ich zustimme. In einigen Fällen kann es jedoch erforderlich sein, eigenen Code zu schreiben. Im Folgenden habe ich versucht zu demonstrieren, wie die sample () - Funktion in R verwendet wird, um Beobachtungen zufällig Kreuzvalidierungsfalten zuzuweisen. Ich verwende auch for-Schleifen, um eine variable Vorauswahl (unter Verwendung einer univariaten linearen Regression mit einem milden p-Wert-Cutoff von 0,1) und eine Modellbildung (unter Verwendung einer schrittweisen Regression) für die zehn Trainingssätze durchzuführen. Sie können dann Ihren eigenen Code schreiben, um die resultierenden Modelle auf die Validierungsfalten anzuwenden. Hoffe das hilft!

################################################################################
## 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.
################################################################################

Bevor Sie eine Kreuzvalidierung durchführen, ist es wichtig, dass Sie sich über die ordnungsgemäße Verwendung informieren. Diese beiden Referenzen bieten hervorragende Diskussionen zur Kreuzvalidierung:

  1. Simon RM, Subramanian J., Li MC, Menezes S. Verwenden der Kreuzvalidierung zur Bewertung der Vorhersagegenauigkeit von Überlebensrisikoklassifikatoren auf der Grundlage hochdimensionaler Daten. Kurze Bioinform. 2011 May; 12 (3): 203 & ndash; 14. Epub 2011 Feb 15. http://bib.oxfordjournals.org/content/12/3/203.long
  2. Richard Simon, Michael D. Radmacher, Kevin Dobbin und Lisa M. McShane. Fallstricke bei der Verwendung von DNA-Microarray-Daten für die diagnostische und prognostische Klassifizierung. JNCI J Natl Cancer Inst (2003) 95 (1): 14 & ndash; 18. http://jnci.oxfordjournals.org/content/95/1/14.long

Diese Artikel richten sich an Biostatistiker, wären aber für jeden nützlich.

Denken Sie auch immer daran, dass die schrittweise Regression gefährlich ist (obwohl die Verwendung der Kreuzvalidierung zur Verringerung der Überanpassung beitragen sollte). Eine gute Diskussion der schrittweisen Regression finden Sie hier: http://www.stata.com/support/faqs/stat/stepwise.html .

Lassen Sie mich wissen, wenn Sie weitere Fragen haben!

Alexander
quelle
0

Ich habe hier gerade etwas Schönes gefunden: http://cran.r-project.org/web/packages/Causata/vignettes/Causata-vignette.pdf

Versuchen Sie dies möglicherweise, wenn Sie das glmnet-Paket verwenden

# 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
quelle