Bölüm 8 Koşul İfadeleri, Döngüler ve Fonksiyonlar

8.1 Koşul İfadeleri

8.1.1 if() Koşul İfadesi

if() koşul ifadesi hemen hemen tüm programlama dillerinde mevcuttur ve oldukça önemlidir. Bu bir fonksiyon olarak düşünülebilir ve bu fonksiyonda koşullu bir ifade bir ölçüt ile karşılaştırılarak test edilir ve koşullu ifadenin gerçekleşmesi durumunda (TRUE) elde edilecek çıktı belirlenebilir.

deger <- 175 
if (deger >= 160) { 
print("Yeterli") 
}
## [1] "Yeterli"
if (deger >= 176) { 
print("Yeterli") 
}

İlk örnekte ‘Yeterli’ çıktısı alınırken, ikinci örnekte herhangi bir çıktı bulunmamaktadır. Çünkü deger isimli nesnede saklanan değer 176’ya eşit ya da ondan büyük değildir.

8.1.2 else() Koşul İfadesi

else() koşul ifadesi if() koşuk ifadesindeki koşullar sağlanmadığı durumda ortaya çıkacak alternatifi belirlemek amacıyla kullanılır.

deger <- 175 
if (deger >= 180) { 
print("Yeterli") 
} else { 
print("Yetersiz") 
}
## [1] "Yetersiz"

8.1.3 else if() Koşul İfadesi

if() ve else() koşul ifadelerinde bir koşullu önermenin iki farklı alternatifi (TRUE ya da FALSE) üzerinde durulmaktadır. Ancak, olası durum çıktılarının ikiden fazla olması da söz konusu olabilir. Bu durumda else if() koşul ifadesi kullanılabilir.

p1 <- 0.37 
if(p1 >= 0.80) { 
  print("Çok Kolay")
} else if(p1 >= 0.60) { 
    print("Kolay") 
} else if(p1 >= 0.40) { 
    print("Orta") 
} else if(p1 >= 0.20) { 
  print("Zor")
} else if(p1 >= 0.00) { 
  print("Çok Zor") 
  }
## [1] "Zor"

if() koşul ifadeleri vektörlerde kullanılamaz. Yukarıdaki örneğe benzer şekilde, birden fazla madde (soru) için madde güçlük indeksleri verildiğinde her biri için yorum yapmak istendiğinde ifelse() fonksiyonu kullanılabilir.

8.1.4 ifelse() Koşul İfadesi

ifelse() koşul ifadesinin genel kullanımı şu şekildedir: ifelse(koşul, doğru ifade, yanlış ifade).

deger <- 173 
ifelse(deger >= 175, "Yeterli", "Yetersiz")
## [1] "Yetersiz"
degerler <- c(173, 170, 181, 189, 190, 191, 180, 171, 163, 166) 
ifelse(degerler >= 175, "Yeterli", "Yetersiz")
##  [1] "Yetersiz" "Yetersiz" "Yeterli"  "Yeterli"  "Yeterli"  "Yeterli" 
##  [7] "Yeterli"  "Yetersiz" "Yetersiz" "Yetersiz"
# örneğin ifelse() ile bir veri setindeki 99 değerleri yerine NA girilebilir. 
yeniveri <- c(2, 2, 2, 1, 1, 99, 1, 2) 
yeniveri2 <- ifelse(yeniveri == 99, NA, yeniveri) 
yeniveri2
## [1]  2  2  2  1  1 NA  1  2
ornekData <- data.frame(no = c (1:5), 
                        isim = c("Kaan","Ata","Yamaç","Okan","Serhat"), 
                        maas = c(12000, 17000, 160000, 21000, 8500)) 
ornekData2 <- ornekData 
ornekData2$maas <- ifelse(ornekData$maas >= 50000, "hatali giris", ornekData$maas) 
ornekData3 <- data.frame(ornekData$no, ornekData$isim, ornekData2$maas) 
ornekData3
##   ornekData.no ornekData.isim ornekData2.maas
## 1            1           Kaan           12000
## 2            2            Ata           17000
## 3            3          Yamaç    hatali giris
## 4            4           Okan           21000
## 5            5         Serhat            8500
colnames(ornekData3) <- c("No", "Ad", "Maas") 
ornekData3
##   No     Ad         Maas
## 1  1   Kaan        12000
## 2  2    Ata        17000
## 3  3  Yamaç hatali giris
## 4  4   Okan        21000
## 5  5 Serhat         8500

8.2 Döngüler

Döngüler, programlama dillerinde sıklıkla kullanılan akış kontrolü (flow control) mekanizmasının bir parçasıdır. R’da döngüler for(), while() ve repeat() fonksiyonları ile çalıştırılır.

8.2.1 for Döngüsü

# bir vektör içindeki tüm elemanların karesini alma
x <- c(1:20) 
for (i in x) {
  print(i^2)
  }
## [1] 1
## [1] 4
## [1] 9
## [1] 16
## [1] 25
## [1] 36
## [1] 49
## [1] 64
## [1] 81
## [1] 100
## [1] 121
## [1] 144
## [1] 169
## [1] 196
## [1] 225
## [1] 256
## [1] 289
## [1] 324
## [1] 361
## [1] 400

Yukarıdaki örnekte x vektörünün her elemanının karesinin alınıp tek tek gösterilmesi (print()) istenmiştir. for() fonksiyonunun içindeki i indeksi göstermektedir ve i’nin sırasıyla 1’den 20’ye kadar değer alması istenmiştir.

