R: Bir Koşul Karşılandığında Döngüyü Durdurma

0

Soru

R programlama dili ile çalışıyorum. 1000 rasgele sayı üreten aşağıdaki döngüyü oluşturdum - ve sonra bu işlemi 10 kez tekrarladım:

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)

Soru: Bu döngüyü, yalnızca 1000 rasgele sayı üretmek yerine, belirli bir koşul karşılanana kadar rasgele sayılar üretmeye devam edecek şekilde değiştirmek istiyorum, örneğin: d_i$a > 10 VE d_i$b >> 10'A KADAR rasgele sayılar üretmeye devam edin.

Bir "WHİLE()" ifadesi kullanarak bunu yapmaya çalıştım:

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)

Sorun: Ancak, bu aşağıdaki uyarıları döndürür (10 kez):

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

Ve boş bir tablo üretir:

> results_df

data frame with 0 columns and 0 rows

Lütfen birisi bana bu sorunu çözmeye yardımcı olabilir?

Teşekkürler!

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

En iyi cevabı

3

Orijinal gönderideki hata iletileri şu nedenlerden kaynaklanmaktadır: d_i$a ve d_i$b 1000 elemanlı vektörlerdir ve 10 bir skalerdir. Bu nedenle, R ilk öğeyi karşılaştırır d_i$a ve içindeki ilk unsur d_i$b 10 ile.

Hata mesajını çözmek için uzunluğu 1 olan bir vektörü skaler 10 ile karşılaştırmamız gerekir. Bu, rasgele sayıları birer birer oluşturmak için kodun yeniden yapılandırılmasını gerektirir. Orijinal yazıdaki açıklamadan, bu davranışın kasıtlı olup olmadığı açık değildir.

Bir satır her ikisine de sahip olana kadar rasgele sayılarla bir veri çerçevesinin nasıl oluşturulacağını göstermek için 10 çoğaltma kümesini ortadan kaldırarak sorunu basitleştireceğim a ve b 10'dan büyük değerlerle.

İlk olarak, cevabı tekrarlanabilir hale getirmek için bir tohum belirledik ve sonra bazı nesneleri başlattık. Ayarlayarak a ve b 0 sağlamak while() döngü en az bir kez yürütülür.

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 

Başlatılmış olması a ve b, bu while() döngü şu şekilde değerlendirilir TRUE iki rasgele sayı üretir, bir dizin değeri atar ve bunları bir veri çerçevesi olarak yazar. results liste. İçin mantık while() ya bu döngü gösterir a 10'dan küçük veya eşittir veya b 10'dan küçük veya eşittir, döngü yinelemeye devam eder. Her ikisi de durduğunda durur a ve b 10'dan büyük.

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
}

Döngü, tek tek satırları birleştirdikten sonra elde edilen veri çerçevesini yazdırarak görebildiğimiz gibi dokuzuncu yinelemeden sonra yürütmeyi durdurur do.call() ve rbind().

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

...ve çıktı:

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

Veri çerçevesindeki son satırın her ikisi için de 10'dan büyük değerlere sahip olduğuna dikkat edin a ve b.

While döngüsünün birden çok çoğaltması

İşlemi orijinal gönderide olduğu gibi 10 kez tekrarlamak için işlemi bir for() döngü yapın ve ikinci bir liste ekleyin, combined_results her yinelemenin sonuçlarını kaydetmek için.

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

...ve dış döngünün ilk 4 yinelemesi için çıktı:

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

Yine, her yinelemedeki son satırın (9, 18, 19 ve 21) her ikisi için de 10'dan büyük değerlere sahip olduğunu not ediyoruz a ve b.

Bu yaklaşımın, R'deki vektörleştirilmiş işlemlerden yararlanamadığını, yani her aramada 1.000 rasgele sayı üretmek yerine rnorm(), kod dayalı bir while() arama başına tek bir rasgele sayı üretir rnorm(). Dan beri rnorm() kaynak yoğun bir işlevdir, kod sayısını en aza indirir rnorm() yürütmek arzu edilir.

2021-11-24 20:45:06
2

Umarım bu yorumlar nasıl çalıştığını takip etmeye yardımcı olur. Esas olarak aşağıdakileri kullanır repeat bu sadece sonsuz bir döngüdür. Bu kullanarak durdurulabilir break kelime.

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

Bir döngüden çıkmak için (while veya for), sadece bir break() bir sonra if koşul.

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

Bir döngüden kopacak. -den ?break: denetim, en iç döngü dışındaki ilk deyime aktarılır.

Bununla birlikte, sorunuzdan neden bunu denediğiniz tam olarak belli değil - vektörize bir çözüm mevcut olabileceğinden, böyle bir kontrol akışı uygun çözüm olmayabilir. Ayrıca, bir döngü içinde gereksiz şeyler yapmaya dikkat edin-yavaş çalışan kodun yaygın bir nedenidir. Ve burada bir şeylerin dışında bir şeyler götürmek gibi yapabiliriz d_i$iteration ve d_i$index ve yine de aynı sonuçla sonuçlanır. Üçüncü Daireye bir bak.

2021-11-23 23:46:14

Diğer dillerde

Bu sayfa diğer dillerde

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