R’da İlk Adımlar – 2

R’da İlk Adımlar – 1‘de fonksiyon kelimesini 37 defa kullanmışım. Serimizin bu yazısı fonksiyonlarla başlayacak; if koşul ifadeleri ile devam edecek. Bu yazı ile beraber önceki derste öğrendiklerinizi de pekiştirmiş olacaksınız.

Başlamadan kodları artık script‘te yazdığımı belirtmek istiyorum.

Fonksiyonları bir örnek ile anlamaya çalışalım. Önceki yazıda kullandığımız mean() fonksiyonuna bakalım. Basit bir şekilde bu fonksiyon ve genel olarak fonksiyonlar şu işleri yapar: Kullanıcıdan girdi parametrelerini alırlar. Bu parametreleri alarak bir aksiyon oluştururlar. Aksiyondan sonra bir çıktı üretirler.

Elimizde üç adet ve beş elemanlı vektörler olsun.

vektor1 <- c(2,3,5,7,11)
vektor2 <- c(2,4,6,8,10)
vektor3 <- c(1,3,5,7,9)

Bu vektörlerin ortalamasını iki farklı yoldan alalım.

#yol-1

ortalama1_1 <- (2+3+5+7+11)/5
ortalama1_2 <- (2+4+6+8+10)/5
ortalama1_3 <- (1+3+5+7+9)/5

c("Ortalama1"=ortalama1_1,"Ortalama2"=ortalama1_2,"Ortalama3"=ortalama1_3)

Ortalama1 Ortalama2 Ortalama3 
      5.6       6.0       5.0
#yol-2

ortalama2_1 <- mean(vektor1)
ortalama2_2 <- mean(vektor2)
ortalama2_3 <- mean(vektor3)

c("Ortalama1"=ortalama2_1,"Ortalama2"=ortalama2_2,"Ortalama3"=ortalama2_3)

Ortalama1 Ortalama2 Ortalama3 
      5.6       6.0       5.0

Yukarıda görüldüğü üzere ortalamaları iki farklı yoldan almış olduk. İkinci yol, önceki derste de kullandığımız mean() fonksiyonunu kullanmak oldu. Bu basit örnekte bile fonksiyonlar pratikliğini ortaya koyuyor. Bir kere yazılan fonksiyon bizi iş yükünden kurtaracaktır. Peki, fonksiyon nasıl yazılır?

Temel yapı şudur:

fonksiyon_ismi <- function(parametre){

  aksiyon

  return(çıktı)

}

function(){} yazdıktan sonra iki süslü parantezin arasındayken enter’a basılabilir.

Adım-1: Önce fonksiyonumuza bir isim verelim. Böylece ilk dersten de hatırlayacağımız üzere bir obje yaratmış olacağız.

ortalama <- function(){
  
}

class() ile objenin sınıfını öğrenebiliriz.

class(ortalama)

[1] "function"

Adım-2: Kullanıcıdan almak istediğimiz parametreleri belirleyelim.

ortalama <- function(sayi){
  
}

Burada sayi bir parametredir.

Adım-3: Aldığımız parametrelerle aksiyonu oluşturalım.

ortalama <- function(sayi){
  toplam <- sum(sayi)
  uzunluk <- length(sayi)
  sonuc <- toplam / uzunluk
}

ortalama(sayi = c(2,3,5,7,11))

Sırasıyla toplam almada ve uzunluk belirlemede kullanılan sum() ve length() fonksiyonlarından yararlanarak bu sayıların ortalamasını alan bir aksiyon yarattık. Kullanıcı ortalama yazıp parantezi açtıktan sonra (otomatik olarak kapanacak) içeride bir parametre çıkacaktır. Bu parametre daha önce fonksiyonun içine yazılan sayi‘dir. Kullanıcı bunları c() fonksiyonu ile girer (bu fonksiyon vektör oluşturmada yardımcı oluyordu).