liste <- list(1:6, letters[1:4], c("AA", "BA", "BB", "CB", "CC")) 
liste
## [[1]]
## [1] 1 2 3 4 5 6
## 
## [[2]]
## [1] "a" "b" "c" "d"
## 
## [[3]]
## [1] "AA" "BA" "BB" "CB" "CC"
for(i in 1:length(liste)) {
  liste[[i]] <- rep(liste[[i]], 3)
  } 
liste
## [[1]]
##  [1] 1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6
## 
## [[2]]
##  [1] "a" "b" "c" "d" "a" "b" "c" "d" "a" "b" "c" "d"
## 
## [[3]]
##  [1] "AA" "BA" "BB" "CB" "CC" "AA" "BA" "BB" "CB" "CC" "AA" "BA" "BB" "CB" "CC"

Yukarıdaki örnekte i’nin sırasıyla 1’den liste isimli nesnenin uzunluk değerine kadar değer alması istenmiştir. Döngünün içine yazılan fonksiyon (rep()) aracılığı ile listenin i’nci elemanından başlayarak her elemanının - ki üç elemanı (nesnesi) vardır - içindeki elemanların üç kere tekrarlanarak nesnelerin uzatılması istenmiştir. Bu işlemin ardından liste isimli nesne değişecektir, ancak ekrana bir sonuç gelmeyecektir. Çünkü istenmemiştir. Ardından komut satırına liste yazılarak nesnenin yeni hali görüntülenebilir.

# 6 satırdan 3 sütundan oluşan bir data frame oluşturalım
yeniVeri <- data.frame(S1 = c(1, 3, 5, 7, 9, 11),
                       S2 = rep(1:3, 2),
                       S3 = seq(from = 1, to = 20, length.out = 6))

# Bu data frame'e yeni bir sütun (S4) eklensin ve bu sütunda ilk üç sütundaki değerlerin toplamı gösterilsin
for (i in 1:6) {
  yeniVeri$S4[i] <- yeniVeri$S1[i] + yeniVeri$S2[i] + yeniVeri$S3[i]
  
}
yeniVeri
##   S1 S2   S3   S4
## 1  1  1  1.0  3.0
## 2  3  2  4.8  9.8
## 3  5  3  8.6 16.6
## 4  7  1 12.4 20.4
## 5  9  2 16.2 27.2
## 6 11  3 20.0 34.0
# aynı işlemi yaparken i indeksinin 1 ile 6 arasında dönmesi ile 1 ile nrow(yeniVeri) arasında dönmesi aynı anlama gelmektedir. Çünkü nrow() fonksiyonu içindeki data frame'in satır sayısını vermektedir
yeniVeri <- data.frame(S1 = c(1, 3, 5, 7, 9, 11),
                       S2 = rep(1:3, 2),
                       S3 = seq(from = 1, to = 20, length.out = 6))

for (i in 1:nrow(yeniVeri)) {
  yeniVeri$S4[i] <- yeniVeri$S1[i] + yeniVeri$S2[i] + yeniVeri$S3[i]
}
yeniVeri
##   S1 S2   S3   S4
## 1  1  1  1.0  3.0
## 2  3  2  4.8  9.8
## 3  5  3  8.6 16.6
## 4  7  1 12.4 20.4
## 5  9  2 16.2 27.2
## 6 11  3 20.0 34.0
# burada for döngüsü örneklendirilmeye çalışılmıştır. Ancak satırdaki değerlerin toplamı için daha basit bir komut R'da mevcuttur: rowSums()
yeniVeri <- data.frame(S1 = c(1, 3, 5, 7, 9, 11),
                       S2 = rep(1:3, 2),
                       S3 = seq(from = 1, to = 20, length.out = 6))

# for döngüsü kullanılmadan satırlardaki ya da sütunlardaki değerleri toplamak mümkündür. Benzer şekilde satırlardaki/sütunlardaki değerlerin çarpımı, ortalamasının, standart sapmasının alınması gibi pek çok işlem için R'da özel fonksiyonlar bulunmaktadır
yeniVeri$S4 <- rowSums(yeniVeri)
yeniVeri
##   S1 S2   S3   S4
## 1  1  1  1.0  3.0
## 2  3  2  4.8  9.8
## 3  5  3  8.6 16.6
## 4  7  1 12.4 20.4
## 5  9  2 16.2 27.2
## 6 11  3 20.0 34.0

Bir başka örnekte ncol() fonksiyonunu kullanalım.

# 9 satırdan 3 sütundan oluşan bir data frame oluşturalım
# not: seq_len() ve seq.int() fonksiyonlarını ayrı ayrı çalıştırarak nasıl birer vektör oluşturduklarını inceleyiniz.
yeniVeri2 <- data.frame(S1 = seq_len(9),
                        S2 = seq.int(-4, 4),
                        S3 = c(-1, 1, 1, -1, 1, -2, 2, 1, -1)^2)
yeniVeri2
##   S1 S2 S3
## 1  1 -4  1
## 2  2 -3  1
## 3  3 -2  1
## 4  4 -1  1
## 5  5  0  1
## 6  6  1  4
## 7  7  2  4
## 8  8  3  1
## 9  9  4  1
# j indeksinin 1 ile 6 arasında dönmesi ile 1 ile ncol(yeniVeri2) arasında dönmesi aynı anlama gelmektedir. Çünkü ncol() fonksiyonu içindeki data frame'in sütun sayısını vermektedir
for (j in 1:ncol(yeniVeri2)) {
  yeniVeri2[, 3+j] <- yeniVeri2[, j]^2
}

