3. Ders - Döngüler

Yusuf Akbulut
2022-05-18

Vektörel İşlemler

R işlem yaparken vektörel işlemlerde eleman seviyesinde işlem yapar. Bu temelde n’ninci elemanın n’ninci elemanla işleme sokulmasıdır. Mesela aşağıdaki b vektörü ile c vektörü çapılırken b’nin 1. elemanı ile c’nin 1. elemanı, b’nin 2. elemanı ile c’nin 2. elemanı şeklinde çarpılarak ilerlenir.

b <-  c(1, 4, 7, 77)

c <-  c(3, 4, 2, 11)

b * c
[1]   3  16  14 847

Eğer vektörlerin eleman sayıları eşit değilse R otomatik olarak eleman sayısı az olan vektörün eleman sayısını uzun vektörün sayısına getirir. Mesela a vektörün d ile bir işleme sokulduğunda 5, 5, 5, 5, 5 şeklini alır. e vektörü ise 6, 7, 5, 6, 7 şeklini alır. Bu değişiklikleri de uyarı olarak çıktıda belirtir.

a <-  c(5)

d <-  c(2, 5, 2, 5, 8)

e <-  c(6, 7, 5)

a * d
[1] 10 25 10 25 40
d * e
[1] 12 35 10 30 56

Burada ek olarak küçük bir bilgi. Bir vektörün elemanını değiştirmek ya da eklemek istersek aşağıdaki notasyonu kullanırız.

z <- c(42, 22, 43)

z[2] <- 123

z
[1]  42 123  43

Tidyverse

https://www.tidyverse.org/

İçerisinde bir çok paketi bulunduran R kullanıını kolaylaştıran bir yaklaşım.

Bu kısımda kullanacağımız paketi ve veriyi yüklüyoruz. Eğer paketler sizde yüklü değilse başında # olan satırlardan # sembolünü silerek paketleri yükleyebilirsiniz

#install.packages("tidyverse")
#install.packages("nycflights13")

library(tidyverse)
library(nycflights13)

ucuslar <- flights
paged_table(ucuslar)

For döngüsü

For döngüleri elle tekrar tekrar yapma durumunda kaldığımız işlemleri otomatize etmemize yarıyor. Belirli bir sentaks takip edilerek oluşturulan bu döngü iki temel kısımdan oluşuyor.

  1. kısımda üzerinde gezmek istediğimiz vektörü (ya da üzerinde gezmeye uygun veri) belirtiyoruz.
  2. kısımda ise her adımda yapılacak işlemi belirtiyoruz.
median(ucuslar$distance)
[1] 872
median(ucuslar$dep_delay, na.rm = T)
[1] -2

burada uçuşlar verisinin her sütunu için medyan değerini bulmak istediğimizde hem uzun sürecek hem verimsiz olacaktır. Değişiklik yapmak istediğimizde her adım için ayrıca bu değişiklikleri gerçekleştirmemiz de cabası.

Bunun için döngüleri kullanıyoruz. Aşağıda kodun yanında döngü için gerekli basamaklar yazılı:

# üzerinde gezeceğimiz basit bir vektör oluşturduk.
notlar <- c(90, 20, 70, 60)

for (i in notlar) { # bu kısımda hangi veri üzerinde gezeceğimizi belirtiriyoruz
  print(i**2) # bu kısımda da her adımda ne yapacağımızı belirtiyoruz.
}
[1] 8100
[1] 400
[1] 4900
[1] 3600

Alıştırma: Notlar vektörü elemanlarının 7 ile bölümünden kalanları for döngüsü kullanarak hesaplayınız.

notlar <- c(90, 20, 70, 60)

for (i in notlar) {
  print(i %% 7)
}
[1] 6
[1] 6
[1] 0
[1] 4

Basit örnekten sonra biraz daha karmaşık bir örneğe daha bakacağız. Önce bir datafreame/tibble oluşturalım.

df <- tibble(
  a = rnorm(10),
  b = rnorm(10),
  c = rnorm(10),
  d = rnorm(10)
)

paged_table(df)

DataFrame sütunlarına aşağıdaki gibi iki şekilde ulaşabiliriz. Sütun sırası ya da ismi kullanılarak. Bu döngüde birinci versiyonu kullanacağız.

