R: l'Arrêt d'une Boucle Lorsqu'une Condition est remplie

0

La question

Je travaille avec le R langage de programmation. J'ai créé la boucle suivante, qui génère de 1000 nombres aléatoires - et puis répète ce processus 10 fois:

results <- list()

for (i in 1:10){

a = rnorm(1000,10,1)
b = rnorm(1000,10,1)


d_i = data.frame(a,b)
d_i$index = 1:nrow(d_i)
d_i$iteration = as.factor(i)

 results[[i]] <- d_i

}



results_df <- do.call(rbind.data.frame, results)

Question: je voudrais changer cette boucle telle que, au lieu de ne créer de 1000 nombres aléatoires, il garde la génération de nombres aléatoires jusqu'à ce qu'une certaine condition est remplie, par exemple: GARDER la génération de nombres aléatoires JUSQU'à ce que d_i$a > 10 ET d_i$b > 10.

À l'aide d'un "WHILE()" déclaration, j'ai essayé de faire ceci:

results <- list()

for (i in 1:10){

 while (d_i$a > 10 & d_i$b >10) {

a = rnorm(1000,10,1)
b = rnorm(1000,10,1)


d_i = data.frame(a,b)
d_i$index = 1:nrow(d_i)
d_i$iteration = as.factor(i)

 results[[i]] <- d_i

}

}


results_df <- do.call(rbind.data.frame, results)

Problème: Toutefois, il renvoie les avertissements suivants (10 fois):