yeniVeri2
##   S1 S2 S3 V4 V5 V6
## 1  1 -4  1  1 16  1
## 2  2 -3  1  4  9  1
## 3  3 -2  1  9  4  1
## 4  4 -1  1 16  1  1
## 5  5  0  1 25  0  1
## 6  6  1  4 36  1 16
## 7  7  2  4 49  4 16
## 8  8  3  1 64  9  1
## 9  9  4  1 81 16  1

Yukarıdaki for döngüsünün ne yaptığını anlamaya çalışalım. j indeksi (illa i olmak zorunda değil) 1 ile 3 arasında dönecektir. Her seferinde yeniVeri’nin j’nci sütunundaki değerlerin karesini alacak ve bunu (3+j)’nci sütun olarak ekleyecektir. Böylelikle data frame’e 3 yeni sütun eklenecek ve data frame 6 sütunlu olacaktır.

Bir döngüde çeşitli fonksiyonlar kullanılabilir. Örneğin bir başka geliştiricinin hazırladığı bir paketteki fonksiyonu kullanarak bir problemi çözmeye çalışalım. Aşağıdaki örnekte öncelikle 3 farklı test verisi oluşturulmuş (hepsinde 10 maddeye yanıt veren öğrenciler bulunmakta, 1’ler doğru, 0’lar yanlış yanıtı ifade etmekte) ve sonrasında psychometric paketi içindeki bir fonksiyondan (item.exam()) yararlanılarak eldeki farklı veri setlerindeki maddelerin madde güçlük indeksleri hesaplanmıştır.

# üç farklı test verisinin matris şeklinde oluşturulması
test_verisi_1 <- matrix(sample(c(1, 0), replace = TRUE, size = 50, prob = c(.40, .60)), 5, 10)
test_verisi_2 <- matrix(sample(c(1, 0), replace = TRUE, size = 50, prob = c(.50, .50)), 10, 10)
test_verisi_3 <- matrix(sample(c(1, 0), replace = TRUE, size = 50, prob = c(.50, .50)), 15, 10)

# üç farklı test verisinin bir listeye alınması
test_verisi <- list(test_verisi_1, test_verisi_2, test_verisi_3)

Örnek uygulama için veri setleri oluşturulmuştur. Farklı bir paketteki fonksiyondan yararlanabilmek için o paket indirilmeli ve kurulmalıdır. Bunun için install.packages("psychometric") satır komutu çalıştırıldıktan sonra aşağıdaki komut çalıştırılmalıdır.

library(psychometric)
## Zorunlu paket yükleniyor: multilevel
## Zorunlu paket yükleniyor: nlme
## 
## Attaching package: 'nlme'
## The following object is masked from 'package:dplyr':
## 
##     collapse
## Zorunlu paket yükleniyor: MASS
## 
## Attaching package: 'MASS'
## The following object is masked from 'package:dplyr':
## 
##     select
## Zorunlu paket yükleniyor: purrr

Paket çalışır hale geldikten sonra aşağıdaki satır komutları çalıştırılabilir.

# boş bir listenin oluşturulması
p_ind <- list()

for (i in 1:3) {
  p_ind[[i]] <- item.exam(test_verisi[[i]])
  print(p_ind[[i]][4])
}
## Warning in cor(x, TOT, use = "complete"): the standard deviation is zero
## Warning in cor(x, TOT.woi, use = "complete"): the standard deviation is zero
##    Difficulty
## 1         0.4
## 2         0.4
## 3         0.2
## 4         0.4
## 5         0.4
## 6         0.4
## 7         0.8
## 8         0.6
## 9         0.0
## 10        0.2
##    Difficulty
## 1         0.7
## 2         0.1
## 3         0.7
## 4         0.7
## 5         0.6
## 6         0.7
## 7         0.1
## 8         0.7
## 9         0.7
## 10        0.6
##    Difficulty
## 1   0.3333333
## 2   0.5333333
## 3   0.6000000
## 4   0.4000000
## 5   0.5333333
## 6   0.4666667
## 7   0.5333333
## 8   0.5333333
## 9   0.4000000
## 10  0.6666667

Sonuçta üç farklı test verisindeki 10 maddeye ilişkin elde edilen madde güçlük indeksleri arka arkaya listelenecektir. Kullanıcı bu görünümü değiştirmek için döngünün içindeki kodları değiştirebilir ya da oluşan p_ind isimli nesne üzerinden düzenlemeler yapabilir. Birden fazla for() döngüsü iç içe kullanılabilir. Bu durumda bu tür döngülere iç içe döngüler (nested loops) denir.

matrisA <- round(matrix(runif(10, min = -2, max = 2), nrow = 5), 2) 
matrisA
##       [,1]  [,2]
## [1,]  1.84 -1.15
## [2,] -0.48  1.66
## [3,]  0.12 -0.87
## [4,]  1.67  1.46
## [5,]  0.38 -0.01
for(i in 1:nrow(matrisA)) {
  for(j in 1:ncol(matrisA)) {
    print(paste("Her a için", "i =", i, "ve", "j =", j, "iken", "değer", matrisA[i, j]))
  }
  }