df[[1]]
df[[2]]
df[[3]]
df[[4]]


df$a
df$b
df$c
df$d

Tüm sütunların medyan değerlerini bulmak istediğimizi düşünelim.

median(df[[1]])
median(df[[2]])
median(df[[3]])
median(df[[4]])

Tabii ki bu şekilde tek tek yazmak yerine bir döngü kurmak daha kolay. Bu örnekte her sütunun medyan değerlerini bulup bir vektöre kaydedeceğiz. Bunun için önce boş ya da daha hızlı olması için yazdıracağımız eleman sayısı uzunluğunda “0”lardan oluşan bir vectör oluşturacağız.

output <- vector("double", ncol(df)) 

Vektör oluşturmanın bir çok şekli olmakla beraber ikinci kullanım döngüler için daha uygundur. Bu şekilde bir kullanımda dataframe’mizdeki sütun sayısından bağımsız bir şekilde döngü oluştururken daha hızlı bir döngü sistemi kurmuş oluyoruz.

Kullandığımız vector() fonksiyonu ilk argüman olarak tür ikinci argüman olarak da elaman sayısı almaktadır. Eleman sayısı yerine kullandığımız ncol() fonksiyonu dataframe’deki sütun sayısını vermektedir. Sonuçta oluşan vektör de “output” isimli bir vektöre kaydedilmektedir.

Yukarıdaki kodun Türkçesini “Verimdeki sütun sayısı kadar sıfırlardan oluşan bir vektör oluştur. Bunu da ‘output’ isimli değişkene yazdır.” olarak okuyabiliriz.

for (i in seq_along(df)) {        
  output[[i]] <- median(df[[i]])      
}

For döngüsünün asıl yapısına geldiğimizde iki kısımdan oluştuğunu belirtmiştik. Buradaki ilk kısımda üzerinde gezilecek veri kısmında yine bir fonsiyon görüyoruz. Bu fonksiyon bize 1’den n’ninci sayıya kadar (n dataframe’in sütun sayısı olmak üzere) bir vektör oluşturuyor. Daha sonra bu dataframe elemanlarını for döngüsünün ana gövdesinde sırası ile işleme sokuyoruz.

seq_along(df)
[1] 1 2 3 4

Üzerinde gezilen vektör aşağıdaki gibi oluşuyor. Her adımda da 1, 2 ,3 ve 4 ana gövdede ki “i” nin yerine sıra ile konularak kod çalıştırılıyor. Çıkan sonuç da daha önce oluşturduğumuz vektörün i’ye karşılık gelen sırasına yazılıyor. sonuç aşağıdaki gibi oluşuyor.

output
[1] -0.01324154 -0.17722229  0.09109897 -0.60604155

While döngüsü

While döngüsü for döngüsü ile çok benzer olmakla beraber ana fark 1. kısımdadır. While döngüsünde yapının birici kısmının TRUE ya da FALSE olmasına göre 2. kısmın çalışıp çalışmaması durumu vardır. Döngünün ilk kısmındaki ifadenin TRUE olduğu her durumda döngü çalışmaya devam eder. Sonsuz bir döngüye girmemesi için ana bölüme her seferinde değişecek bir parametre eklenir bununla bir süre sonra döngünün durması sağlanır.

aşağıdaki örnekte i’nin 1’e eşit olduğu durumda döngü başlıyor. her turda i 1 artıyor. i’nin altı olduğu durumda i<6 yanlış olduğu için döngü duruyor.