Fonksiyon bir çıktı vermedi. Finali return() ile tamamlıyoruz. Bu, bize sonuc‘u döndürecektir.

ortalama <- function(sayi){
  toplam <- sum(sayi)
  uzunluk <- length(sayi)
  sonuc <- toplam / uzunluk
  return(sonuc)
}

ortalama(sayi = c(2,3,5,7,11))

[1] 5.6

R’ın temel fonksiyonlarından biri olan mean() ile ortalama alıp sonuçları karşılaştıralım.

mean(x = c(2,3,5,7,11))

[1] 5.6

Şimdi bir problem yaratalım. Eğer kullanıcı sayı olmayan değerler girseydi sonuç ne olacaktı?

ortalama(sayi = c(2,3,5,7,11,"x"))

Error in sum(sayi) : argümanın geçersiz 'type' (character)

Sonuçtan da görüldüğü üzere hata alacaktı. O zaman bunu kontrol etmek gerekiyor. İlk dersi pekiştirmeye devam ediyoruz. Girilen değerlerin numeric olup olmadığını kontrol edelim.

sayi <- c(2,3,5,7,11)
is.numeric(sayi)

[1] TRUE

Sonucu, logical değerlerden biri olan TRUE döndürdü. Yani, sayi vektörü numeric‘tir. Bu durumda fonksiyon çalışabilir.

sayi <- c(2,3,5,7,11,"x")
is.numeric(sayi)

[1] FALSE

İçine bir karakter ekleyince bu defa sonucu logical değerlerden biri olan FALSE döndürdü. Yani, sayi vektörü character‘e zorlandı. O zaman burada bir “if-else” diyeceğiz. Diğer bir ifade ile, eğer girilen vektör numeric ise işlemi gerçekleştir; numeric değilse kullanıcıya uyarı ver.

Bu ifadeleri üç şekilde yazabiliriz: if, if-else, if-else if-else

if: Eğer yazı bittiyse kahve yap.

if-else: Eğer yazı bittiyse kahve yap; yoksa yazıya devam et.

if-else if-else: Eğer yazı bittiyse kahve yap; eğer yazı bitmediyse ama yorulduysan hava al; yoksa yazıya devam et.

Başlamadan bir not: if(){}, else if(){} ve else{} dedikten sonra iki süslü parantez arasında iken enter’a basabilirsiniz. Bu, kod yazacağınız alanı genişletip daha rahat yazmanızı sağlar.

Temel yapı şöyledir:

if(koşul){
  
  aksiyon-1

} else {
  
  aksiyon-2
  
}

Önce, girilen sayının çift olup olmadığı ile ilgili basit bir örnek yapalım.

x <- 100

if(x %% 2 == 0){
  cat("Girilen sayı",x,"çifttir.")
} else {
  cat("Girilen sayı",x,"çift değildir.")
}

Girilen sayı 100 çifttir.

if-else yapısının temel mantığı budur. Parantezin içine yazılan koşul TRUE ise süslü parantezin içine yazılan aksiyonu yerine getirir. Eğer yazılan koşul FALSE ise aksiyonu pas geçer ve bir sonrakine bakar.

%% operatörü (100 mod 2) ile sonuca baktık. Eğer sonuç sıfır ise çift; değilse çift değildir dedik. Bunu, == 0 ile kontrol ettik. print() yerine cat()‘i de tanımanızı istedim. cat() fonksiyonu verilen parametreleri karaktere çevirir. Yani, tek bir karakter vektöründe birleştirir. print() ile bunu yapamazsınız. Eğer ısrarla print() ile yapmak isterseniz de ilk derste anlatılan paste() veya paste0() fonksiyonları ile şöyle yazılabilir.

x <- 100

#yol-1

if(x %% 2 == 0){
  print(paste("Girilen sayı",x,"çifttir."))
} else {
  print(paste("Girilen sayı",x,"çift değildir."))
}

[1] "Girilen sayı 100 çifttir."