## [1] "Her a için i = 1 ve j = 1 iken değer 1.84"
## [1] "Her a için i = 1 ve j = 2 iken değer -1.15"
## [1] "Her a için i = 2 ve j = 1 iken değer -0.48"
## [1] "Her a için i = 2 ve j = 2 iken değer 1.66"
## [1] "Her a için i = 3 ve j = 1 iken değer 0.12"
## [1] "Her a için i = 3 ve j = 2 iken değer -0.87"
## [1] "Her a için i = 4 ve j = 1 iken değer 1.67"
## [1] "Her a için i = 4 ve j = 2 iken değer 1.46"
## [1] "Her a için i = 5 ve j = 1 iken değer 0.38"
## [1] "Her a için i = 5 ve j = 2 iken değer -0.01"

8.2.2 while Döngüsü

for() döngülerinde tekrar sayısı vektörün eleman sayısı kadar iken while() döngülerinde döngü sayısı için bir ifade bulunmaz. while() döngüsü if() durum cümlesinde olduğu gibi verilen bir koşulun yanlış (FALSE) olduğu zamana kadar çalışır.

sifir <- 0 
while (sifir < 5) {
  print(sifir) 
  sifir <- sifir + 1
  }
## [1] 0
## [1] 1
## [1] 2
## [1] 3
## [1] 4
while (sifir < 5) {
  sifir <- sifir + 1
  print(sifir)
  }

8.2.3 repeat Döngüsü

repeat() fonksiyonu ile belirlenen ifade bitirme komutuna kadar tekrar edilir. Bu fonksiyon, döngüyü bitirmeye yarayan break komutu ile birlikte kullanılır.

s <- 0 
repeat{
  s <- s + 10
  print(s)
  if(s == 100) break
  }
## [1] 10
## [1] 20
## [1] 30
## [1] 40
## [1] 50
## [1] 60
## [1] 70
## [1] 80
## [1] 90
## [1] 100

8.3 Temel Fonksiyon Yazımı

R’da fonksiyonlar temelde üç temel bileşenden oluşur: başlık, argüman ve gövde. Örnek olarak F_a isimli bir fonksiyon oluşturalım. Bu fonksiyon, kendisine verilen bir değerden 1 sayısını çıkarsın.

F_a <- function(x) {
  x - 1
  }
girdiler <- c(10, 15, 20) 
ciktilar <- F_a(girdiler) 
ciktilar
## [1]  9 14 19

Bir üs alma fonksiyonu yazalım. Bu fonksiyon, kendisine verilen bir değerin üssünü alsın.

usAlma <- function(x, u) {
  x^u
  } 
usAlma(2, 6)
## [1] 64
usAlma(2024, 0)
## [1] 1

Bir küpün bir ayrıtının uzunluğu verildiğinde, küpün hacmini, taban alanını ve yüzeylerinin alanlarının toplamını veren bir fonksiyon yazalım.

kupFonk <- function(a) {
  sonuc <- data.frame(Hacim = a^3, TabanAlani = a^2, AlanlarToplami = 6*a^2)
  print(sonuc)
  } 
kupFonk(4)
##   Hacim TabanAlani AlanlarToplami
## 1    64         16             96
# Birden fazla küp için değerlerin elde edilmesi 
kupFonk2 <- function(a) {
  sonuc <- data.frame(Kenar = a, Hacim = a^3, TabanAlani = a^2, AlanlarToplami = 6*a^2)
  print(sonuc)
  } 
kupFonk2(c(1, 2, 3, 4, 5))
##   Kenar Hacim TabanAlani AlanlarToplami
## 1     1     1          1              6
## 2     2     8          4             24
## 3     3    27          9             54
## 4     4    64         16             96
## 5     5   125         25            150

Kendi yazdığımız fonksiyon içinde, başka geliştiricilerin hazırladığı fonksiyonları da kullanabiliriz. Örneğin;

8.4 apply() Ailesi

R’da istatistiksel analizler yapılırken matrislerin, listelerin veya veri setlerinin her bir satırına ya da sütununa işlemler uygulanmak istenebilir. Bu durumda döngülerin kullanılması her zaman pratik olmayabilir. apply() ailesine ait fonksiyonlarla da satırlara ve sütunlara işlemler uygulanabilir. Bu ailede apply(), lapply(), sapply(), vapply(), mapply(), rapply() ve tapply() fonksiyonları yer almaktadır. Bunlar arasından sık kullanılan dört tanesini inceleyelim.

8.4.1 apply() Fonksiyonu

matris_a <- matrix(c(1:100), nrow = 20, ncol = 5) 
matris_a
##       [,1] [,2] [,3] [,4] [,5]
##  [1,]    1   21   41   61   81
##  [2,]    2   22   42   62   82
##  [3,]    3   23   43   63   83
##  [4,]    4   24   44   64   84
##  [5,]    5   25   45   65   85
##  [6,]    6   26   46   66   86
##  [7,]    7   27   47   67   87
##  [8,]    8   28   48   68   88
##  [9,]    9   29   49   69   89
## [10,]   10   30   50   70   90
## [11,]   11   31   51   71   91
## [12,]   12   32   52   72   92
## [13,]   13   33   53   73   93
## [14,]   14   34   54   74   94
## [15,]   15   35   55   75   95
## [16,]   16   36   56   76   96
## [17,]   17   37   57   77   97
## [18,]   18   38   58   78   98
## [19,]   19   39   59   79   99
## [20,]   20   40   60   80  100
apply(matris_a, 2, mean)
## [1] 10.5 30.5 50.5 70.5 90.5
apply(matris_a, 1, max)
##  [1]  81  82  83  84  85  86  87  88  89  90  91  92  93  94  95  96  97  98  99
## [20] 100
yenibirfonksiyon <- function(x) {
  (mean(x)+max(x))*10
  } 
