R’da İlk Adımlar – 3

R’da İlk Adımlar serisinin son yazısından selamlar.

Önceki derste fonksiyonlarla beraber if-else if-else koşullu ifadelerini görmüştük. Bu derste ise döngüleri göreceğiz. Döngüler isminde de anlaşılacağı üzere tekrarlı işlemlerdir.

for döngüsü:

for(i in 1:10){
  print("for döngüsü çalıştı")
}

[1] "for döngüsü çalıştı"
[1] "for döngüsü çalıştı"
[1] "for döngüsü çalıştı"
[1] "for döngüsü çalıştı"
[1] "for döngüsü çalıştı"
[1] "for döngüsü çalıştı"
[1] "for döngüsü çalıştı"
[1] "for döngüsü çalıştı"
[1] "for döngüsü çalıştı"
[1] "for döngüsü çalıştı"

Yukarıdaki örnekte, belirlediğimiz bir değişken (i) verdiğimiz bir aralıkta (1:10) içeriye yazılan komutu (print(“for döngüsü çalıştı”)) tekrarladı. Yani, bu işlemi 10 defa yaptı. Hepsi bu kadar.

for döngüsü kullanılırken çoğunlukla i değişkeni kullanılır fakat bu zorunlu değildir.

for(herhangi_bir_degisken in 1:10){
  print("for döngüsü çalıştı")
}

[1] "for döngüsü çalıştı"
[1] "for döngüsü çalıştı"
[1] "for döngüsü çalıştı"
[1] "for döngüsü çalıştı"
[1] "for döngüsü çalıştı"
[1] "for döngüsü çalıştı"
[1] "for döngüsü çalıştı"
[1] "for döngüsü çalıştı"
[1] "for döngüsü çalıştı"
[1] "for döngüsü çalıştı"

Gördüğünüz gibi i yerine herhangi_bir_degisken yazdık, yine çalıştı.

Aralığı vektör olarak da verebiliriz.

for(k in c("R","Python","Diğer")){
  print(k)
}

[1] "R"
[1] "Python"
[1] "Diğer"

Ya da daha önce oluşturulmuş bir objeyi çalıştırabiliriz.

diller <- c("R","Python","Diğer")

for(j in diller){
  print(j)
}

[1] "R"
[1] "Python"
[1] "Diğer"

Görüldüğü üzere mantığı oldukça basittir. Her bir değer, sırası ile değişkene atanır ve komut her bir değer için çalıştırılır. Bunu görmek için şöyle de yazabiliriz:

alfabe <- LETTERS[1:3]

for(i in 1:3){
  print(paste0("Alfabenin ",i,". harfi: ",alfabe[i]))
}

[1] "Alfabenin 1. harfi: A"
[1] "Alfabenin 2. harfi: B"
[1] "Alfabenin 3. harfi: C"

alfabe diye bir objemiz var. Atadığımız i değişkenini 1’den 3’e kadar çalıştırmak istedik ve şunu yaptık:

#paste0("Alfabenin ",i,". harfi: ",alfabe[i])

i değişkeni sırasıyla 1, 2 ve 3 değerlerini aldı ve sonuna da alfabe objesindeki i. elementi yazdı.

for(i in 1:3){
  print(i)
}

[1] 1
[1] 2
[1] 3

for(i in 1:3){
  print(alfabe[i])
}

[1] "A"
[1] "B"
[1] "C"

Aslında yukarıdaki iki farklı döngüpaste0() ile süsledik.

for döngüsü iç içe de yazılabilir.

for(i in 1:3){
  for(j in 1:5){
    print(paste0("i:",i," j:",j))
  }
}

[1] "i:1 j:1"
[1] "i:1 j:2"
[1] "i:1 j:3"
[1] "i:1 j:4"
[1] "i:1 j:5"
[1] "i:2 j:1"
[1] "i:2 j:2"
[1] "i:2 j:3"
[1] "i:2 j:4"
[1] "i:2 j:5"
[1] "i:3 j:1"
[1] "i:3 j:2"
[1] "i:3 j:3"
[1] "i:3 j:4"
[1] "i:3 j:5"