#yol-2

if(x %% 2 == 0){
  print(paste0("Girilen sayı ",x," çifttir."))
} else {
  print(paste0("Girilen sayı ",x," çift değildir."))
}

[1] "Girilen sayı 100 çifttir."

Şimdi ilk yazdığımız fonksiyona dönelim ve if-else yapısını içeriye ekleyelim.

ortalama <- function(sayi){
  if(is.numeric(sayi) == FALSE){
    print("Sayısal olmayan değer(ler) girdiniz!")
  } else {
    toplam <- sum(sayi)
    uzunluk <- length(sayi)
    sonuc <- toplam / uzunluk
    return(sonuc)
  }
}

ortalama(sayi = c(2,3,5,7,11,"x"))

[1] "Sayısal olmayan değer(ler) girdiniz!"

ortalama(sayi = c(2,3,5,7,11))

[1] 5.6

Başka bir problem yaratalım. Kullanıcı NA de girebilir. Hatırlayalım: NA (Not Available) kayıp veri olduğunu söyler. Örneğin, kullanıcının elinde bir data frame ya da veri çerçevesi vardır ve bir sütununun ortalamasını aldırmak isteyebilir. Fakat o sütunda da bir veya birden fazla NA olabilir.

df <- data.frame(
  col1 = letters[1:10],
  col2 = c(1,2,3,NA,4,5,6,NA,NA,7)
)

ortalama(sayi = df$col2)

[1] NA

Fonksiyonumuz sonucu NA verdi fakat bizim fonksiyonumuz NA‘ye rağmen işlem yapıyor olsun.

ortalama <- function(sayi){
  if(is.numeric(sayi) == FALSE){
    print("Sayısal olmayan değer(ler) girdiniz!")
  } else {
    toplam <- sum(sayi, na.rm = TRUE)
    uzunluk <- length(sayi[!is.na(sayi)])
    sonuc <- toplam / uzunluk
    return(sonuc)
  }
}

ortalama(sayi = df$col2)

[1] 4

Önceki derste, eğer NA‘ye rağmen işlem gerçekleştirilmek istenirse na.rm = TRUE ile NA yok sayılabilir demiştik. Bunu sum() fonksiyonunun içine yerleştirdik ki NA‘ye rağmen toplamı alabilsin. length() fonksiyonunda ise şu yapıdan yararlandık: sayi[!is.na(sayi)]. Karışık görünen ama oldukça basit bu yapıyı biraz açalım.

df‘in ikinci sütununu sayi değişkenine atayalım.

sayi <- df$col2

Bu vektörün uzunluğu veya eleman sayısı normalde 10’dur.

length(sayi)

[1] 10

Ama bu 10 olan uzunluk NA‘ler de içermektedir. Test edelim.

is.na(sayi)

[1] FALSE FALSE FALSE  TRUE FALSE FALSE FALSE  TRUE  TRUE FALSE

TRUE olanlar NA anlamındadır. Başına ! mantıksal operatörünü koyarsak bu NA içermeyenleri, FALSE olanları, ifade eder.

!is.na(sayi)

[1]  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE FALSE FALSE  TRUE

TRUE olanlar bu defa NA içermeyenler anlamına geldi. Vektörlerde bir değere ulaşmak için [] köşeli parantezlerini kullanırız. Örneğin, sayi vektörünün 10. değeri şudur:

sayi[10]

[1] 7

Eğer köşeli parantezlerin içine !is.na(sayi) koyarsak bu TRUE olanları, NA olmayanları, getirir.

sayi[!is.na(sayi)]

[1] 1 2 3 4 5 6 7

Şimdi bir de başına length() koyarsak bize NA‘siz uzunluğu vermiş olacaktır.

length(sayi[!is.na(sayi)])

[1] 7

İşte yaptığımız şey yukarıda anlatılanlardı. Artık sonucun bize doğru olan 4 değerini vermesini bekleyebiliriz.