apply(matris_a, 2, yenibirfonksiyon)
## [1]  305  705 1105 1505 1905
apply(matris_a, 2, function(x) {(mean(x)+max(x))*10})
## [1]  305  705 1105 1505 1905

8.4.2 lapply() Fonksiyonu

lapply() fonksiyonu apply() fonksiyonunun listeler, vektörler ve veri setleri için özelleştirilmiş halidir.

aa <- c(1, 4, 9) 
bb <- c(16, 25, 36) 
liste_sayilar <- list(aa, bb) 
lapply(liste_sayilar, sqrt)
## [[1]]
## [1] 1 2 3
## 
## [[2]]
## [1] 4 5 6
lapply(liste_sayilar, function(x) {mean(x)^2})
## [[1]]
## [1] 21.77778
## 
## [[2]]
## [1] 658.7778

8.4.3 sapply() Fonksiyonu

sapply() fonksiyonu ile de lapply() fonksiyonunda olduğu gibi liste, veri setleri ve vektörler üzerinde çalışılır. sapply() fonksiyonunun temel amacı çıktıları basitleştirmektir. lapply() ile elde edilen çıktılar liste biçiminde iken, sapply() ile elde edilen çıktılar daha çok vektör ya da vektörlerin özel halleri türündedir.

aa <- c(1, 4, 9) 
bb <- c(16, 25, 36) 
liste_sayilar <- list(aa, bb) 

sapp <- sapply(liste_sayilar, sqrt) 
sapp
##      [,1] [,2]
## [1,]    1    4
## [2,]    2    5
## [3,]    3    6
rowSums(sapp)
## [1] 5 7 9

8.4.4 tapply() Fonksiyonu

tapply() fonksiyonu liste ve data frame türündeki nesnelere uygulandığında sonucu vektör ya da liste şeklinde vermektedir. Eğer tapply() içinde kullanılan fonksiyon tek bir değer veriyorsa çıktı vektör olur, birden fazla değer veriyorsa çıktı liste olacaktır.

ad <- c("oguz","sabahattin","yusuf", "tezer") 
cinsiyet <- c("E", "E", "E", "K") 
boy <- c(185, 170, 175, 165) 
cinsiyet <- factor(cinsiyet) 
yeniliste <- list(ad = ad, cinsiyet = cinsiyet, boy = boy) 
# cinsiyete göre boy uzunluklarını küçükten büyüğe sıralanması (cinsiyet faktör idi) 
tapply(yeniliste$boy, yeniliste$cinsiyet, sort)
## $E
## [1] 170 175 185
## 
## $K
## [1] 165
# adlara göre boy uzunluklarını küçükten büyüğe sıralanması 
tapply(yeniliste$boy, yeniliste$ad, sort)
##       oguz sabahattin      tezer      yusuf 
##        185        170        165        175

8.5 Bazı Yararlı Fonksiyonlar

R’da herhangi bir paket (package) indirmeden kullanılabilen, çok sayıda fonksiyon bulunmaktadır. Bu fonksiyonların bir kısmı, kitabın önceki bölümlerinde ele alındı. Bunun haricinde, çeşitli amaçlarla kullanılabilecek birkaç fonksiyonu burada listelemek istedim.

8.5.1 dput() Fonksiyonu

dput() fonksiyonu ile çalışma alanınızda kayıtlı bir veri setini satır komutları haline getirebilirsiniz. Bu özellikle, veri setinizi ya da veri setinizin bir kısmını R’da çalışacak olan biriyle paylaşmak istediğinizde yararlı olabilir.

data(iris)
iris_ornek <- head(iris, 10)
iris_ornek
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1           5.1         3.5          1.4         0.2  setosa
## 2           4.9         3.0          1.4         0.2  setosa
## 3           4.7         3.2          1.3         0.2  setosa
## 4           4.6         3.1          1.5         0.2  setosa
## 5           5.0         3.6          1.4         0.2  setosa
## 6           5.4         3.9          1.7         0.4  setosa
## 7           4.6         3.4          1.4         0.3  setosa
## 8           5.0         3.4          1.5         0.2  setosa
## 9           4.4         2.9          1.4         0.2  setosa
## 10          4.9         3.1          1.5         0.1  setosa
dput(iris_ornek)
## structure(list(Sepal.Length = c(5.1, 4.9, 4.7, 4.6, 5, 5.4, 4.6, 
## 5, 4.4, 4.9), Sepal.Width = c(3.5, 3, 3.2, 3.1, 3.6, 3.9, 3.4, 
## 3.4, 2.9, 3.1), Petal.Length = c(1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 
## 1.4, 1.5, 1.4, 1.5), Petal.Width = c(0.2, 0.2, 0.2, 0.2, 0.2, 
## 0.4, 0.3, 0.2, 0.2, 0.1), Species = structure(c(1L, 1L, 1L, 1L, 
## 1L, 1L, 1L, 1L, 1L, 1L), levels = c("setosa", "versicolor", "virginica"
## ), class = "factor")), row.names = c(NA, 10L), class = "data.frame")

dput(iris_ornek) yukarıda structure() fonksiyonu içinde verilen fonksiyon, argüman ve diğer bilgileri verecektir. Bunu kopyalayarak başka biri ile paylaşabilirsiniz. Böylelikle, o kişi de sizin verdiğiniz veriyi R’a aktarabilir.

8.5.2 Yardım Fonksiyonları