Önce içerideki döngüyü bitirdiğine dikkat edin. i = 1 değerini aldıktan sonra içeride 1’den 5’e kadar tekrar yaptı. Yani, 1-1, 1-2, 1-3, 1-4, 1-5. İçerideki döngü bittikten sonra i bu defa 2 değerini aldı ve aynı düzen devam etti. 2-1, 2-2, 2-3, 2-4, 2-5…

for döngüsünün içine if-else if-else koşullu ifadelerini de koyabiliriz.

for(sayi in 1:10){
  if(sayi %% 2 == 0){
    print(paste0(sayi," bir çift sayıdır."))
  }
}

[1] "2 bir çift sayıdır."
[1] "4 bir çift sayıdır."
[1] "6 bir çift sayıdır."
[1] "8 bir çift sayıdır."
[1] "10 bir çift sayıdır."

sayi değişkeni 1 ile 10 arasındaki bütün değerleri aldı fakat biz bir koşul belirterek sadece çift sayıları yazdırmasını istedik. Çift sayı olup olmadığını da mod (%%) ile belirledik. Örneğin, 8 mod 2 sonucu 0’a eşitse çift sayıdır.

for döngüsüne next ve break kontrol yapılarını ekleyebiliriz. next ile bir sonraki döngüye geçilir; break ile döngü sonlandırılır. Bir örnek ile çok kolay anlayacağız.

harfler <- c("A","B","C","Ç","D","E","F","G","Ğ","H","I")

harfler adında bir objemiz var ve iki tane Türkçe karakter içeriyor. Bu harfleri yazdıralım fakat Türkçe karakter görürse onu geçsin.

for(harf in harfler){
  if(harf %in% c("Ç","Ğ")){
    next
  }
  print(harf)
}

[1] "A"
[1] "B"
[1] "C"
[1] "D"
[1] "E"
[1] "F"
[1] "G"
[1] "H"
[1] "I"

harf değişkeni harfler objesindeki tüm elementleri temsil ediyor. harf değişkeni Ç ve Ğ’ye denk geldiğinde bu harfleri yazdırmadı. next‘i kaldırdığımızda tüm harfleri yazdıracaktır.

Şimdi de herhangi bir Türkçe karaktere denk gelirse döngüyü sonlandırmasını isteyelim.

for(harf in harfler){
  if(harf %in% c("Ç","Ğ")){
    break
  }
  print(harf)
}

[1] "A"
[1] "B"
[1] "C"

Gördüğünüz gibi A, B ve C’yi yazdırdı ama Ç’ye denk geldiği için döngüyü sonlandırdı.

while döngüsü:

Bu döngü TRUE oldukça çalışır.

x <- 0

while(x < 10){
  print(x)
  x = x + 1
}

[1] 0
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9

x‘e ilk olarak sıfır değerini atadık ve while döngüsü ile x 10’dan küçük oldukça çalışmasını istedik. İçeride de her defasında x‘i yazdırdık ve 1 arttırdık.

Döngülerle çalışırken içinde kalmamaya dikkat edin; yoksa sonsuz döngüleriniz olur.

Aşağıdaki yapıdan tek kurtuluşunuz: Esc

x <- 0

while(TRUE){
  
  print("Çalışıyor...")
  
  x = x + 1
  
  print(x)
  
}

#içine örnek olarak şu koşul eklenebilir:

if(x == 10){
    break
  }

Diğer diller de dahil olmak üzere R’da da en çok kullandığım iki döngüyü anlatmış oldum. R’da ara ara faydalandığım ve aslında önerilen apply ailesidir. Apply ailesi döngülere olan ihtiyacınızı minimize eder. Bu yazıda ailenin üyelerinden olan üç fonksiyondan kısaca bahsedeceğim: apply(), lapply(), sapply().

