R: Zastavení Smyčky Při splnění Podmínky

0

Otázka

Já jsem pracoval s R programovací jazyk. Vytvořil jsem následující smyčky, která vygeneruje 1000 náhodných čísel - a pak opakuje tento proces 10 krát:

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)

Otázka: chtěl bych změnit tuto smyčku tak, že namísto generování 1000 náhodných čísel, udržuje generování náhodných čísel až do určitého podmínka je splněna, například: aby generování náhodných čísel AŽ d_i$a > 10 A d_i$b > 10.

Pomocí "WHILE()" prohlášení, snažil jsem se udělat toto:

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ém: to Však vrátí následující varování (10 krát):

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

A produkuje prázdná tabulka:

> results_df

data frame with 0 columns and 0 rows

Může mi někdo prosím, pomozte mi vyřešit tento problém?

Díky!!!

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

Nejlepší odpověď

3

Chybové zprávy v původním příspěvku, jsou vzhledem k tomu, že d_i$a a d_i$b jsou vektory s 1000 prvky a 10 je skalární veličina. Proto, R porovná první prvek v d_i$a a první prvek v d_i$b 10.

Chcete-li vyřešit chybovou zprávu, musíme porovnat vektor s délkou 1 skalární 10. To vyžaduje restrukturalizaci kódu pro generování náhodných čísel jeden po druhém. Z popisu v původní příspěvek, není jasné, zda toto chování bylo úmyslné.

Budu problém zjednodušit tím, že odstraní sada 10 replikací pro ilustraci, jak vytvořit datový rámec s náhodnými čísly, dokud řadě má i a a b hodnoty větší než 10.

Za prvé, jsme se nastavit semeno, aby odpověď reprodukovatelné, a pak inicializovat některé objekty. Nastavením a a b 0 ujišťujeme, že while() smyčky bude provádět alespoň jednou.

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 

S inicializován a a b, while() smyčky se vyhodnotí na TRUE generuje dvě náhodná čísla, přiřadí hodnota indexu, a zapíše je jako datový rámec na results seznam. Logika pro while() loop znamená, že pokud buď a je méně než nebo se rovná 10 nebo b je méně než nebo se rovná 10, smyčka drží iterace. To se zastaví, když oba a a b jsou větší než 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
}

Smyčky zastaví provádění po deváté iterace jak můžeme vidět v tisku výsledný datový rámec poté, co jsme kombinovat jednotlivé řádky s do.call() a rbind().

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

...a výstup:

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

Všimněte si, že poslední řádek v datové rám má hodnoty větší než 10 pro oba a a b.

Více replikací, zatímco smyčka

Proces opakovat 10 krát jako je tomu v původní příspěvek, končíme provoz v for() smyčky, a přidat druhý seznam, combined_results chcete-li uložit výsledky z každé iteraci.

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

...a výstupu pro první 4 iterací vnější smyčky:

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

Opět jsme na vědomí, že poslední řádek v každé iteraci (9, 18, 19, a 21) mají hodnoty větší než 10 pro oba a a b.

Všimněte si, že tento přístup nedokáže využít vectorized operace v R, což znamená, že namísto generování z 1000 náhodných čísel s každé volání rnorm()kód založený na while() generuje jeden náhodné číslo, na volání rnorm(). Od rnorm() je náročná funkce, kód, který minimalizuje počet časy rnorm() provádí je žádoucí.

2021-11-24 20:45:06
2

Doufám, že tyto připomínky pomohou sledovat, jak to funguje. To především využívá repeat což je prostě nekonečná smyčka. To může být zastaven pomocí break klíčové slovo.

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

Vymanit se ze smyčky (while nebo for), jednoduše na break() po if stavu.

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

Vypukne smyčky. Z ?break: ovládání je převedena do prvního prohlášení mimo vnitřní smyčky.

Nicméně, z vaší otázky není zcela jasné, proč se snažíte to - takové řízení toku nemusí být vhodné řešení, jako vectorized řešení by mohlo existovat. Dále, dejte si pozor na dělat zbytečné věci uvnitř smyčky - to je častou příčinou pro pomalý běh kódu. Zde můžeme vzít nějaké věci z pro-smyčky, např. d_i$iteration a d_i$indexa ještě skončit se stejným výsledkem. Podívejte se na Třetí Kruh.

2021-11-23 23:46:14

V jiných jazycích

Tato stránka je v jiných jazycích

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