help() fonksiyonu, adından anlaşılacağı üzere yardım fonksiyonudur. Bu fonksiyon ya da ? ile R’daki fonksiyonlar, veri setleri ve diğer nesneler ile ilgili yardım sayfalarına ulaşılabilir. Örneğin help(difTID, package = “difR”) satır komutu çalıştırılarak “difR” paketi içindeki difTID() fonksiyonu ile ilgili bilgilere erişilebilir. Bunun yanı sıra, bir fonksiyon (örneğin lm() fonksiyonu) ile ilgili detaylı bilgilere erişmek isteniyorsa help(lm), help(“lm”), ?lm ya da ?“lm” satır komutları çalıştırılabilir. Ek olarak apropos() fonksiyonu ile isminin bir kısmı hatırlanan fonksiyonlar ve çalışma alanına kayıtlı nesneler listelenebilir. Bu fonksiyonun içine yazılacak metin tırnak işareti içinde verilmelidir ve fonksiyon büyük-küçük harfe duyarlı değildir.

apropos("mean")
##  [1] ".colMeans"      ".rowMeans"      "colMeans"       "cummean"       
##  [5] "gmeanrel"       "graph.ran.mean" "kmeans"         "mean"          
##  [9] "mean.Date"      "mean.default"   "mean.difftime"  "mean.POSIXct"  
## [13] "mean.POSIXlt"   "rowMeans"       "weighted.mean"

8.5.3 ls() Fonksiyonu

ls() fonksiyonunu kullanarak çalışma alanınıza kayıtlı tüm nesneleri listeleyebilirsiniz.

8.5.4 rm() Fonksiyonu

rm() fonksiyonunu kullanarak çalışma alanınızda kayıtlı olan bir nesneyi silebilirsiniz. rm(list = ls()) komutunu çalıştırarak çalışma alanınızda kayıtlı olan tüm nesneleri silebilirsiniz.

8.5.5 identical()

identical() fonksiyonu kendisine verdiğiniz nesnelerin birebir aynı olup olmadığını test etmede kullanılır. Bu kitapta da kullanılmıştır. Örneğin, iki vektörün aynı olup olmadığını aşağıdaki kodlar ile test edelim.

vektor_1 <- 1:5
vektor_2 <- seq(5)
identical(vektor_1, vektor_2)
## [1] TRUE

Çıktının TRUE olması, verilen iki nesnenin (vektör) birebir aynı olduğu anlamına gelir. Eğer bu vektörlerin herhangi bir elemanı farklı olsaydı, sonuç FALSE olarak dönecekti. Bir başka örnek olarak aşağıdaki iki matrisin aynı olup olmadığını test edelim:

matris_1 <- diag(1, 3, 3)
matris_2 <- matrix(c(1, 0, 0, 0, 1, 0, 0, 0, 1), 3, 3)
identical(matris_1, matris_2)
## [1] TRUE

8.5.6 solve()

solve() fonksiyonu yardımıyla cebirsel eşitlikler çözümlenebilir. Bu fonksiyon yardımıyla denklem sistemleri de çözülebilmektedir. Örneğin, \(5x=20\) eşitliğinde \(x\)’in kaç olduğu şu şekilde çözülebilmektedir:

solve(5, 20)
## [1] 4

Dahası, iki denklemden oluşan bir denklem sisteminin çözümünde matrislerden yararlanılabilir. Diyelim ki, \[4x+y=13\] \[3x-2y=7\] denklem sistemi verilsin. Buna göre \(x\) ve \(y\) kaçtır?

# öncelikle denklemlerin çözümü için gerekli matrisleri oluşturalım, bu matrisler katsayılardan oluşacaktır.
M1 <- matrix(c(4, 3, 1, -2), nrow = 2)
M2 <- matrix(c(13, 7), nrow = 2)

# sonucu isteyelim.
solve(M1, M2)
##      [,1]
## [1,]    3
## [2,]    1

8.5.7 D()

D() fonksiyonu ile bir fonksiyonun türevi alınabilir. Örneğin, \(y = x^2+x-1\) fonksiyonunun türevini alalım. Sonucun \(2x+1\) olması gerekir.

f1 <- expression(x^2 + x - 1)
f1_turev <- D(f1, "x")
f1_turev
## 2 * x + 1
# elde edilen sonuca (fonksiyona) aynı işlem tekrar yapılarak 2. türev de alınabilir.
D(f1_turev, "x")
## [1] 2

8.5.8 integrate()

integrate() fonksiyonu ile bir fonksiyonun integrali alınabilir. Örneğin, \(4x^3-2x\) fonksiyonunun integralini alalım. Sonucun \(x^4-x^2+c\) olması gerekir. Üst sınırın 2, alt sınırın 0 olduğu durumda alınan belirli integralin sonucu ise 12 olması gerekir.

f2 <- function(x) {
  4*x^3 - 2*x
}
integrate(f2, lower = 0, upper = 2)
## 12 with absolute error < 1.4e-13

8.5.9 Sys.Date() ve Sys.time()

Sys.Date() ve Sys.time() fonksiyonları sistemin tarih ve saatini yazdırmaya yarar. Çıktısı ‘tarih’ türünde bir nesnedir.

Sys.Date()
## [1] "2024-06-15"
Sys.time()
## [1] "2024-06-15 00:54:02 +03"

8.5.10 aggregate()

aggregate() fonksiyonu veriyi alt veri setlerine göre gruplandırarak işlem yapma olanağı sağlar. Örnek için R’da bulunan airquality veri setini ele alalım. Bu veri setindeki Ozone ve Temp değişkenlerinin aylara (Month) göre ortalamalarını bulmak için aşağıdaki satır komutları kullanılır.