apply():

Özellikle veri çerçevesi ile çalışacağımız için bu yapı üzerinde anlatacağım. Aynı zamanda matris ve dizilerle de çalışabilir bir fonksiyondur.

Her üç sütunu da random sayılardan oluşan 5 satırlı bir veri çerçevesi oluşturalım. Random olduğu için sizde bu sayılar; dolayısıyla sonuçlar değişebilir.

random1 <- sample(x = 1:100, size = 5)
random2 <- sample(x = 1:100, size = 5)
random3 <- sample(x = 1:100, size = 5)

df <- data.frame(
  sutun1 = random1,
  sutun2 = random2,
  sutun3 = random3
)

Her bir satırın (1) ortalaması:

apply(X = df, MARGIN = 1, FUN = mean)

[1] 73.33333 54.33333 42.66667 49.66667 74.66667

Her bir sütunun (2) ortalaması:

apply(X = df, MARGIN = 2, FUN = mean)

sutun1 sutun2 sutun3
  50.6   44.4   81.8

apply() fonksiyonunun içine hangi veri çerçevesi ile çalışılacağı, satırda mı sütunda mı işlem yapılacağı, hangi fonksiyonun uygulanacağı bilgilerini sırası ile verdik.

Yeri gelmişken bunu rowMeans() ve colMeans() fonksiyonlarının da yaptığını görelim.

rowMeans(x = df)

[1] 73.33333 54.33333 42.66667 49.66667 74.66667

colMeans(x = df)

sutun1 sutun2 sutun3
  50.6   44.4   81.8

lapply():

Listeler üzerinde çalıştığımız zaman kullanabileceğimiz bir fonksiyondur.

liste <- list(
  sutun1 = random1,
  sutun2 = random2,
  sutun3 = random3
)
lapply(X = liste, FUN = mean)

$sutun1
[1] 50.6

$sutun2
[1] 44.4

$sutun3
[1] 81.8

sapply():

Listeler üzerine sapply() fonksiyonu da kullanılabilir ve lapply()‘a göre çıktıları daha basit verir.

sapply(X = liste, FUN = mean)

sutun1 sutun2 sutun3
  50.6   44.4   81.8

lapply() fonkisyonu ile bu çıktıyı listeden çıkararak alabilirdik.

unlist(lapply(X = liste, FUN = mean))

sutun1 sutun2 sutun3
  50.6   44.4   81.8

Döngüler söz konusu olduğu zaman başta da dediğim gibi diğer dillerden de olan alışkanlıkla for, while gibi seçenekleri tercih ediyorum fakat bazı zamanlar apply ailesine de başvurabiliyorum. Bunların dışında da seçeneklerimiz olacak fakat onları gelecek yazılarda göreceğiz. Sonunda neyi kullanmak istediğinize yine siz karar vereceksiniz.

Yazıyı bir oyun ile bitirelim. Bu oyunda bilgisayarın belirlediği sayıyı tahmin etmeye çalışalım.

Kullanıcı q‘ya basmadığı sürece oyun devam etsin. Bu, bize while döngüsünü hatırlatıyor: TRUE oldukça çalış.

while(TRUE){
  
  girdi <- readline(prompt = "Bir sayı girin: ") #readline'ı hatırladınız mı?
  
  if(girdi == "q"){
    break
  } else {
    print("Döngü çalışıyor")
  }
  
}

1-100 arasında bir sayı girin: q

q‘ya basmadığınız sürece döngü çalışmaya devam edecektir ve her çalıştığında console‘da “Döngü çalışıyor” yazdığını göreceksiniz.

Şimdi makine 1 ile 100 arasında bir sayı üretsin ve bunu yazdırsın.

while(TRUE){
  
  makine <- sample(x = 1:100, size = 1)
  
  girdi <- readline(prompt = "1-100 arasında bir sayı girin: ")
  
  if(girdi == "q"){
    break
  } else {
    print(paste0("Döngü çalışıyor. Üretilen sayı: ",makine))
  }
  
}