ortalama(sayi = df$col2)

[1] 4

#test

mean(x = df$col2, na.rm = TRUE)

[1] 4

Öğrendiklerimizi pekiştirmek için gelin bir uygulama yapalım. Bu uygulamamızda Vücut Kitle Endeksini (VKE) hesaplayalım.

  • VKE, ağırlığın boyun karesine oranıdır. VKE = ağırlık / boy^2

Çıkan değer;

  • 18.5’den küçük ise zayıf,
  • 18.5 ile 24.9 arasında ise normal kilolu,
  • 25 ile 29.9 arasında ise fazla kilolu,
  • 30 ile 39.9 arasında ise obez,
  • 40’dan büyük ise morbid obez.

Önce vke adında bir fonksiyon tanımlayalım ve içine girilmesi gereken parametreleri yazalım.

vke <- function(agirlik_kg, boy_metre){
  
}

Ardından formülü yazıp çıkan değere göre kullanıcının hangi aralığa düştüğünü yazalım.

Geçmeden üç not: i) if-else koşul ifadesine else if de eklenebilir. Eğer ikiden fazla koşul varsa if ile else arasında kalan koşulları anlatmak için else if‘den yararlanılır. ii) round() ile değerin digit sayısı (ondalık uzunluğu) belirlenebilir. Biz noktadan sonra 1 rakam alacağız. iii) <= küçük eşit, >= büyük eşit, & mantıksal ve demektir.

vke <- function(agirlik_kg, boy_cm){
  boy_m <- boy_cm / 100
  endeks <- agirlik_kg / boy_m^2
  deger <- round(endeks, digits = 1)
  if(deger < 18.5){
    cat("VKE:",deger,"Kategori: Zayıf")
  } else if(deger >= 18.5 & deger <= 24.9){
    cat("VKE",deger,"Kategori: Normal Kilolu")
  } else if(deger >= 25 & deger <= 29.9){
    cat("VKE",deger,"Kategori: Fazla Kilolu")
  } else if(deger >= 30 & deger <= 39.9){
    cat("VKE",deger,"Kategori: Obez")
  } else{
    cat("VKE",deger,"Kategori: Morbid Obez")
  }
}

Kullanıcıdan, ağırlığını kg; boyunu cm cinsinden istedik. cm cinsiden verilen boyu m birimine çevirdik. Formül ile endeksi hesapladık. Çıkan endeksi deger değişkenine digit = 1 olacak şekilde atadık. Koşul ifadelerini yazdık. Son koşulu, son olduğu için else‘in içine yazdık fakat else if(deger >= 40) ile de bitirebilirdik. Yani, else yazmak zorunda değiliz.

vke(agirlik = 80, boy = 180)

VKE 24.7 Kategori: Normal Kilolu

vke(agirlik = 120, boy = 190)

VKE 33.2 Kategori: Obez

Başta temel adımları öğrenirken ek bilgilerle kafa karışıklığa yol açmak istemedim fakat yazının sonunda faydalı olabileceğini düşündüğüm için yazmak istiyorum. Birincisi, fonksiyon yazarken kullandığımız parametre, aksiyon, çıktı bilgileri opsiyoneldir. Yani, yazmak zorunda değiliz. İkincisi bir fonksiyonu değişik yazma biçimleri ile oluşturabiliriz. Üçüncüsü fonksiyonda olduğu gibi if koşul ifadelerini de değişik yazma biçimleri ile oluşturabiliriz.

Fonksiyon yazarken kullandığımız parametre, aksiyon, çıktı bilgileri opsiyoneldir.

i. Fonksiyonun ismi karsilama olsun. Herhangi bir parametre almasın. print() ile çıktı versin. return() olmasın.

karsilama <- function(){
  print("Merhaba")
}

karsilama()

[1] "Merhaba"

ii. Fonksiyonun ismi yine karsilama olsun. Bir tane parametre alsın. cat() fonksiyonu ile çıktı versin. Yine return() olmasın.