head(airquality)
##   Ozone Solar.R Wind Temp Month Day
## 1    41     190  7.4   67     5   1
## 2    36     118  8.0   72     5   2
## 3    12     149 12.6   74     5   3
## 4    18     313 11.5   62     5   4
## 5    NA      NA 14.3   56     5   5
## 6    28      NA 14.9   66     5   6
aggregate(cbind(Ozone, Temp) ~ Month, data = airquality, mean)
##   Month    Ozone     Temp
## 1     5 23.61538 66.73077
## 2     6 29.44444 78.22222
## 3     7 59.11538 83.88462
## 4     8 59.96154 83.96154
## 5     9 31.44828 76.89655

8.5.11 cor()

cor() fonksiyonu ile korelasyon matrisleri (tabloları) elde edilebilir. Örneğin R’da bulunan mtcars isimli veri setindeki mpg, cyl ve disp değişkenlerinin ikili korelasyonlarını hesaplayalım.

cor(mtcars[, 1:3])
##             mpg        cyl       disp
## mpg   1.0000000 -0.8521620 -0.8475514
## cyl  -0.8521620  1.0000000  0.9020329
## disp -0.8475514  0.9020329  1.0000000

Yukarıdaki satır komutunda köşeli parantez içinde verilen 1:3 ifadesi birinci sütundan üçüncü sütuna kadar olan sütunları seçmek için kullanılmaktadır. Bu nedenle çıktıda bu sütunlar (mpg, cyl ve disp) yer almaktadır.

8.5.12 merge()

merge() fonksiyonu yardımıyla iki veri seti bir değişken üzerinden birleştirilebilir. Aşağıdaki örnekte Basketbol Süper Ligi ile ilgili istatistiklerden oluşan iki ayrı data frame üretilmiştir.

# örnek uygulama için veri setlerini oluşturalım
BSL1 <- data.frame(id = 1:11,
                   takim = c("Anadolu Efes", "Fenerbahçe", "Eczacıbaşı", "Galatasaray", "İTÜ", "Ülkerspor",
                             "Beşiktaş", "Tofaş", "Pınar Karşıyaka", "Altınordu", "Muhafızgücü"),
                   sampiyonluk = c(16, 10, 8, 5, 5, 4, 2, 2, 2, 1, 1))
BSL2 <- data.frame(ID = c(11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1),
                   ikincilik = c(0, 0, 2, 3, 7, 5, 1, 4, 1, 10, 13),
                   son_sapiyonluk = c("1974", "1967", "2015", "2000", "2012", "2006",
                                      "1973", "2013", "1989", "2022", "2023"))

# veri setlerini inceleyelim
BSL1
##    id           takim sampiyonluk
## 1   1    Anadolu Efes          16
## 2   2      Fenerbahçe          10
## 3   3      Eczacıbaşı           8
## 4   4     Galatasaray           5
## 5   5             İTÜ           5
## 6   6       Ülkerspor           4
## 7   7        Beşiktaş           2
## 8   8           Tofaş           2
## 9   9 Pınar Karşıyaka           2
## 10 10       Altınordu           1
## 11 11     Muhafızgücü           1
BSL2
##    ID ikincilik son_sapiyonluk
## 1  11         0           1974
## 2  10         0           1967
## 3   9         2           2015
## 4   8         3           2000
## 5   7         7           2012
## 6   6         5           2006
## 7   5         1           1973
## 8   4         4           2013
## 9   3         1           1989
## 10  2        10           2022
## 11  1        13           2023

Görüldüğü üzere BSL1 ve BSL2 veri setlerinde id ve ID değişkenleri aynıdır. Bu iki veri setindeki bilgiler bu değişkenler üzerinden birleştirilebilir.

merge(BSL1, BSL2, by.x = "id", by.y = "ID")
##    id           takim sampiyonluk ikincilik son_sapiyonluk
## 1   1    Anadolu Efes          16        13           2023
## 2   2      Fenerbahçe          10        10           2022
## 3   3      Eczacıbaşı           8         1           1989
## 4   4     Galatasaray           5         4           2013
## 5   5             İTÜ           5         1           1973
## 6   6       Ülkerspor           4         5           2006
## 7   7        Beşiktaş           2         7           2012
## 8   8           Tofaş           2         3           2000
## 9   9 Pınar Karşıyaka           2         2           2015
## 10 10       Altınordu           1         0           1967
## 11 11     Muhafızgücü           1         0           1974

Temel paketteki merge() fonksiyonu ile veri setlerinin birleştirilmesi yukarıda örneklendirilmiştir. Veri setlerini farklı şekilde birleştirme ile ilgili detaylı açıklamalar kitabın ‘Veri Setlerini Birleştirme’ bölümünde verilmiştir.

8.5.13 sub(), gsub() ve substr() Fonksiyonları

sub(), gsub() ve substr() fonksiyonları ile bir karakter vektöründeki ifade bulunabilir ve bu ifade istenen karakterler ile değiştirilebilir.

# ilk e harfini * ile değiştirme
sub("e", "*", "metehan")
## [1] "m*tehan"
# tüm e harflerini * ile değiştirme
gsub("e", "*", "metehan")
## [1] "m*t*han"
# kelimenin 1, 2, 3, ve 4. karakterini seçme
substr("metehan", 1, 4)
## [1] "mete"