Warning messages:
1: In while (d_i$a > 10 & d_i$b > 10) { :
  the condition has length > 1 and only the first element will be used

Et produit une table vide:

> results_df

data frame with 0 columns and 0 rows

Quelqu'un peut-il svp m'aider à résoudre ce problème?

Merci!

data-manipulation loops r while-loop
2021-11-23 23:09:34
3

La meilleure réponse

3

Les messages d'erreur dans le post original sont dues au fait que d_i$a et d_i$b sont des vecteurs de 1 000 éléments et 10 est un scalaire. Par conséquent, R compare le premier élément d_i$a et le premier élément d_i$b avec 10.

Pour résoudre le message d'erreur nous avons besoin de comparer un vecteur de longueur 1 à l'scalaire 10. Cela nécessite la restructuration du code pour générer des nombres aléatoires, un à un. À partir de la description dans le post original, il est difficile de savoir si ce comportement est intentionnel.

Je vais simplifier le problème en éliminant la série de 10 répétitions pour illustrer comment créer un bloc de données avec des nombres aléatoires jusqu'à ce qu'une ligne a la fois a et b avec des valeurs supérieures à 10.

Tout d'abord, nous avons mis une graine pour faire la réponse reproductible, puis initialiser certains objets. Par la mise en a et b 0 nous assurer que le while() la boucle sera exécutée au moins une fois.

set.seed(950141238) # for reproducibility 
results <- list()
a <- 0 # initialize a to a number < 10
b <- 0 # initialize b to a number < 10 
i <- 1 # set a counter 

Après avoir initialisé a et ble while() boucle évalue à TRUE génère deux nombres aléatoires, assigne une valeur de l'index, et les écrit comme un bloc de données à la results liste. La logique de la while() boucle indique que, si a est inférieure ou égale à 10 ou b est inférieur ou égal à 10, la boucle continue de l'itération. Il s'arrête quand les deux a et b sont plus grands que 10.

while(a <= 10 | b <= 10){
     a <- rnorm(1,10,1) # generate 1 random number with mean of 10 and sd of 1
     b <- rnorm(1,10,1) # ditto
     results[[i]] <- data.frame(index = i,a,b)
     i <- i + 1 # increment i
}

La boucle s'arrête l'exécution, après le neuvième itération comme on peut le voir par l'impression des données qui en résultent image, après que nous combinons les lignes individuelles avec do.call() et rbind().

df <- do.call(rbind,results)
df

...et la sortie:

> df
  index         a         b
1     1  8.682442  8.846653
2     2  9.204682  8.501692
3     3  8.886819 10.488972
4     4 11.264142  8.952981
5     5  9.900112 10.918042
6     6  9.185120 10.625667
7     7  9.620793 10.316724
8     8 11.718397  9.256835
9     9 10.034793 11.634023
>

Notez que la dernière ligne du bloc de données présente des valeurs supérieures à 10 pour les deux a et b.

Plusieurs répétitions de la boucle while

Répéter le processus 10 fois comme cela se fait dans le post original, de terminer l'opération en for() boucle, et ajouter une deuxième liste, combined_results pour enregistrer les résultats de chaque itération.

set.seed(950141238) # for reproducibility 
combined_results <- list()
for(iteration in 1:10){
     results <- list()
     a <- 0 # initialize a to a number < 10
     b <- 0 # initialize b to a number < 10 
     i <- 1 # set a counter 
     while((a < 10) | (b < 10)){
          a <- rnorm(1,10,1) # generate 1 random number with mean of 10 and sd of 1
          b <- rnorm(1,10,1) # ditto
          results[[i]] <- data.frame(iteration,index = i,a,b)
          i <- i + 1 # increment i
     }
     combined_results[[iteration]] <- do.call(rbind,results)
}
df <- do.call(rbind,combined_results)
df[df$iteration < 5,] 

...et la sortie pour les 4 premières itérations de la boucle externe:

> df[df$iteration < 5,]
   iteration index         a         b
1          1     1  8.682442  8.846653
2          1     2  9.204682  8.501692
3          1     3  8.886819 10.488972
4          1     4 11.264142  8.952981
5          1     5  9.900112 10.918042
6          1     6  9.185120 10.625667
7          1     7  9.620793 10.316724
8          1     8 11.718397  9.256835
9          1     9 10.034793 11.634023
10         2     1 11.634331  9.746453
11         2     2  9.195410  7.665265
12         2     3 11.323344  8.279968
13         2     4  9.617224 11.792142
14         2     5  9.360307 11.166162
15         2     6  7.963320 11.325801
16         2     7  8.022093  8.568503
17         2     8 10.440788  9.026129
18         2     9 10.841408 10.033346
19         3     1 11.618665 10.179793
20         4     1 10.975061  9.503309
21         4     2 10.209288 12.409656
> 

De nouveau, nous constatons que la dernière ligne de chaque itération (9, 18, 19, et 21) ont des valeurs supérieures à 10 pour les deux a et b.

Notez que cette approche ne parvient pas à profiter de vectorisé opérations dans R, ce qui signifie qu'au lieu de générer de 1000 nombres aléatoires à chaque appel à rnorm()le code basé sur une while() génère un seul nombre aléatoire par appel à rnorm(). Depuis rnorm() est une exploitation intensive des ressources de la fonction, le code qui minimise le nombre de fois rnorm() exécute est souhaitable.

2021-11-24 20:45:06
2

J'espère que ces commentaires nous aideront à suivre la façon dont il fonctionne. Il a principalement fait usage de repeat qui est juste une boucle infinie. Il peut être arrêté à l'aide de la break mot-clé.

results <- list()


for (i in 1:10){
  
  # do until break
  repeat {
    
    # repeat many random numbers
    a = rnorm(1000,10,1)
    b = rnorm(1000,10,1)
    
    # does any pair meet the requirement
    if (any(a > 10 & b > 10)) {
      
      # put it in a data.frame
      d_i = data.frame(a,b)
      
      # end repeat
      break
    }
  }
  
  # select all rows until the first time the requirement is met
  # it must be met, otherwise the loop would not have ended
  d_i <- d_i[1:which(d_i$a > 10 & d_i$b > 10)[1], ]
  
  # prep other variables
  d_i$index = seq_len(nrow(d_i))
  d_i$iteration = as.factor(i)
  
  results[[i]] <- d_i
  
}
2021-11-24 01:19:52
2

Pour sortir d'une boucle (while ou for), tout simplement dans un break() après un if condition.

out <- vector("integer", 26)
for (i in seq_along(letters)) {
  if(letters[i] == "t") break()
  out[i] <- i+1
}
out
#> [1]  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20  0  0  0  0  0  0  0

Va sortir de la boucle. À partir de ?break: le contrôle est transféré à la première déclaration de l'extérieur à l'intérieur de la plupart de la boucle.

Cependant, à partir de votre question, il n'est pas tout à fait clair pourquoi vous essayez cette - ces flux de contrôle pourrait ne pas être la solution appropriée, comme un vectorisé solution pourrait exister. De plus, méfiez-vous de faire inutile de choses à l'intérieur d'une boucle, il est une cause commune de la lenteur de l'exécution de code. Ici, nous pouvons prendre certaines choses hors de la boucle for, comme d_i$iteration et d_i$indexet toujours le même résultat. Jetez un oeil à la Troisième Cercle.

2021-11-23 23:46:14

Dans d'autres langues

Cette page est dans d'autres langues

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................