karsilama <- function(isim){
  cat("Merhaba,",isim)
}

karsilama(isim = "RPy")

Merhaba, RPy

Fonksiyon artık bir parametre alıyor ve bu parametre girilmezse hata verecektir.

karsilama()

Error in cat("Merhaba,", isim) : varsayılanı olmayan "isim" argümanı yok

iii. Aynı fonksiyon ismi ile devam edelim. Parametre almaya devam etsin. paste() fonksiyonunu ekleyelim. Bu defa return() içersin ve dışarıya sonuç vermesin.

karsilama <- function(isim){
  x <- paste("Merhaba,",isim)
  return(x)
}

sonuc <- karsilama(isim = "RPy")

Görüldüğü üzere dışarıya herhangi bir sonuç basmadı. sonuc‘u print() ile bastıralım.

print(sonuc)

[1] "Merhaba, RPy"

iv. Son fonksiyonumuzun ismi aynı olsun. Parametre alsın. Bu defa hem print() hem return() olsun.

karsilama <- function(isim){
  x <- paste("Merhaba,",isim)
  print(x)
  
  y <- nchar(x)
  return(y)
}

sonuc <- karsilama(isim = "RPy")

[1] "Merhaba, RPy"

Dikkat ettiyseniz sonuc objesine atadığımız fonkisyonu çalıştırdığımızda “Merhaba, RPy” basıldı. Ama sonuc‘un class‘ına bakarsak bunun karakter sayısını içeren bir veri tipi olduğunu göreceğiz. Yani, integer. Bunu sonuc‘a attığını görebilirsiniz.

class(sonuc)

[1] "integer"

sonuc

[1] 12

nchar("Merhaba, RPy")

[1] 12

Bir fonksiyonu değişik yazma biçimleri ile oluşturabiliriz.

Örneğin, bir sayının karesini alan bir fonksiyon yaratalım.

i. Tip-1 return‘lü

karesi <- function(sayi){
  return(sayi^2)
}

karesi(4)

[1] 16

ii. Tip-2 return‘lü

karesi <- function(sayi){ return(sayi^2) }

karesi(4)

[1] 16

iii. Tip-3 return‘lü

karesi <- function(sayi) return(sayi^2)

karesi(4)

[1] 16

iv. Tip-4 return‘süz

karesi <- function(sayi) sayi^2

karesi(4)

[1] 16

v. Tip-5 return‘süz

karesi <- function(sayi){
  sayi^2
}

karesi(4)

[1] 16

if koşul ifadelerini değişik yazma biçimleri ile oluşturabiliriz.

Örneğin, bir sayının pozitif olup olmadığını yazdıralım.

sayi <- -1

i. Tip-1

if(sayi > 0){
  print("Pozitif")
}

Genişletelim.

if(sayi > 0){
  print("Pozitif")
} else if(sayi < 0){
  print("Negatif")
} else {
  print("Nötr")
}

[1] "Negatif"

ii. Tip-2

if(sayi > 0){ print("Pozitif") }

Genişletelim.

if(sayi > 0){ print("Pozitif") } else if(sayi < 0){ print("Negatif") } else { print("Nötr") }

[1] "Negatif"

iii. Tip-3

if(sayi > 0) print("Pozitif")

Genişletelim.

if(sayi > 0) print("Pozitif") else if(sayi < 0) print("Negatif") else print("Nötr")

[1] "Negatif"

Serinin ikinci yazısının sonuna geldik. Bu yazıda hem fonksiyonlar ile if koşul ifadelerini öğrenmiş hem de önceki derste anlatılanları pekiştirmiş oldunuz. Amacım, bu akışı her yeni yazıda sizlere sunabilmektir.

Yazı serisi devam ediyor olacak, görüşmek dileği ile.

One thought on “R’da İlk Adımlar – 2

Bir cevap yazın

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