1-100 arasında bir sayı girin: q

Bu defa biz her sayı girdiğimizde o da bize farklı bir sayı veriyor. Oyunun daha güzel devam etmesi için makine bir sayıyı sabitlemeli. İleride göreceğimiz set.seed()‘i başına koyabiliriz. Bu her defasında aynı random’ı verir.

while(TRUE){
  
  set.seed(123) #içine istediğiniz sayıyı yazabilirsiniz.
  makine <- sample(x = 1:100, size = 1)
  
  girdi <- readline(prompt = "1-100 arasında bir sayı girin: ")
  
  if(girdi == "q"){
    break
  } else {
    print(paste0("Döngü çalışıyor. Üretilen sayı: ",makine))
  }
  
}

1-100 arasında bir sayı girin: q

Biraz daha geliştirelim. Makine bizim girdiğimiz sayıya göre çık ya da in şeklinde yönlendirme yapsın. Bu durumda else‘den sonra print()‘i kaldırabiliriz ve oraya bir if-else if koşullu ifade yazabiliriz.

while(TRUE){
  
  set.seed(123)
  makine <- sample(x = 1:100, size = 1)
  
  girdi <- readline(prompt = "1-100 arasında bir sayı girin: ")
  
  if(girdi == "q"){
    break
  } else {
    if(as.numeric(girdi) > makine){
      print("İn")
    } else if(as.numeric(girdi) < makine){
      print("Çık")
    } else if(as.numeric(girdi) == makine){
      print("Bildin!")
    }
  }
  
}

1-100 arasında bir sayı girin: q

Kullanıcı q‘ya basarsa döngü sonlandırılır.

set.seed(123) sabit olduğu için kullanıcı her bildikten sonra makine hep aynı sayıyı üretecek. Bundan kurtulabiliriz. Böylece aslında set.seed() ve içindeki değerin de ne anlama geldiği kavranmış olundu.

Eğer girdi makineden büyükse “İn”; küçükse “Çık”; eşitse “Bildin!” basar ekrana.

Eğer q dışında sayı girilmezse döngü hata alıp çıkacaktır. Hatayı yakalamak, uyarı vermek ve hataya rağmen döngünün sonlandırılmaması için tryCatch() kullanabiliriz.

rnd <- 123

while(TRUE){
  
  set.seed(rnd)
  makine <- sample(x = 1:100, size = 1)
  
  girdi <- readline(prompt = "1-100 arasında bir sayı girin: ")
  
  if(girdi == "q"){
    break
  } else {
    if(as.numeric(girdi) > makine){
      print("İn")
    } else if(as.numeric(girdi) < makine){
      print("Çık")
    } else if(as.numeric(girdi) == makine){
      rnd <- sample(x = 1:1000, size = 1)
      print("Bildin!")
    }
  }
  
}

1-100 arasında bir sayı girin: q

rnd diye bir skaler oluşturduk ve bunu 123 ile başlattık. Ardından set.seed()‘in içine rnd‘yi koyduk. Kullanıcı her bildiğinde rnd yenilecek ve makine de yeni bir sayı üretecek. Peki, rnd nerede yenilecek? Son else if blokunda şunu yazdık:

#rnd <- sample(x = 1:1000, size = 1)

Kullanıcı bildikçe rnd‘ye 1 ile 1000 arasında bir sayı atanacak ve bu gidecek set.seed()‘in içindeki rnd‘yi değiştirecek.

Kullanıcının q ve sayı dışında bir değer girmesini de engelleyelim. Bu konuyu ileride daha kapsamlı anlatmak istiyorum. Fakat ön bir bilginiz olmasını isterseniz devam edebilirsiniz.

tryCatch() şöyle bir yapıya sahiptir:

