R: Oprirea o Buclă atunci Când o Condiție este Îndeplinită

0

Problema

Eu lucrez cu R limbaj de programare. Am creat următoarea buclă care generează 1000 de numere aleatoare - și apoi repetă acest proces de 10 ori:

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)

Întrebare: aș dori să schimbe această buclă, astfel încât în loc de doar generatoare de 1000 de numere aleatoare, se păstrează generarea de numere aleatoare până când o anumită condiție este îndeplinită, de exemplu: PĂSTRAȚI-generarea de numere aleatoare PÂNĂ d_i$a > 10 ȘI d_i$b > 10.

Folosind o "în TIMP ce()" declarație, am încercat pentru a face acest lucru:

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)

Problema: cu toate Acestea, acest returnează următoarele avertismente (de 10 ori):

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

Și produce un tabel gol:

> results_df

data frame with 0 columns and 0 rows

Poate cineva să mă ajute rezolva această problemă?

Multumesc!!!

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

Cel mai bun răspuns

3

Mesajele de eroare, în original post se datorează faptului că d_i$a și d_i$b sunt vectori cu 1.000 de elemente și 10 este un scalar. Prin urmare, R compară primul element din d_i$a și primul element din d_i$b cu 10.

Pentru a rezolva mesaj de eroare de care avem nevoie pentru a compara un vector cu lungimea de 1 scalar 10. Acest lucru necesită restructurarea cod pentru a genera numere aleatoare la un moment dat. Din descrierea din postul original, nu este clar dacă acest comportament a fost intenționată.

Voi simplifica problema prin eliminarea set de 10 replici pentru a ilustra cum de a crea un cadru de date cu numere aleatoare până când un rând are ambele a și b cu valori mai mari decât 10.

În primul rând, ne-am stabilit o sămânță pentru a face răspunsul reproductibile, și apoi a inițializa unele obiecte. Prin stabilirea a și b la 0 asigurăm că while() bucla se va executa cel puțin o dată.

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 

Având inițializat a și b, la while() bucla se evaluează la TRUE generează două numere aleatoare, atribuie o valoare index, și le scrie ca un cadru de date la results lista. Logica pentru while() bucla indică faptul că dacă a este mai mică sau egală cu 10 sau b este mai mică sau egală cu 10, buclă continuă iterarea. Se oprește atunci când ambele a și b sunt mai mari decât 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
}

Bucla se oprește de executare după nouă repetare după cum putem vedea de imprimare rezultat cadru de date după ce ne-am combina rânduri individuale cu do.call() și rbind().

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

...și la ieșire:

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

Observați că ultimul rând, în cadru de date are valori mai mari decât 10 pentru ambele a și b.

Mai multe replici de buclă în timp ce

Pentru a repeta procesul de 10 ori cum se face în original post, vom încheia operațiunea într-un for() buclă, și se adaugă o a doua listă, combined_results pentru a salva rezultatele de la fiecare iterație.

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,] 

...și de ieșire pentru primele 4 iterații a buclei exterioare:

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

Din nou observăm că ultimul rând, în fiecare iterație (9, 18, 19 și 21) au valori mai mari decât 10 pentru ambele a și b.

Rețineți că această abordare nu reușește să profite de vectorized operațiuni în R, în sensul că în loc de a genera 1.000 de numere aleatoare cu fiecare apel pentru a rnorm(), codul bazat pe o while() generează un singur număr aleator pe sunați pentru a rnorm(). Deoarece rnorm() este o resursă intensivă funcția, codul care minimizează numărul de ori rnorm() execută este de dorit.

2021-11-24 20:45:06
2

Sper ca aceste comentarii ajuta pentru a urmări cum funcționează. În principal face uz de repeat care este doar o buclă infinită. Acesta poate fi oprit folosind break cuvinte cheie.

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

Pentru a rupe o buclă (de timp sau pentru), pur și simplu, la o break() după o if condiție.

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 rupe dintr-o bucla. Din ?break: controlul este transferat la prima declarație în afara interioară-mai curent.

Cu toate acestea, la intrebarea ta nu este foarte clar de ce sunteți încercarea de acest lucru - astfel fluxul de control nu ar putea fi soluția potrivită, ca un vectorized soluție ar putea exista. Mai mult, feriți-vă de a face lucruri inutile în interiorul unei bucle - aceasta este o cauza comuna pentru care rulează lent cod. Aici putem lua unele lucruri pentru a-buclă, cum ar fi d_i$iteration și d_i$indexsi mai termina cu același rezultat. Avea o privire la cel de-al Treilea Cerc.

2021-11-23 23:46:14

În alte limbi

Această pagină este în alte limbi

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