web-dev-qa-db-fra.com

R répéter la fonction jusqu'à ce que la condition soit remplie

J'essaie de générer un échantillon aléatoire qui exclut certaines "mauvaises données". Je ne sais pas si les données sont "mauvaises" avant de les avoir échantillonnées. Ainsi, je dois faire un tirage au sort de la population, puis le tester. Si les données sont "bonnes", conservez-les. Si les données sont "mauvaises", dessinez-en une autre au hasard et testez-la. Je voudrais le faire jusqu'à ce que ma taille d'échantillon atteigne 25. Ci-dessous est un exemple simplifié de ma tentative d'écrire une fonction qui fait cela. Quelqu'un peut-il me dire ce qui me manque?

df <- data.frame(NAME=c(rep('Frank',10),rep('Mary',10)), SCORE=rnorm(20))
df

random.sample <- function(x) {
  x <- df[sample(nrow(df), 1), ]
  if (x$SCORE > 0) return(x)
 #if (x$SCORE <= 0) run the function again
}

random.sample(df)
15
user1491868

Voici une utilisation générale d'une boucle while:

random.sample <- function(x) {
  success <- FALSE
  while (!success) {
    # do something
    i <- sample(nrow(df), 1)
    x <- df[sample(nrow(df), 1), ]
    # check for success
    success <- x$SCORE > 0
  }
  return(x)
}

Une alternative consiste à utiliser repeat (sucre syntaxique pour while(TRUE)) et break:

random.sample <- function(x) {
  repeat {
    # do something
    i <- sample(nrow(df), 1)
    x <- df[sample(nrow(df), 1), ]
    # exit if the condition is met
    if (x$SCORE > 0) break
  }
  return(x)
}

break vous fait quitter le bloc repeat. Vous pouvez également avoir if (x$SCORE > 0) return(x) pour quitter directement la fonction.

18
flodel

utilisez-le après votre premier échantillon

while (any(bad <- (x$SCORE <= 0)))
   x[bad, ] <- df[sample(nrow(df), sum(bad)), ]
3
Ricardo Saporta
 random.sample <- function(x) {
   x <- df[sample(nrow(df), 1), ]
   if (x$SCORE > 0) return(x)
   Recall(x)# run the function again
 }

 random.sample(df)
#   NAME    SCORE
#14 Mary 1.252566

Il me semble que cela devrait aussi fonctionner:

 df$SCORE[ df$SCORE > 0 ][ sample(1:sum(df$SCORE > 0), 1) ]
#[1] 0.6579631
3
42-

Vous pouvez simplement sélectionner les lignes à échantillonner directement ainsi (seulement 5):

> df <- data.frame(NAME=c(rep('Frank',10),rep('Mary',10)), SCORE=rnorm(20))
> df[sample(which(df$SCORE>0), 5),]


 NAME     SCORE
14  Mary 1.0858854
10 Frank 0.7037989
16  Mary 0.7688913
5  Frank 0.2067499
17  Mary 0.4391216

c'est sans remplacement, pour bootstrap mettre dans replace=T.

2
Stephen Henderson