5 > 3[1] TRUE
10 == 7[1] FALSE
8 != 2[1] TRUE
Programlama yalnızca komutları arka arkaya yazmak değildir. Programlama esas olarak bir problemi küçük adımlara ayırmak, hangi durumda ne yapılacağını belirlemek ve tekrar eden işleri sistematik hale getirmektir. Bu nedenle karar yapıları ve döngüler, programlama mantığının omurgasını oluşturur.
Günlük hayatta sürekli karar veririz:
Bilgisayar programları da benzer mantıkla çalışır. Ancak bilgisayarın karar verebilmesi için koşulların açıkça tanımlanması gerekir. R’de bu amaçla kullanılan temel yapılar şunlardır:
ifelseelse ififelse()forwhilerepeatbreaknextBu bölümde bu yapıların yalnızca nasıl yazıldığını değil, hangi mantıkla çalıştığını, ne zaman tercih edilmesi gerektiğini ve sık yapılan hataları ele alacağız.
Bir R kodu normalde yukarıdan aşağıya doğru çalışır. Ancak bazı durumlarda bu akışı değiştirmek isteriz.
Örneğin:
1. Veriyi oku
2. Eğer veri eksikse uyarı ver
3. Eksik değilse analize devam et
4. Her değişken için özet istatistik hesapla
5. Sonucu raporlaBu tarz yapılarda iki temel ihtiyaç ortaya çıkar:
Karar yapıları bir programın “mantık kapılarıdır”. Döngüler ise programın “tekrarlayan iş gücüdür”. Yani biri ne yapılacağına karar verir, diğeri yapılacak işi tekrar eder.
R’de karar yapıları mantıksal sonuçlara dayanır. Bir koşul genellikle TRUE veya FALSE üretir.
5 > 3[1] TRUE
10 == 7[1] FALSE
8 != 2[1] TRUE
Burada kullanılan temel karşılaştırma operatörleri şunlardır:
| Operatör | Anlamı |
|---|---|
> |
büyüktür |
< |
küçüktür |
>= |
büyük eşittir |
<= |
küçük eşittir |
== |
eşittir |
!= |
eşit değildir |
Dikkat edilmesi gereken önemli nokta şudur: R’de eşitlik kontrolü için == kullanılır. Tek eşittir işareti (=) genellikle atama için kullanılır. Bu ayrım yeni başlayanlar için küçük ama kritik bir ayrımdır.
x <- 10
# x değeri 10'a eşit mi?
x == 10[1] TRUE
Birden fazla koşulu birlikte değerlendirmek için mantıksal operatörler kullanılır.
| Operatör | Anlamı |
|---|---|
& |
ve |
| |
veya |
! |
değil |
yas <- 25
gelir <- 40000
# Hem yaş 18 veya üzeri olsun hem gelir 30000'den büyük olsun.
yas >= 18 & gelir > 30000[1] TRUE
sehir <- "Ankara"
# Şehir Ankara veya İstanbul mu?
sehir == "Ankara" | sehir == "İstanbul"[1] TRUE
mezun <- FALSE
# Mezun değil mi?
!mezun[1] TRUE
Bu operatörler if, ifelse() ve döngü koşullarında sık kullanılır.
if Yapısıif, tek bir koşulu kontrol etmek için kullanılır. Koşul doğruysa kod bloğu çalışır. Yanlışsa çalışmaz.
not <- 75
if (not >= 50) {
print("Dersi geçti")
}[1] "Dersi geçti"
Genel yapı şöyledir:
if (koşul) {
# koşul TRUE ise çalışacak kod
}Burada dikkat edilmesi gereken noktalar:
{} içine yazılır.TRUE ise blok çalışır.FALSE ise blok atlanır.yas <- 16
if (yas >= 18) {
print("Oy kullanabilir")
}Bu örnekte herhangi bir çıktı oluşmaz. Çünkü koşul FALSE değerini üretir.
Tek satırlık örneklerde süslü parantez kullanılmadan da kod yazılabilir. Ancak özellikle öğretici, okunabilir ve sürdürülebilir kod yazmak için süslü parantez kullanmak iyi bir alışkanlıktır.
# Önerilen yazım
if (5 > 3) {
print("Koşul doğru")
}[1] "Koşul doğru"
Kod büyüdükçe süslü parantez kullanmamak hata riskini artırır. Programlama biraz da gelecekteki kendine iyilik yapma sanatıdır.
if ... else YapısıKoşul doğruysa bir işlem, yanlışsa başka bir işlem yapılacaksa else kullanılır.
not <- 42
if (not >= 50) {
print("Geçti")
} else {
print("Kaldı")
}[1] "Kaldı"
Bu yapıda iki olasılık vardır:
TRUE ise if bloğu çalışır.FALSE ise else bloğu çalışır.Aynı anda ikisi birden çalışmaz.
Şu ifadeyi düşünelim:
Eğer hava yağmurluysa şemsiye al, değilse normal çık.
Bunu R ile şöyle yazabiliriz:
hava <- "yağmurlu"
if (hava == "yağmurlu") {
print("Şemsiye al")
} else {
print("Normal çık")
}[1] "Şemsiye al"
Bu örnekte hava == "yağmurlu" ifadesi TRUE olduğu için ilk blok çalışır.
else if YapısıBazı durumlarda iki seçenek yeterli olmaz. Birden fazla olasılığı sırayla kontrol etmek için else if kullanılır.
puan <- 82
if (puan >= 90) {
print("Harf notu: A")
} else if (puan >= 80) {
print("Harf notu: B")
} else if (puan >= 70) {
print("Harf notu: C")
} else if (puan >= 50) {
print("Harf notu: D")
} else {
print("Harf notu: F")
}[1] "Harf notu: B"
Bu yapı yukarıdan aşağıya çalışır. İlk doğru koşul bulunduğunda ilgili blok çalışır ve kalan koşullar kontrol edilmez.
else if yapısında koşulların sırası kritik öneme sahiptir.
puan <- 95
if (puan >= 50) {
print("Geçti")
} else if (puan >= 90) {
print("Çok başarılı")
}[1] "Geçti"
Bu kod "Geçti" sonucunu üretir. Çünkü puan >= 50 koşulu zaten doğrudur ve R daha aşağıdaki puan >= 90 koşuluna bakmaz.
Daha doğru yapı şöyle olmalıdır:
puan <- 95
if (puan >= 90) {
print("Çok başarılı")
} else if (puan >= 50) {
print("Geçti")
} else {
print("Kaldı")
}[1] "Çok başarılı"
Genel ilke: Daha özel ve dar koşullar önce yazılmalıdır.
if Kullanımı Konusunda Dikkatif yapısı tek bir TRUE veya FALSE bekler. Vektörel koşullarda doğrudan kullanılmamalıdır.
notlar <- c(45, 60, 80)
# Bu kullanım hatalıdır veya beklenmeyen uyarı üretir:
# if (notlar >= 50) {
# print("Geçti")
# }Burada notlar >= 50 ifadesi tek bir TRUE/FALSE değil, birden fazla mantıksal değer üretir.
notlar >= 50[1] FALSE TRUE TRUE
Vektörel kararlar için ifelse() kullanmak daha uygundur.
ifelse() Fonksiyonuifelse() fonksiyonu, bir vektörün her elemanı için koşul kontrolü yapar.
notlar <- c(45, 60, 80, 30)
ifelse(notlar >= 50, "Geçti", "Kaldı")[1] "Kaldı" "Geçti" "Geçti" "Kaldı"
Genel yapı şöyledir:
ifelse(test, yes, no)Argümanlar:
test: Kontrol edilecek koşulyes: Koşul doğruysa dönecek değerno: Koşul yanlışsa dönecek değer# Sayısal kodlama örneği
basari_kodu <- ifelse(notlar >= 50, 1, 0)
basari_kodu[1] 0 1 1 0
Bu fonksiyon özellikle veri çerçevelerinde yeni değişken oluştururken kullanışlıdır.
ogrenci <- data.frame(
ad = c("Ali", "Ayşe", "Mehmet", "Zeynep"),
not = c(45, 72, 88, 39)
)
# Yeni bir başarı durumu değişkeni oluşturalım.
ogrenci$durum <- ifelse(ogrenci$not >= 50, "Geçti", "Kaldı")
ogrenciifelse()Birden fazla kategori üretmek için iç içe ifelse() kullanılabilir.
puan <- c(95, 82, 67, 40)
harf <- ifelse(
puan >= 90, "A",
ifelse(
puan >= 80, "B",
ifelse(
puan >= 70, "C",
ifelse(puan >= 50, "D", "F")
)
)
)
harf[1] "A" "B" "D" "F"
Bu yapı küçük örneklerde işe yarar. Ancak kategori sayısı arttıkça okunabilirlik düşer. Bu nedenle daha büyük projelerde dplyr::case_when() gibi daha okunabilir alternatifler tercih edilebilir.
for Döngüsü Nedir?for döngüsü, belirli bir dizi elemanın her biri için aynı işlemi tekrar etmek amacıyla kullanılır.
Örneğin:
Genel yapı şöyledir:
for (i in vektor) {
# her adımda çalışacak kod
}Burada i geçici bir değişkendir. Döngünün her adımında vektor içindeki sıradaki değeri alır.
for Döngüsüfor (i in 1:5) {
print(i)
}[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
Bu döngüde:
i = 1i = 2i = 5olur.
Döngü tamamlandığında işlem biter.
for (i in 1:5) {
kare <- i^2
print(kare)
}[1] 1
[1] 4
[1] 9
[1] 16
[1] 25
Bu örnekte her adımda i değerinin karesi hesaplanır.
Ancak burada önemli bir sorun vardır: sonuçlar sadece ekrana yazdırılır, bir nesnede saklanmaz. Analizde çoğu zaman sonuçları saklamak isteriz.
Döngü çıktılarının saklanması için önce uygun uzunlukta boş bir nesne oluşturmak iyi bir yaklaşımdır.
# numeric(5), uzunluğu 5 olan boş sayısal vektör oluşturur.
sonuc <- numeric(5)
for (i in 1:5) {
sonuc[i] <- i^2
}
sonuc[1] 1 4 9 16 25
Bu yöntem daha düzenlidir. Özellikle büyük döngülerde her adımda nesneyi büyütmek yerine baştan yer ayırmak daha sağlıklı bir alışkanlıktır.
Döngüler yalnızca sayılarla çalışmaz. Karakter vektörleri üzerinde de kullanılabilir.
isimler <- c("Ali", "Ayşe", "Mehmet")
for (isim in isimler) {
mesaj <- paste("Merhaba", isim)
print(mesaj)
}[1] "Merhaba Ali"
[1] "Merhaba Ayşe"
[1] "Merhaba Mehmet"
Bu örnekte isim değişkeni her adımda isimler vektöründeki sıradaki değeri alır.
Bazı durumlarda yalnızca elemanın kendisine değil, konumuna da ihtiyaç duyarız. Bu durumda indeks üzerinden döngü kurabiliriz.
notlar <- c(45, 72, 88)
for (i in seq_along(notlar)) {
print(paste(i, ". gözlem:", notlar[i]))
}[1] "1 . gözlem: 45"
[1] "2 . gözlem: 72"
[1] "3 . gözlem: 88"
Burada seq_along(notlar), notlar vektörünün uzunluğu kadar güvenli bir sıra üretir. 1:length(notlar) yerine çoğu durumda seq_along() daha güvenli bir tercihtir.
for ve if Birlikte KullanımıDöngü içinde karar yapıları sık kullanılır.
notlar <- c(45, 72, 88, 39)
durum <- character(length(notlar))
for (i in seq_along(notlar)) {
if (notlar[i] >= 50) {
durum[i] <- "Geçti"
} else {
durum[i] <- "Kaldı"
}
}
durum[1] "Kaldı" "Geçti" "Geçti" "Kaldı"
Bu kod, her not için ayrı ayrı koşul kontrolü yapar.
Aynı işlem ifelse() ile daha kısa yapılabilir:
ifelse(notlar >= 50, "Geçti", "Kaldı")[1] "Kaldı" "Geçti" "Geçti" "Kaldı"
Bu nedenle R’de şu soru her zaman sorulmalıdır:
Bu işlem için gerçekten döngüye ihtiyacım var mı, yoksa vektörel bir çözüm daha uygun mu?
df <- data.frame(
isim = c("Ali", "Ayşe", "Mehmet", "Zeynep"),
not = c(45, 72, 88, 39)
)
df$durum <- ""
for (i in seq_len(nrow(df))) {
if (df$not[i] >= 50) {
df$durum[i] <- "Geçti"
} else {
df$durum[i] <- "Kaldı"
}
}
dfBurada seq_len(nrow(df)), veri çerçevesindeki satır sayısı kadar güvenli bir sıra üretir.
Bir şirkette çalışanlara performans puanına göre prim verildiğini düşünelim:
| Performans puanı | Prim |
|---|---|
| 90 ve üzeri | 5000 |
| 75-89 | 3000 |
| 60-74 | 1500 |
| 60 altı | 0 |
puan <- c(95, 82, 70, 55, 91)
prim <- numeric(length(puan))
for (i in seq_along(puan)) {
if (puan[i] >= 90) {
prim[i] <- 5000
} else if (puan[i] >= 75) {
prim[i] <- 3000
} else if (puan[i] >= 60) {
prim[i] <- 1500
} else {
prim[i] <- 0
}
}
data.frame(puan, prim)Bu örnek, for, if, else if ve sonuç saklama mantığını birlikte gösterir.
while Döngüsüwhile döngüsü, belirli bir koşul doğru olduğu sürece çalışır.
Genel yapı şöyledir:
while (koşul) {
# koşul TRUE olduğu sürece çalışacak kod
}for döngüsünde tekrar sayısı çoğu zaman baştan bellidir. while döngüsünde ise tekrar sayısı koşula bağlıdır.
i <- 1
while (i <= 5) {
print(i)
i <- i + 1
}[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
Burada i değeri 5’e ulaşana kadar döngü devam eder.
while Döngüsünde Dikkat: Sonsuz Döngüwhile döngülerinde koşulu değiştiren bir adım bulunmazsa döngü sonsuza kadar çalışabilir.
# DİKKAT: Bu kod sonsuz döngüye girer.
# i <- 1
# while (i <= 5) {
# print(i)
# }Doğru kullanımda sayaç güncellenmelidir.
i <- 1
while (i <= 5) {
print(i)
i <- i + 1 # sayaç güncelleniyor
}[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
Sonsuz döngü programlamanın “çay koydum geliyorum” hatasıdır; kod dönmeye devam eder, siz beklersiniz.
while Kullanım Örneği: Hedefe Ulaşana Kadar BirikimBir kişinin her ay 1000 TL biriktirdiğini ve 5000 TL hedefe ulaşmak istediğini düşünelim.
birikim <- 0
ay <- 0
while (birikim < 5000) {
birikim <- birikim + 1000
ay <- ay + 1
}
ay[1] 5
birikim[1] 5000
Bu örnekte kaç tekrar yapılacağı başta açıkça yazılmamıştır. Döngü hedefe ulaşıldığında durmuştur.
repeat Döngüsürepeat döngüsü, açıkça durdurulana kadar çalışır. Bu nedenle içinde genellikle break kullanılır.
Genel yapı şöyledir:
repeat {
# çalışacak kod
if (durdurma_koşulu) {
break
}
}Basit bir örnek:
i <- 1
repeat {
print(i)
i <- i + 1
if (i > 5) {
break
}
}[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
repeat, koşulun döngünün başında değil, döngü içinde kontrol edilmesi gereken durumlarda kullanılabilir. Ancak dikkatli kullanılmalıdır; çünkü break unutulursa sonsuz döngü oluşur.
break Kullanımıbreak, döngüyü tamamen sonlandırır.
for (i in 1:10) {
if (i == 6) {
break
}
print(i)
}[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
Bu örnekte i değeri 6 olduğunda döngü durur. Bu nedenle 6 ve sonrası yazdırılmaz.
break, istenen koşul bulunduğunda aramayı durdurmak için kullanılabilir.
sayilar <- c(3, 8, 12, 5, 20)
for (s in sayilar) {
if (s > 10) {
print(paste("10'dan büyük ilk sayı:", s))
break
}
}[1] "10'dan büyük ilk sayı: 12"
next Kullanımınext, döngünün o adımını atlar ve bir sonraki adıma geçer.
for (i in 1:5) {
if (i == 3) {
next
}
print(i)
}[1] 1
[1] 2
[1] 4
[1] 5
Bu örnekte 3 yazdırılmaz; çünkü i == 3 olduğunda next çalışır ve döngü bir sonraki adıma geçer.
next, belirli gözlemleri işlem dışı bırakmak için kullanılabilir.
notlar <- c(80, NA, 65, 90)
for (n in notlar) {
if (is.na(n)) {
next
}
print(paste("Not:", n))
}[1] "Not: 80"
[1] "Not: 65"
[1] "Not: 90"
Burada eksik değer olan adım atlanır.
| Yapı | Ne zaman kullanılır? |
|---|---|
for |
Tekrar sayısı veya üzerinde dönülecek nesne belliyse |
while |
Koşul sağlandığı sürece devam edilecekse |
repeat |
Döngü en az bir kez çalışacak ve durdurma içeride yapılacaksa |
break |
Döngüyü erken bitirmek gerekiyorsa |
next |
Sadece mevcut adımı atlamak gerekiyorsa |
ifelse() |
Vektörel karar üretilecekse |
R’de çoğu veri analizi işlemi vektörel fonksiyonlarla daha kısa ve okunabilir yazılabilir. Ancak döngüler programlama mantığını öğrenmek ve daha genel problemleri çözmek için vazgeçilmezdir.
Bir üretim sürecinde ölçüm değerleri olsun. Ölçüm 100’den büyükse “kontrol gerekli”, 100 veya altındaysa “uygun” diyelim. Eksik değerler varsa bunları atlayalım.
olcumler <- c(95, 102, NA, 88, 110, 99)
sonuc <- character(length(olcumler))
for (i in seq_along(olcumler)) {
if (is.na(olcumler[i])) {
sonuc[i] <- "Eksik"
next
}
if (olcumler[i] > 100) {
sonuc[i] <- "Kontrol gerekli"
} else {
sonuc[i] <- "Uygun"
}
}
data.frame(olcum = olcumler, sonuc = sonuc)Bu örnekte:
for ile her ölçüm üzerinde dönüldü,is.na() ile eksik değer kontrol edildi,next ile eksik değerler için sonraki adıma geçildi,if/else ile kalite durumu üretildi.Aylık satış değerleri verilsin. Toplam satış 1000’i geçtiği ilk ayı bulalım.
satis <- c(120, 180, 250, 300, 220, 150)
toplam <- 0
hedef_ay <- NA
for (i in seq_along(satis)) {
toplam <- toplam + satis[i]
if (toplam >= 1000) {
hedef_ay <- i
break
}
}
hedef_ay[1] 5
toplam[1] 1070
Burada break kullanılmasının nedeni, hedefe ulaşıldıktan sonra kalan ayları kontrol etmeye gerek olmamasıdır.
= ile == Karıştırmakx <- 5
# Doğru eşitlik kontrolü
x == 5[1] TRUE
= veya <- atama için, == karşılaştırma için kullanılır.
puan <- 95
if (puan >= 50) {
print("Geçti")
} else if (puan >= 90) {
print("Çok başarılı")
}[1] "Geçti"
Bu örnekte ikinci koşula hiç ulaşılmaz. Koşullar özelden genele doğru yazılmalıdır.
for (i in 1:3) {
print(i^2)
}[1] 1
[1] 4
[1] 9
Bu kod çıktıyı ekrana verir ama saklamaz. Analiz için çoğu zaman sonuçların bir nesnede tutulması gerekir.
# i güncellenmediği için sonsuz döngü oluşur.
# i <- 1
# while (i <= 5) {
# print(i)
# }R vektörel bir dildir. Bazı işlemler döngüsüz daha doğal yazılır.
notlar <- c(45, 60, 80)
# Döngüsüz çözüm
ifelse(notlar >= 50, "Geçti", "Kaldı")[1] "Kaldı" "Geçti" "Geçti"
Aşağıdaki vektör üzerinden soruları cevaplayınız.
notlar <- c(45, 78, 91, 66, 52, 39, NA)ifelse() ile “Geçti / Kaldı” değişkeni üretiniz.for döngüsü ile notların karelerini hesaplayınız.next ile atlayarak yalnızca geçerli notları yazdırınız.while döngüsü ile 1’den 10’a kadar sayıları yazdırınız.repeat döngüsü ile 1’den 5’e kadar sayıları yazdırınız.notlar <- c(45, 78, 91, 66, 52, 39, NA)
# 1. Geçti / Kaldı
ifelse(notlar >= 50, "Geçti", "Kaldı")[1] "Kaldı" "Geçti" "Geçti" "Geçti" "Geçti" "Kaldı" NA
# 2. Harf notu
harf <- ifelse(
notlar >= 90, "A",
ifelse(
notlar >= 80, "B",
ifelse(
notlar >= 70, "C",
ifelse(notlar >= 50, "D", "F")
)
)
)
harf[1] "F" "C" "A" "D" "D" "F" NA
# 3. Kare hesaplama
kare <- numeric(length(notlar))
for (i in seq_along(notlar)) {
kare[i] <- notlar[i]^2
}
kare[1] 2025 6084 8281 4356 2704 1521 NA
# 4. 80 üzeri notları yazdırma
for (n in notlar) {
if (!is.na(n) && n > 80) {
print(n)
}
}[1] 91
# 5. Eksik değerleri atlama
for (n in notlar) {
if (is.na(n)) {
next
}
print(n)
}[1] 45
[1] 78
[1] 91
[1] 66
[1] 52
[1] 39
# 6. Ortalama nottan büyük olanları işaretleme
ortalama <- mean(notlar, na.rm = TRUE)
ifelse(notlar > ortalama, "Ortalama üstü", "Ortalama altı veya eşit")[1] "Ortalama altı veya eşit" "Ortalama üstü"
[3] "Ortalama üstü" "Ortalama üstü"
[5] "Ortalama altı veya eşit" "Ortalama altı veya eşit"
[7] NA
# 7. while döngüsü
i <- 1
while (i <= 10) {
print(i)
i <- i + 1
}[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
# 8. repeat döngüsü
i <- 1
repeat {
print(i)
i <- i + 1
if (i > 5) {
break
}
}[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
Bu bölümde R’de karar yapıları ve döngülerin temel mantığını ele aldık.
Öne çıkan noktalar şunlardır:
if, tek bir koşula bağlı işlem yapmak için kullanılır.else, koşul sağlanmadığında alternatif işlem tanımlar.else if, birden fazla koşulu sırayla kontrol eder.ifelse(), vektörel karar üretmek için kullanılır.for, belirli bir nesnenin elemanları üzerinde tekrar yapmak için uygundur.while, koşul doğru olduğu sürece çalışır.repeat, açıkça durdurulana kadar çalışır.break, döngüyü tamamen bitirir.next, yalnızca mevcut döngü adımını atlar.Karar yapıları ve döngüler, programlama dilinin yalnızca teknik ayrıntıları değildir. Bunlar bir problemi mantıksal adımlara ayırmanın araçlarıdır. Bir problemi doğru koşullara ve tekrar eden işlemlere bölebiliyorsanız, onu kodla ifade etmeniz çok daha kolay hale gelir.