Yukarıdaki örneklerden de anlaşıldığı üzere sub() fonksiyonu aranan ‘e’ ifadesini ilk bulduğu yeri ’*’ işareti ile değiştirmiştir. gsub() ise sub() fonksiyonunun genel halidir ve vektörde bulduğu tüm ifadeleri istenen işaret ile değiştirmiştir. substr() fonksiyonu ile ilgili karakterlerin 1’den 4’e kadar olan kısmı bir alt küme olarak alınmıştır.

8.5.14 grep() ve grepl() Fonksiyonları

grep() ve grepl() fonksiyonları ile bir nesne içindeki bazı spesifik karakterler bulunabilir. Örneğin, BAFTA ödülüne layık görülen filmlerin isimlerini ve türlerini inceleyelim.

# örneklendirmek için bir veri seti içe aktaralım.
BAFTA_film <- read.csv("https://raw.githubusercontent.com/gungorMetehan/BAFTA/main/BAFTA_film.csv")

# grep() yardımıyla filmler arasında adında 'la' ifadesi geçen filmlerin indekslerini bulalım.
grep("la", BAFTA_film$film)
## [1]  4 11 24 34 63
# grepl() yardımıyla film türleri arasında 'Drama' türünde olan filmleri bulmaya çalışalım.
grepl("Drama", BAFTA_film$genres)
##  [1]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
## [13]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
## [25]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
## [37]  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE
## [49]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE
## [61] FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
## [73]  TRUE  TRUE  TRUE  TRUE

grep() ve grepl() fonksiyonları benzer amaçlarla kullanılsa da, çıktılarının farklı olduğu görülecektir. grep() çıktı olarak ilgili satırların indekslerini verirken, grepl() her satırda aranan değerin bulunup bulunmadığına ilişkin mantıksal değerleri (TRUE ya da FALSE) verir.

BAFTA

BAFTA (British Academy of Film and Television Arts) Akademi Ödülleri’nin (Oscars) Birleşik Krallık’taki dengi olan ödül törenidir, her yıl düzenlenmektedir ve sinema, televizyon dallarında ödüller dağıtılır. Bu ödüller pek çok kategoride olabilir. Bunlardan bazıları şunlardır: en iyi film, en iyi yönetmen, en iyi kadın oyuncu, en iyi erkek oyuncu, en iyi yardımcı kadın oyuncu, en iyi yardımcı erkek oyuncu. Yıllara göre ödül alan filmler ile ilgili detaylı bilgiye organizasyonun web sitesinden ulaşılabilir.

8.5.15 Yuvarlama Fonksiyonları

R’da sayıları yuvarlamak için pek çok seçenek vardır. Bunlardan bazıları aşağıda listelenmiştir.

# beş tane gerçek (reel) sayıdan oluşan bir vektör oluşturalım
bes_gercek_sayi <- c(.5, 8, 3.99, 1.04, 9.86)

# round() ile yuvarlama yapılmaktadır. digits argümanına girilen değer virgülden sonra kaç tane basamak olmasını istediğimizi gösterir.
round(bes_gercek_sayi, digits = 1)
## [1] 0.5 8.0 4.0 1.0 9.9
# signif() fonksiyonu sayıları önemli görülen toplam basamak sayısı kadar yuvarlama yapar.
signif(bes_gercek_sayi, digits = 2)
## [1] 0.5 8.0 4.0 1.0 9.9
# ceiling() fonksiyonu vektördeki sayıları kendisine ya da üstündeki ilk tam sayıya yuvarlar.
ceiling(bes_gercek_sayi)
## [1]  1  8  4  2 10
# floor() fonksiyonu vektördeki sayıları kendisine ya da altındaki ilk tam sayıya yuvarlar.
floor(bes_gercek_sayi)
## [1] 0 8 3 1 9
# trunc() fonksiyonu vektördeki sayıların ondalık kısımlarını siler.
trunc(bes_gercek_sayi)
## [1] 0 8 3 1 9

8.6 Alıştırmalar

Alıştırma 1 Kendisine verilen bir \(k\) değerinin iki katından bir sayısını çıkaran bir fonksiyon yazınız.

Yanıt İçin Tıklayınız
F_1 <- function(k) {
  2*k - 1
  }

Alıştırma 2 matris_yeni <- matrix(c(1:100), nrow = 20, ncol = 5) komutunu çalıştırarak matris nesnesini oluşturunuz. Ardından apply() fonksiyonunu kullanarak bu matrisi tüm sütunlarının ortalamalarını hesaplayınız.

Yanıt İçin Tıklayınız
matris_yeni <- matrix(c(1:100), nrow = 20, ncol = 5)
apply(matris_yeni, 2, mean)
## [1] 10.5 30.5 50.5 70.5 90.5

Alıştırma 3 yeni_boy <- 175 komutunu çalıştırarak yeni_boy isimli nesneyi oluşturunuz. Ardından if() cümlesini kullanarak 165 değerine eşit veya büyük değerlerin ‘Uygun’ olarak ifade edilmesini sağlayınız.

Yanıt İçin Tıklayınız
yeni_boy <- 175

if (yeni_boy >= 165) { 
print("Uygun") 
}
## [1] "Uygun"

Alıştırma 4 for() döngüsünü kullanarak 1’den 10’a kadar olan tam sayıların küplerini yazdırınız.

Yanıt İçin Tıklayınız
y <- 1:10 
for (i in y) {
  print(i^3)
  }
## [1] 1
## [1] 8
## [1] 27
## [1] 64
## [1] 125
## [1] 216
## [1] 343
## [1] 512
## [1] 729
## [1] 1000