1 < 6
[1] TRUE
i <- 1
while (i < 6) {
  print(i)
  i <- i + 1
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5

Fonksiyonlar

R kullanırken temelde tüm işlemlerimiz fonksiyonları çalıştırmaktır. Her işlem bir fonksiyonun çalışması ve verdiği çıktının işlemesi üzerine devam eder.

Fonksiyon oluştururken de RStudio’nun snippet özelliğini kullanarak iskeletini otomatik olarak çekebiliriz. Fonksiyonlar 3 ana kısımdan oluşuyor.

  1. kısımda daha sonra fonksiyonu çağıracağımız isim belirleniyor.
  2. kısımda fonksiyonun alacağı değişkenler oluşturuluyor.
  3. kısımda bu değişkenlerin fonksiyon içerisinde ne tür işlemlerden geçeceği belirtiliyor.

Aşağıdaki örnekte a ve b değişkenleri alan ders_fnc bu iki değeri çarparak sonucunu veriyor.

ders_fnc <- function(a, b = 3) {
  a*b
}

Bu fonksiyonda b değeri varsayılan olarak 3 değerini alıyor. Eğer fonksiyona tek değer verilirse ikinci değeri 3 olarak varsayıyor. Aşağıda örnekleri görülebilir.

ders_fnc(6, 7)
[1] 42
ders_fnc(6)
[1] 18
mean(ucuslar$dep_time)
[1] NA
mean(ucuslar$dep_time, na.rm = T)
[1] 1349.11
ncol(ucuslar)
[1] 19

select fonksiyonu

select() fonksiyonu verimizin sütunlarını seçme işlevi görüyor.

select(ucuslar, year, month, day, dep_time)
# A tibble: 336,776 × 4
    year month   day dep_time
   <int> <int> <int>    <int>
 1  2013     1     1      517
 2  2013     1     1      533
 3  2013     1     1      542
 4  2013     1     1      544
 5  2013     1     1      554
 6  2013     1     1      554
 7  2013     1     1      555
 8  2013     1     1      557
 9  2013     1     1      557
10  2013     1     1      558
# … with 336,766 more rows

Seçmek istediğimiz sütunları tek tek yazmakla beraber yardımcı fonksiyonlar da kullanabiliriz. contains() fonksiyonu sütün isminde geçen karakterlere göre filtreleme yapamaktadır.

select(ucuslar, contains("arr"))
# A tibble: 336,776 × 4
   arr_time sched_arr_time arr_delay carrier
      <int>          <int>     <dbl> <chr>  
 1      830            819        11 UA     
 2      850            830        20 UA     
 3      923            850        33 AA     
 4     1004           1022       -18 B6     
 5      812            837       -25 DL     
 6      740            728        12 UA     
 7      913            854        19 B6     
 8      709            723       -14 EV     
 9      838            846        -8 B6     
10      753            745         8 AA     
# … with 336,766 more rows

starts_with() fonksiyonu sütun isminin başlangıcı ends_with() fonksiyonu ise sütun isminin sonuna göre filtreleme yapmamızı sağlamaktadır.

select(ucuslar, starts_with("dep"))
# A tibble: 336,776 × 2
   dep_time dep_delay
      <int>     <dbl>
 1      517         2
 2      533         4
 3      542         2
 4      544        -1
 5      554        -6
 6      554        -4
 7      555        -5
 8      557        -3
 9      557        -3
10      558        -2
# … with 336,766 more rows
select(ucuslar, ends_with("time"))
# A tibble: 336,776 × 5
   dep_time sched_dep_time arr_time sched_arr_time air_time
      <int>          <int>    <int>          <int>    <dbl>
 1      517            515      830            819      227
 2      533            529      850            830      227
 3      542            540      923            850      160
 4      544            545     1004           1022      183
 5      554            600      812            837      116
 6      554            558      740            728      150
 7      555            600      913            854      158
 8      557            600      709            723       53
 9      557            600      838            846      140
10      558            600      753            745      138
# … with 336,766 more rows

filter fonksiyonu

filter fonksiyonu satırlar bazında filtreleme yapmamızı sağlamaktadır. Bunun için filtreleme yapmak istediğimiz sütunda bir mantıksal ifade kullanmamız gerekiyor. Aşağıdaki 1. örnekte sayısal değerlerden oluşan bir sütun için > ifadesi kullanılmıştır. arr_değeri 33’ten büyük olan satırları getirmektedir. 2. örnekte ise metin verisi tutan sütunda “UA” ifadesine eşit olan satırlar filtrelenmiştir.

filter(ucuslar, arr_delay > 33)
# A tibble: 47,962 × 19
    year month   day dep_time sched_dep_time dep_delay arr_time
   <int> <int> <int>    <int>          <int>     <dbl>    <int>
 1  2013     1     1      635            635         0     1028
 2  2013     1     1      702            700         2     1058
 3  2013     1     1      749            710        39      939
 4  2013     1     1      811            630       101     1047
 5  2013     1     1      826            715        71     1136
 6  2013     1     1      848           1835       853     1001
 7  2013     1     1      903            820        43     1045
 8  2013     1     1      905            905         0     1309
 9  2013     1     1      933            904        29     1252
10  2013     1     1      953            921        32     1320
# … with 47,952 more rows, and 12 more variables:
#   sched_arr_time <int>, arr_delay <dbl>, carrier <chr>,
#   flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
#   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>,
#   time_hour <dttm>
filter(ucuslar, carrier == "UA")
# A tibble: 58,665 × 19
    year month   day dep_time sched_dep_time dep_delay arr_time
   <int> <int> <int>    <int>          <int>     <dbl>    <int>
 1  2013     1     1      517            515         2      830
 2  2013     1     1      533            529         4      850
 3  2013     1     1      554            558        -4      740
 4  2013     1     1      558            600        -2      924
 5  2013     1     1      558            600        -2      923
 6  2013     1     1      559            600        -1      854
 7  2013     1     1      607            607         0      858
 8  2013     1     1      611            600        11      945
 9  2013     1     1      623            627        -4      933
10  2013     1     1      628            630        -2     1016
# … with 58,655 more rows, and 12 more variables:
#   sched_arr_time <int>, arr_delay <dbl>, carrier <chr>,
#   flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
#   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>,
#   time_hour <dttm>

arrange fonksiyonu

arrange() fonksionu satırları büyükten küçüğe ya da küçükten büyüğe sıralamaya yaramaktadır. Eğer birden fazla sütun ismi verilirse ilkinde eşit durumda olan satırları sonrakilere göre sıralıyor. desc() fonksiyonu içinde kalanları büyükten küçüğe diğerlerini küçükten büyüğe sıralıyor.

arrange(ucuslar, arr_delay, dep_delay, desc(day))
# A tibble: 336,776 × 19
    year month   day dep_time sched_dep_time dep_delay arr_time
   <int> <int> <int>    <int>          <int>     <dbl>    <int>
 1  2013     5     7     1715           1729       -14     1944
 2  2013     5    20      719            735       -16      951
 3  2013     5     6     1826           1830        -4     2045
 4  2013     5     2     1947           1949        -2     2209
 5  2013     5     4     1816           1820        -4     2017
 6  2013     5     2     1926           1929        -3     2157
 7  2013     5    13      657            700        -3      908
 8  2013     5     6     1753           1755        -2     2004
 9  2013     5     7     2054           2055        -1     2317
10  2013     5     3      616            630       -14      803
# … with 336,766 more rows, and 12 more variables:
#   sched_arr_time <int>, arr_delay <dbl>, carrier <chr>,
#   flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
#   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>,
#   time_hour <dttm>

%>% (Pipe)

Bu sembol R’daki değişkenleri bir sonraki fonksiyona taşımaya yarıyor. tidyverse paketinin bir fonksiyonu olan pipe daha temiz ve anlaşılır bir kod ile çalışma imkanı sağlıyor.

Aşağıdaki örneklerde olduğu gibi ucuslar verisi önce filter() sonra arrange() fonksiyonlarına aktarılıyor.

arr_33 <- filter(ucuslar, arr_delay > 33)
arrange(arr_33, desc(arr_delay))

ucuslar %>% 
  filter(arr_delay > 33) %>% 
  arrange(desc(arr_delay))

Atölye Alıştırmaları

ucuslar %>%
  filter(month == 1) %>% 
  select(dep_time, sched_dep_time, arr_time, sched_arr_time)

ucuslar_ort <- ucuslar %>%
  filter(month == 1) %>% 
  select(contains("time")) %>% 
  select(-air_time, -time_hour)

vector <- c(1, 2, 3, 4)

for (i in vector) {
  print(names(ucuslar_ort)[i])
  print((mean(ucuslar_ort[[i]], na.rm = T)))
}
sonuclar <- c()

sonuclar[]

for (i in seq_along(ucuslar_ort)) {
 sonuclar[i] <- mean(ucuslar_ort[[i]], na.rm = T)
}

sonuclar
sonuclar <- vector("double", 4)


for (i in seq_along(ucuslar_ort)) {
 sonuclar[i] <- mean(ucuslar_ort[[i]], na.rm = T)
}

sonuclar

ucuslar_ort[[1]]