tryCatch(
  
    expr = {
        #çalıştırılacak kod
    },
    
    error = function(e){ 
        #hata
    },
    
    warning = function(w){
        #uyarı
    },
    
    finally = {
        #yapı sonlandırıldığında mesaj
    }
)
rnd <- 123

while(TRUE) {
  
  set.seed(rnd)
  makine <- sample(x = 1:100, size = 1)
  
  tryCatch(
    
    expr = {
      
      girdi <- readline(prompt = "1-100 arasında bir sayı girin: ")
      
      if (girdi == "q") {
        break
      } else {
        if (as.numeric(girdi) > makine) {
          print("İn")
        } else if (as.numeric(girdi) < makine) {
          print("Çık")
        } else if (as.numeric(girdi) == makine) {
          rnd <- sample(x = 1:1000, size = 1)
          print("Bildin!")
        }
      }
      
    },
    
    error = function(e) {
      
      message("Bir hata yakaladık! Lütfen sayı girin.")
      print(e)
      
    }
    
  )
  
}

tryCatch()‘in içine expr ve error koyduk. expr‘ın içine çalışması gereken kodu yerleştirdik. Kullanıcıdan girdi aldığımız yerden itibaren çalıştırmak işimizi görecektir çünkü hatayı orada alabiliriz. error‘ün içinde de hatayı yakalayan ve kullanıcıyı bilgilendiren bir fonksiyon var. Böylece hem hata ile mesajı ekrana veren hem de döngünün sonlanmamasını sağlayan bir yapıdan faydalandık.

Oyunun yapım aşaması bitti. Eklenecek daha bir çok özellik olacaktır. Ben iki tanesini yazayım belki sizler yapmak istersiniz. 1) Oynayan kişinin canı olsun ve her yanlış yaptığında 1 azalsın. Bunu ekrana yazdırın ve canı bitince oyunu sonlandırın. Fakat bilirse canını yenileyin. 2) Oynayan kişi q ile çıktığı zaman ekrana ilk “oyundan çıkılıyor…” yazdırın; sonra “oyun sonlandırıldı” gelsin. Aşağıya cevapları bırakacağım. Aynı olmak zorunda değil; sadece düşünün ve yazın.

Biraz oynayalım.

#döngüyü çalıştır

1-100 arasında bir sayı girin: 10
[1] "Çık"

1-100 arasında bir sayı girin: 50
[1] "İn"

1-100 arasında bir sayı girin: 45
[1] "Bildin!"

1-100 arasında bir sayı girin: q

Yazının ve R’da İlk Adımlar serisinin sonuna geldik. Bundan sonraki yazılarda uygulamalar ile ileri ve özel konulara değineceğim. Umuyorum faydalı bir başlangıç serisi olmuştur.

can <- 9
rnd <- 123

while(TRUE) {
  
  set.seed(rnd)
  makine <- sample(x = 1:100, size = 1)
  
  tryCatch(
    
    expr = {
      
      girdi <- readline(prompt = "1-100 arasında bir sayı girin: ")
      
      if (girdi == "q") {
        print("Oyun sonlandırılıyor...")
        Sys.sleep(time = 3) #3 saniye bekletir
        print("Oyun sonlandırıldı.")
        break
      } else {
        if (as.numeric(girdi) > makine) {
          can = can - 1
          print(paste0("Hakkınız: ",can," Komut: İn"))
        } else if (as.numeric(girdi) < makine) {
          can = can - 1
          print(paste0("Hakkınız: ",can," Komut: Çık"))
        } else if (as.numeric(girdi) == makine) {
          rnd <- sample(x = 1:1000, size = 1)
          can = 9
          print(paste0("Bildin! Toplam can: ",can))
        }
      }
      
    },
    
    error = function(e) {
      
      message("Bir hata yakaladık! Lütfen sayı girin.")
      print(e)
      
    }
    
  )
  
  if(can == 0){
    print("Canınız kalmadı")
    break
  }
  
}

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir