Veri Manipülasyonu Felsefesi: tidyverse ve dplyr

R ile veri manipülasyonu yapmanın birçok yolu vardır, ancak modern R yaklaşımında bu işin kalbinde tidyverse adı verilen bir felsefe ve paketler topluluğu yatar.

tidyverse Nedir? tidyverse, Hadley Wickham ve ekibi tarafından geliştirilen, veri biliminin her aşaması için tasarlanmış ve birbiriyle uyum içinde çalışan R paketlerinden oluşan bir koleksiyondur (The Tidyverse Team, n.d.). Bu paketlerin ortak bir felsefesi vardır: Kodu daha okunabilir, daha sezgisel ve daha insancıl hale getirmek.

Bu ekosistemin veri manipülasyonu için kullandığı İsviçre çakısı ise dplyr paketidir (Wickham vd., 2023).

dplyr: Veri için Bir Gramer

dplyr, veri manipülasyonunu birkaç temel “fiil” (verb) üzerine kurarak karmaşık işlemleri basitleştirir. Her bir fiil, çok spesifik ve kolay anlaşılır bir görevi yerine getirir. İşte en temel dplyr fiilleri:

Cümleleri Birleştiren Yapı: Pipe Operatörü (%>%)

Bu fiilleri birer kelime olarak düşünürsek, bu kelimeleri anlamlı cümlelere dönüştüren bağlaç ise pipe (boru) operatörüdür (%>%). Pipe operatörü, bir komutun çıktısını, bir sonraki komutun ilk girdisi olarak “borular”. Bu sayede, iç içe geçmiş karmaşık fonksiyonlar yerine, adım adım okunan, anlaşılır bir iş akışı oluşturabiliriz.

Örneğin: veriyi al %>% sonra satırları filtrele %>% sonra yeni bir sütun oluştur

Bu teorik temel, birazdan göreceğimiz kod örneklerini anlamamız için bize sağlam bir zemin hazırlayacak. Şimdi bu güçlü fiillerin pratikte nasıl çalıştığını keşfetmeye hazırız!

Meraklısı İçin Bir Not: İki Farklı “Boru” Operatörü (%>% vs |>)

Serimiz boyunca, tidyverse dünyasının vazgeçilmezi olan %>% (magrittr pipe) operatörünü kullanacağız. Ancak R’ın 4.1.0 sürümü ile birlikte, R’ın kendi içine yerleşik yeni bir “pipe” operatörü daha geldi: |> (base R pipe).

Peki bu ikisi arasında ne fark var ve biz neden %>% kullanmayı tercih ediyoruz?

Özellik / Fark %>% (magrittr / Tidyverse Pipe) |> (Base R / Yerel Pipe)
Kaynak magrittr paketinden gelir (ve tidyverse ile yüklenir). R 4.1.0 ve üzeri sürümlerde R’ın kendi içinde yerleşiktir. Ek paket gerektirmez.
Hız Bir R fonksiyonu olduğu için çok küçük bir miktar ek yükü vardır. R’ın çekirdeğinde (C dilinde) yazıldığı için genellikle daha hızlıdır.
En Önemli Fark: Yer Tutucu (.) Sol taraftaki verinin, sağdaki fonksiyonda nereye gideceğini belirtmek için . yer tutucusunu kullanmamıza izin verir. Bu, inanılmaz esneklik sağlar. . yer tutucusunu desteklemez. Sol taraftaki veri, sağdaki fonksiyonun her zaman ilk argümanı olmak zorundadır.

Neden . Yer Tutucusu Bu Kadar Önemli?

Bazı fonksiyonlar, veri setini ilk argüman olarak almaz. Örneğin, bir lineer model kuran lm() fonksiyonu, ilk argüman olarak formula’yı (formül) alır.

%>% ile . sayesinde bu sorunu kolayca çözeriz:

# Beygir gücünü, diğer tüm değişkenlere göre modelle
# Nokta (.) "diğer tüm değişkenler" anlamına gelir.
cars_data %>%
  lm(hp ~ ., data = .) 

Burada . yer tutucusu sayesinde, cars_data’yı lm() fonksiyonunun data argümanına başarıyla “boruladık”.

Ancak |> ile bu mümkün değildir:

# Bu kod HATA VERECEKTİR!
cars_data |>
  lm(hp ~ ., data = .) # HATA: |> operatörü '.' yer tutucusunu anlamaz.

Serimiz İçin Kararımız

Her ne kadar |> R’ın geleceği için heyecan verici bir gelişme olsa da, bu seride aşağıdaki nedenlerden dolayı tidyverse’ün standartı olan %>% ile devam edeceğiz:

  1. Fonksiyonellik: . yer tutucusu, dplyr iş akışlarının ötesine geçen daha karmaşık analizlerde vazgeçilmez bir esneklik sunar.
  2. Yaygınlık: İnternette, kitaplarda ve Stack Overflow’da bulacağınız R kodlarının çok büyük bir çoğunluğu %>% kullanır. Bunu öğrenmek, R ekosistemini anlamanızı kolaylaştırır.
  3. Ekosistem: magrittr paketi, %>%’in yanı sıra %T>% (tee operatörü) gibi başka kullanışlı borular da sunar.

Bu nedenle, |>’nin varlığından haberdar olmak harika bir şey, ancak şimdilik R’da veri manipülasyonunun fiili standardı olan %>% ile ustalaşmak en doğru yaklaşımdır.

Pratik Uygulama: dplyr Fiilleri İle Veri Sanatı

Artık dplyr fiillerinin ne işe yaradığını teorik olarak biliyoruz. Şimdi atölyemizin başına geçip bu fiilleri kullanarak verilerimizle nasıl “konuşacağımızı” ve onları nasıl istediğimiz şekle sokacağımızı görelim.

İlk olarak, dplyr paketini yükleyelim (eğer daha önce yapmadıysanız install.packages("dplyr") komutunu konsola yazarak bir kereliğine yüklemeniz gerekir) ve örnek bir veri seti oluşturalım. Bu veri seti, küçük bir kütüphanenin kitap stok ve satış bilgilerini temsil etsin.

# dplyr paketini aktif hale getirelim
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
# Örnek veri setimizi oluşturalım: Kütüphane Kitap Bilgileri
kitaplar_df <- data.frame(
  KitapID = 101:110,
  KitapAdi = c("Evrenin Gizemi", "Kodlama Sanatı", "Veri Analizine Giriş", 
               "Tarihin Kırılma Noktaları", "Yapay Zeka Temelleri", 
               "Büyük Veri Mimarileri", "Roman Okuma Rehberi", "Uzay Keşfi", 
               "Matematiksel Düşünce", "Yeni Nesil Algoritmalar"),
  Yazar = c("Yazar A", "Yazar B", "Yazar A", "Yazar C", "Yazar D", 
            "Yazar E", "Yazar F", "Yazar A", "Yazar G", "Yazar D"),
  Kategori = c("Bilim", "Yazılım", "Veri Bilimi", "Tarih", "Yapay Zeka", 
               "Veri Bilimi", "Edebiyat", "Bilim", "Bilim", "Yapay Zeka"),
  Fiyat = c(45.50, 60.00, 72.00, 35.00, 88.00, 
            95.00, 50.00, 55.00, 48.00, 110.00),
  StokAdedi = c(10, 5, 12, 8, 3, 
                7, 15, 10, 6, 2),
  OrtalamaPuan = c(4.2, 4.5, 4.1, 3.8, 4.7, 
                   4.3, 4.0, 4.6, 3.9, 4.8)
)




# Veri setimize ilk göz atış
head(kitaplar_df)

select(): İlgilendiğimiz Sütunları Seçmek

select() fonksiyonu, bir veri çerçevesinden sadece istediğimiz sütunları almamızı sağlar. Tıpkı büyük bir dosyada sadece ad ve soyad kısmına bakmak gibi.

# --- Örnek 1: Sadece Kitap Adı ve Yazar sütunlarını seçelim ---
kitap_ve_yazar <- kitaplar_df %>% select(KitapAdi, Yazar)
kitap_ve_yazar
# --- Örnek 2: Kitap ID, Fiyat ve Stok Adedi dışındaki tüm sütunları seçelim ---
# "-" işareti ile hariç tutmak istediğimiz sütunları belirtebiliriz.
diger_bilgiler <- kitaplar_df %>% select(-KitapID, -Fiyat, -StokAdedi)
diger_bilgiler
# --- Örnek 3: Bir aralıktaki sütunları seçelim (sütun sırasına göre) ---
# KitapAdi'ndan Kategori'ye kadar olan tüm sütunları alalım.
belli_aralik_sutunlar <- kitaplar_df %>% select(KitapAdi:Kategori)
belli_aralik_sutunlar

filter(): Verilerimizi Süzmek

filter() fonksiyonu, belirli koşullara uyan satırları seçmemizi sağlar. Bu, veri analizinde en sık kullandığımız işlemlerden biridir.

# --- Örnek 1: Fiyatı 50 TL'den yüksek olan kitapları filtreleyelim ---
pahali_kitaplar <- kitaplar_df %>% filter(Fiyat > 50)
pahali_kitaplar
# --- Örnek 2: "Bilim" kategorisindeki ve Stok Adedi 10'dan fazla olan kitapları bulalım ---
# Birden fazla koşulu virgül (,) veya `&` (VE) operatörü ile birleştirebiliriz.
bilim_ve_stoklu <- kitaplar_df %>% filter(Kategori == "Bilim", StokAdedi > 10)
bilim_ve_stoklu
# --- Örnek 3: Yazar A tarafından yazılmış VEYA ortalama puanı 4.5'ten yüksek olan kitapları seçelim ---
# `|` (VEYA) operatörünü kullanarak farklı koşulları birleştirebiliriz.
yazar_a_veya_yuksek_puan <- kitaplar_df %>% filter(Yazar == "Yazar A" | OrtalamaPuan > 4.5)
yazar_a_veya_yuksek_puan

mutate(): Yeni Sütunlar Oluşturmak veya Mevcutları Değiştirmek

mutate() fonksiyonu, mevcut sütunları kullanarak yeni sütunlar eklememizi veya var olanları değiştirmemizi sağlar. Bu, verimizden yeni bilgiler türetmek için harikadır.

# --- Örnek 1: Toplam Gelir (Fiyat * StokAdedi) adında yeni bir sütun ekleyelim ---
gelir_eklenmis_df <- kitaplar_df %>% mutate(ToplamGelir = Fiyat * StokAdedi)
gelir_eklenmis_df
# --- Örnek 2: Puan Kategorisi (OrtalamaPuan'a göre "Yüksek", "Orta", "Düşük") ekleyelim ---
puan_kategorili_df <- kitaplar_df %>% 
  mutate(PuanKategorisi = case_when(
    OrtalamaPuan >= 4.5 ~ "Yüksek",
    OrtalamaPuan >= 4.0 ~ "Orta",
    TRUE ~ "Düşük" # Diğer tüm durumlar
  ))
puan_kategorili_df
# --- Örnek 3: Fiyatları %10 artıralım ve KDV'li Fiyat adında yeni sütun ekleyelim ---
fiyat_guncel_df <- kitaplar_df %>% 
  mutate(Fiyat = Fiyat * 1.10, # Mevcut Fiyat sütununu güncelliyoruz
         KDVFiyat = Fiyat * 1.18) # Yeni, güncel Fiyat üzerinden KDV'li Fiyat hesaplıyoruz
fiyat_guncel_df

arrange(): Verilerimizi Sıralamak

arrange() fonksiyonu, veri çerçevemizdeki satırları bir veya daha fazla sütuna göre sıralamamızı sağlar.

# --- Örnek 1: Kitapları Fiyata göre küçükten büyüğe sıralayalım ---
fiyata_gore_sirali <- kitaplar_df %>% arrange(Fiyat)
fiyata_gore_sirali
# --- Örnek 2: Kitapları Stok Adedine göre büyükten küçüğe sıralayalım ---
# `desc()` fonksiyonu, azalan (descending) sıralama yapar.
stok_azalan_sirali <- kitaplar_df %>% arrange(desc(StokAdedi))
stok_azalan_sirali
# --- Örnek 3: Önce Kategoriye göre (alfabetik), sonra Ortalama Puana göre (büyükten küçüğe) sıralayalım ---
cift_siralama <- kitaplar_df %>% arrange(Kategori, desc(OrtalamaPuan))
cift_siralama

summarise() ve group_by(): Gruplar Halinde Özet Çıkarmak

Bu ikili, veri analizinin en güçlü araçlarından biridir. group_by() ile veriyi gruplarız, summarise() ile her grup için özet istatistikler hesaplarız.

# --- Örnek 1: Tüm kitapların ortalama fiyatını ve toplam stok adedini bulalım ---
genel_ozet <- kitaplar_df %>% 
  summarise(
    OrtalamaFiyat = mean(Fiyat),
    ToplamStok = sum(StokAdedi),
    KitapSayisi = n() # n() fonksiyonu grup içindeki satır sayısını verir
  )
genel_ozet
# --- Örnek 2: Her kategori için ortalama fiyatı ve ortalama puanı hesaplayalım ---
kategori_bazli_ozet <- kitaplar_df %>% 
  group_by(Kategori) %>% 
  summarise(
    OrtalamaFiyat = mean(Fiyat),
    OrtalamaPuan = mean(OrtalamaPuan),
    KategoriKitapSayisi = n()
  )
kategori_bazli_ozet
# --- Örnek 3: Her yazar için yazdığı kitap sayısını ve en düşük/yüksek fiyatını bulalım ---
yazar_bazli_fiyat_ozeti <- kitaplar_df %>% 
  group_by(Yazar) %>% 
  summarise(
    YazilanKitapAdedi = n(),
    EnDusukFiyat = min(Fiyat),
    EnYuksekFiyat = max(Fiyat)
  )
yazar_bazli_fiyat_ozeti

Yolculuğun Bu Etabı da Tamamlandı!

Tebrikler, dostlar! dplyr’ın temel fiilleriyle verilerimizi nasıl seçtiğimizi, süzdüğümüzü, dönüştürdüğümüzü, sıraladığımızı ve özetlediğimizi gördük. Özellikle group_by() ve summarise() ikilisinin gücü, karmaşık veri setlerinden anlamlı içgörüler elde etmek için kilit rol oynar.

Bu bilgiler, makine öğrenmesi modelleri kurmadan önce verilerimizi hazırlamak ve keşfetmek için vazgeçilmez bir temel oluşturuyor. tidyverse felsefesiyle, veri manipülasyonu artık göz korkutucu değil, aksine keyifli ve akıcı bir süreç haline geliyor.

Bir sonraki bölümde, verilerimizin bize anlattığı hikayeleri görselleştirmeye başlayacağız. Gelin, öğrendiğimiz bu yeni becerilerle verileri konuşturmaya devam edelim!


Yararlandığımız Kaynak

Bu bölümdeki konuların sırası, dplyr fiillerinin sınıflandırılması ve genel anlatım felsefesi oluşturulurken aşağıdaki değerli eserden ilham alınmıştır. Örnekler ve metinler tamamen özgün olsa da, bu kaynağın yol göstericiliği için atıfta bulunmak etik bir gerekliliktir.

Lafaye de Micheaux, P., Drouilhet, R., & Liquet, B. (2013). The R Software: Fundamentals of Programming and Statistical Analysis. Springer. (Chapter 3: Data manipulation, functions)

The Tidyverse Team. (n.d.). Tidyverse. https://www.tidyverse.org/

Wickham, H., Averick, M., Bryan, J., Chang, W., McGowan, L., François, R., Grolemund, G., Hayes, A., Henry, L., Hester, J., Kuhn, M., Pedersen, T., Miller, E., Bache, S., Müller, K., Ooms, J., Robinson, D., Seidel, D., Spinu, V., … Yutani, H. (2023). Welcome to the tidyverse. Journal of Open Source Software, 4(43), 1686. https://joss.theoj.org/papers/10.21105/joss.01686

Wickham, H., & Grolemund, G. (2017). R for data science: Import, tidy, transform, visualize, and model data. O’Reilly Media. https://r4ds.had.co.nz/

Alıştırmalar

Şimdi sıra sizde! Yukarıda öğrendiğimiz dplyr fiillerini ve pipe operatörünü (%>%) kullanarak aşağıdaki görevleri yerine getirin.

Veri Seti: Kitaplar_df veri setini kullanmaya devam edebilirsiniz.

1. Yeni Sütun Oluşturma ve Seçme: a. Kitapların Fiyatına ve Stok Adedine göre TahminiCiro (Fiyat * StokAdedi) adında yeni bir sütun ekleyin. b. Sadece KitapAdi, Kategori ve TahminiCiro sütunlarını içeren yeni bir veri çerçevesi oluşturun.

2. Kitapları Filtreleme ve Sıralama: a. Kategori’si “Yapay Zeka” olan ve OrtalamaPuanı 4.5’ten yüksek olan kitapları listeleyin. b. Bu kitapları OrtalamaPuana göre büyükten küçüğe doğru sıralayın.

3. Gruplama ve Özetleme: a. Her bir Yazar için yazdığı kitap sayısını, ortalama fiyatını ve toplam stok adedini içeren bir özet tablo oluşturun. b. Sadece 2’den fazla kitap yazmış yazarları ve onların özet bilgilerini gösterin.

4. Zincirleme İşlemler (Pipe Operatörü ile): kitaplar_df üzerinde tek bir zincirleme işlemle (tek bir pipe serisi kullanarak): a. Fiyatı 50 TL’den düşük olan kitapları seçin. b. Bu kitapların KitapAdi ve Fiyat sütunlarını alın. c. Fiyatı artan sıraya göre sıralayın.

Alıştırmalar ve Çözümleri

# Çalışmaya başlamadan önce dplyr'ı yüklüyoruz ve örnek veri setimizi kullanıyoruz.
library(dplyr)
kitaplar_df <- data.frame(
  KitapID = 101:110,
  KitapAdi = c("Evrenin Gizemi", "Kodlama Sanatı", "Veri Analizine Giriş", 
               "Tarihin   Kırılma Noktaları", "Yapay Zeka Temelleri", 
               "Büyük Veri Mimarileri", "Roman Okuma Rehberi", 
               "Uzay Keşfi", "Matematiksel Düşünce", "Yeni Nesil Algoritmalar"),
  Yazar = c("Yazar A", "Yazar B", "Yazar A", "Yazar C", "Yazar D", 
            "Yazar E", "Yazar F", "Yazar A", "Yazar G", "Yazar D"),
  Kategori = c("Bilim", "Yazılım", "Veri Bilimi", "Tarih", "Yapay Zeka", 
              "Veri Bilimi", "Edebiyat", "Bilim", "Bilim", "Yapay Zeka"),
  Fiyat = c(45.50, 60.00, 72.00, 35.00, 88.00, 
            95.00, 50.00, 55.00, 48.00, 110.00),
  StokAdedi = c(10, 5, 12, 8, 3, 
                7, 15, 10, 6, 2),
  OrtalamaPuan = c(4.2, 4.5, 4.1, 3.8, 4.7, 
                  4.3, 4.0, 4.6, 3.9, 4.8)
)


# --- Çözüm 1: Yeni Sütun Oluşturma ve Seçme ---
# a. Tahmini Ciro sütunu ekleme
kitaplar_ciro <- kitaplar_df %>%
  mutate(TahminiCiro = Fiyat * StokAdedi)

# b. İstenen sütunları seçme
secilen_kitap_bilgileri <- kitaplar_ciro %>%
  select(KitapAdi, Kategori, TahminiCiro)
secilen_kitap_bilgileri
# --- Çözüm 2: Kitapları Filtreleme ve Sıralama ---
# a. Kategori "Yapay Zeka" ve Ortalama Puan > 4.5 olan kitaplar
yapay_zeka_yuksek_puan <- kitaplar_df %>%
  filter(Kategori == "Yapay Zeka" & OrtalamaPuan > 4.5)
yapay_zeka_yuksek_puan
# b. Bu kitapları Ortalama Puana göre büyükten küçüğe sıralama
sirali_yapay_zeka_kitaplar <- yapay_zeka_yuksek_puan %>%
  arrange(desc(OrtalamaPuan))
sirali_yapay_zeka_kitaplar
# --- Çözüm 3: Gruplama ve Özetleme ---
# a. Her yazar için özet tablo
yazar_ozet <- kitaplar_df %>%
  group_by(Yazar) %>%
  summarise(
    YazilanKitapAdedi = n(),
    OrtalamaFiyat = mean(Fiyat),
    ToplamStokAdedi = sum(StokAdedi)
  )
yazar_ozet
# b. Sadece 2'den fazla kitap yazmış yazarları gösterme
cok_kitap_yazan_yazarlar <- yazar_ozet %>%
  filter(YazilanKitapAdedi > 2)
cok_kitap_yazan_yazarlar
# --- Çözüm 4: Zincirleme İşlemler (Pipe Operatörü ile) ---
zincirleme_sonuc <- kitaplar_df %>%
  filter(Fiyat < 50) %>% # a. Fiyatı 50 TL'den düşük olanları seç
  select(KitapAdi, Fiyat) %>% # b. Kitap Adı ve Fiyat sütunlarını al
  arrange(Fiyat) # c. Fiyatı artan sıraya göre sırala
zincirleme_sonuc

Farklı Bir Atölye, Aynı Aletler: mtcars Veri Setiyle Çalışma

Şimdiye kadar kütüphane verileriyle çalıştık. Şimdi ise bambaşka bir alana geçerek, aynı dplyr fiillerinin ne kadar evrensel olduğunu görelim. Bu sefer, R ile birlikte gelen klasik mtcars (Motor Trend Araba Yol Testleri) veri setini kullanarak bir otomobil mühendisi veya bir pazar araştırmacısı gibi düşüneceğiz.

Çalışma Veri Setimizi Hazırlama

mtcars veri setinin küçük bir sorunu var: araba modelleri satır ismi olarak saklanıyor, bu da “tidy” (düzenli) veri prensibine aykırı. İlk işimiz bu satır isimlerini “model” adında gerçek bir sütuna dönüştürmek olacak. tidyverse ekosisteminin bir parçası olan tibble paketi bunun için harika bir fonksiyona sahip.

# dplyr'i içeren tidyverse paketini çağıralım
library(tidyverse) 

# mtcars verisini yükleyip, satır isimlerini "model" adında bir sütuna dönüştürelim
# rownames_to_column() fonksiyonu bu işi yapar.
cars_data <- mtcars %>% 
  rownames_to_column(var = "model")

# Veri setimizin ilk 6 satırına ve sütunlarına hızlıca göz atalım
head(cars_data)
glimpse(cars_data) # glimpse(), str()'nin daha modern ve okunaklı bir alternatifidir.
## Rows: 32
## Columns: 12
## $ model <chr> "Mazda RX4", "Mazda RX4 Wag", "Datsun 710", "Hornet 4 Drive", "H…
## $ mpg   <dbl> 21.0, 21.0, 22.8, 21.4, 18.7, 18.1, 14.3, 24.4, 22.8, 19.2, 17.8…
## $ cyl   <dbl> 6, 6, 4, 6, 8, 6, 8, 4, 4, 6, 6, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 8…
## $ disp  <dbl> 160.0, 160.0, 108.0, 258.0, 360.0, 225.0, 360.0, 146.7, 140.8, 1…
## $ hp    <dbl> 110, 110, 93, 110, 175, 105, 245, 62, 95, 123, 123, 180, 180, 18…
## $ drat  <dbl> 3.90, 3.90, 3.85, 3.08, 3.15, 2.76, 3.21, 3.69, 3.92, 3.92, 3.92…
## $ wt    <dbl> 2.620, 2.875, 2.320, 3.215, 3.440, 3.460, 3.570, 3.190, 3.150, 3…
## $ qsec  <dbl> 16.46, 17.02, 18.61, 19.44, 17.02, 20.22, 15.84, 20.00, 22.90, 1…
## $ vs    <dbl> 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0…
## $ am    <dbl> 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0…
## $ gear  <dbl> 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 3, 3…
## $ carb  <dbl> 4, 4, 1, 1, 2, 1, 4, 2, 2, 4, 4, 3, 3, 3, 4, 4, 4, 1, 2, 1, 1, 2…

Artık analiz için harika bir veri setimiz var. Haydi aynı fiilleri bu yeni atölyede kullanmaya başlayalım!

dplyr Fiilleriyle Pratik Çalışma (mtcars)

filter() (Satırları Süzmek)

Görevi: Belirlediğimiz koşul(lar)a uyan arabaları seçer.

# Örnek 1: Sadece 6 silindirli (cyl == 6) arabaları görelim.
filter(cars_data, cyl == 6)
# Örnek 2: 4 silindirli (cyl == 4) VE 100 beygir gücünden (hp > 100) yüksek arabalar.
filter(cars_data, cyl == 4, hp > 100)

arrange() (Satırları Sıralamak)

Görevi: Veri çerçevesini bir veya daha fazla özelliğe göre sıralar.

# Örnek 1: Arabaları en yüksek yakıt verimliliğinden (mpg) en düşüğe doğru sırala.
arrange(cars_data, desc(mpg))
# Örnek 2: Önce silindire (azdan çoğa), sonra beygir gücüne (çoktan aza) göre sırala.
arrange(cars_data, cyl, desc(hp))

select() (Sütunları Seçmek)

Görevi: Sadece ilgilendiğimiz özellikleri seçer.

# Örnek 1: Sadece model, silindir ve beygir gücü sütunlarını seç.
select(cars_data, model, cyl, hp)
# Örnek 2: 'gear' (vites) ve 'carb' (karbüratör) sütunları DIŞINDAKİ her şeyi seç.
select(cars_data, -gear, -carb)

mutate() (Yeni Özellikler Türetmek)

Görevi: Mevcut özelliklerden yeni özellikler hesaplamamızı sağlar.

# Örnek 1: 'wt' sütunu (1000 lbs cinsinden) kullanarak ağırlığı kilogram (kg) cinsinden hesaplayalım.
# 1 lbs = 0.453592 kg
cars_data_yeni <- mutate(cars_data, wt_kg = wt * 1000 * 0.453592)
head(select(cars_data_yeni, model, wt, wt_kg)) # Sadece ilgili sütunlara bakalım
# Örnek 2: Beygir gücünün ağırlığa oranını (kg başına düşen beygir gücü) hesaplayalım.
cars_data_yeni <- mutate(cars_data_yeni, hp_per_kg = hp / wt_kg)
head(select(cars_data_yeni, model, hp, wt_kg, hp_per_kg))

summarise() ve group_by() (Özetleme ve Gruplama)

Görevi: Farklı araba grupları için özet istatistikler hesaplar.

# Örnek 1: Her bir silindir (cyl) grubu için ayrı ayrı ortalama mpg hesapla.
cars_data %>%
  group_by(cyl) %>%
  summarise(ortalama_mpg = mean(mpg))
# Örnek 2: Her bir 'vites' (am: 0=Otomatik, 1=Manuel) tipi için;
# gruptaki araç sayısını (n()) ve ortalama beygir gücünü (mean(hp)) bulalım.
cars_data %>%
  group_by(am) %>%
  summarise(
    arac_sayisi = n(),
    ortalama_hp = mean(hp)
  )

Hepsini Birleştirmek: Pipe (%>%) ile Ustalık

Soru: “Sadece 6 ve 8 silindirli arabaları seç, bunları vites tipine (am) göre grupla, her grup için ortalama beygir gücünü (ortalama_hp) ve ortalama yakıt tüketimini (ortalama_mpg) hesapla ve sonucu ortalama beygir gücüne göre azalan şekilde sırala.”

# dplyr ile bu karmaşık soru, okunabilir bir iş akışına dönüşür:
cars_data %>%
  filter(cyl %in% c(6, 8)) %>%  # Silindiri 6 VEYA 8 olanları seç (%in% operatörü çok kullanışlıdır)
  group_by(am) %>%             # Vites tipine göre grupla
  summarise(                   # Şimdi özetle:
    ortalama_hp = mean(hp),
    ortalama_mpg = mean(mpg)
  ) %>%
  arrange(desc(ortalama_hp)) # Son olarak yüksek hp'ye göre sırala

Sonuç

Gördüğünüz gibi dostlar, problem ister kitap satışı olsun ister araba performansı, dplyr’ın temel fiilleri aynı mantık ve sadelikle çalışıyor. Bu, tidyverse felsefesinin en büyük gücüdür: Veriyle “konuşmak” için evrensel bir dil sunması.

Bu iki farklı örnekle, veri manipülasyonunun temellerini sağlam bir şekilde atmış olduk.

Ustalık Projesine Başlamadan Önce: Atölyemizin Adresini Belirlemek

Dostlar, şimdiye kadar R’ın kendi içinde hazır gelen mtcars gibi veri setleriyle çalıştık. R bu verilerin nerede olduğunu zaten biliyordu. Ancak şimdi, tıpkı bir ustanın dışarıdan getirdiği ham bir kütüğü atölyesine sokması gibi, biz de bilgisayarımıza indirdiğimiz bir .csv dosyasını R’a okutacağız.

Bunu yapabilmemiz için, R’a önce atölyemizin, yani proje klasörümüzün nerede olduğunu söylememiz gerekir. Bu adrese R dünyasında Çalışma Dizini (Working Directory) denir.

Çalışma Dizini Nedir ve Neden Önemlidir?

Çalışma Dizini, R’ın dosya okuma (read_csv()) veya yazma (write_csv()) gibi komutları verdiğimizde ilk bakacağı yerdir. Eğer bu adresi doğru ayarlamazsak, R aradığı dosyayı bulamaz ve o meşhur “cannot open file … No such file or directory” hatasını alırız. Bu adımı doğru yapmak, bizi birçok potansiyel hatadan en baştan kurtarır.

1. Adım: Şu An Neredeyiz? getwd() ile Mevcut Adresi Öğrenme

Herhangi bir değişiklik yapmadan önce, R’ın şu anda hangi klasörde çalıştığını öğrenmek iyi bir alışkanlıktır. getwd() (Get Working Directory) fonksiyonu, bize tam olarak bu bilgiyi verir.

# R'a soralım: "Şu an hangi klasördesin?"
getwd()

Bu komutun çıktısı, R’ın o anki çalışma dizinini size bir metin olarak gösterecektir.

2. Adım: Atölyenin Adresini Değiştirme

Eğer getwd() komutunun çıktısı, proje dosyalarınızın olduğu klasör değilse, adresimizi değiştirmemiz gerekir. Bunun iki temel yolu vardır:

Yöntem 1: En Kolay Yol (Tıklayarak Ayarlama)

Bu yöntem, özellikle yeni başlayanlar için en hızlı ve en az hataya açık yoldur.

  1. RStudio’nun sağ alt penceresindeki Files sekmesine gidin.

  2. Proje Klasörünüze Gidin: Eğer proje klasörünüz doğrudan görünmüyorsa, dosya yolunun gösterildiği çubuğun en sağındaki ... (üç nokta) butonuna tıklayın. Bu, bilgisayarınızın dosya gezginini açacaktır. Bu pencereden, .Rmd ve .csv dosyalarınızın bulunduğu klasörü bulun ve Open’a tıklayın.

  3. Çalışma Dizinini Ayarlayın: Artık Files paneli doğru klasörün içeriğini gösterdiğine göre, More yazan dişli ikonuna tıklayın.

  4. Seçimi Onaylayın: Açılan menüden Set As Working Directory seçeneğini seçin.

RStudio'da Çalışma Dizinini Ayarlama

RStudio’da Çalışma Dizinini Ayarlama

Bu işlemi yaptığınızda, Konsol penceresinde setwd("...") şeklinde bir komutun belirdiğini göreceksiniz. Bu, RStudio’nun bizim için bu komutu otomatik olarak çalıştırdığı anlamına gelir. Artık R, doğru atölyede olduğumuzu biliyor!

Yöntem 2: Usta Yolu (Kod ile Ayarlama)

Daha kalıcı ve projelerinizi başkalarıyla paylaşırken hayat kurtaran yöntem ise, bu komutu script’imizin en başına kendimiz yazmaktır. setwd() (Set Working Directory) fonksiyonu, çalışma dizinini ayarlar.

# setwd(".../proje/klasorunuzun/yolu")
# Örnek:
setwd("/Users/ismail/Documents/R_Serisi_Projesi")

Çok Önemli Not (Windows Kullanıcıları İçin): Windows’ta dosya yolunu kopyaladığınızda, yollar \ ters taksim işareti ile gelir (C:\Users\... gibi). Ancak R, bu işareti özel bir karakter olarak algılar. Bu nedenle, setwd() içinde dosya yolunu yazarken tüm \ işaretlerini / düz taksim ile değiştirmelisiniz!

  • Yanlış: setwd("C:\\Users\\ismail\\Desktop") -> HATA VEREBİLİR! (Çift \\ de çalışır ama kafa karıştırıcıdır.)
  • Doğru ve Evrensel: setwd("C:/Users/ismail/Desktop") -> HER ZAMAN ÇALIŞIR!

3. Adım: Doğru Yerde Miyiz? getwd() ile Teyit Etme

setwd() komutunu çalıştırdıktan veya menüden ayarınızı yaptıktan sonra, getwd() komutunu tekrar çalıştırarak değişikliğin başarılı olup olmadığını kontrol etmek mükemmel bir alışkanlıktır.

# Adresi değiştirdikten sonra tekrar soralım:
getwd()

Bu komutun çıktısı, artık sizin proje klasörünüzün adresini göstermelidir.

Artık R’a atölyemizin yerini gösterdiğimize ve doğru yerde olduğumuzu teyit ettiğimize göre, ilk gerçek dünya verimizi içeri almaya tamamen hazırız!

Ustalık Projesi: Gerçek Hayat Verisiyle Çalışma (Kaggle)

Dostlar, atölyemizde yeterince pratik yaptık. Artık R becerilerimizi gerçek dünya verileriyle test etme zamanı. Bu bölümde, veri bilimcilerin oyun alanı olan Kaggle’dan popüler bir veri seti alıp, şimdiye kadar öğrendiğimiz tüm dplyr fiillerini bu “ham” veri üzerinde kullanacağız.

Bu adım, serimizin en heyecan verici kısmı olabilir, çünkü artık sadece R öğrenmiyor, aynı zamanda gerçek bir veri analizi projesinin ilk adımlarını atıyoruz!

Veri Setimizi Tanıyalım ve Yükleyelim

Veri Seti: “Netflix Movies and TV Shows” Bu veri seti, Netflix’te bulunan film ve diziler hakkında show_id, type, title, country, release_year gibi bilgiler içerir.

Adım 1: Veriyi İndirme

  1. Linke giderek Kaggle’dan veri setini indirin: https://www.kaggle.com/datasets/shivamb/netflix-shows
  2. “Download” butonuna basarak netflix_titles.csv dosyasını bilgisayarınıza indirin.
  3. İndirdiğiniz bu .csv dosyasını, .Rmd projenizin bulunduğu klasörün içine koyun. Bu, dosyayı R’a yüklememizi çok kolaylaştıracaktır.

Adım 2: Veriyi R’a Yükleme tidyverse’ün bir parçası olan readr paketi, read_csv() adında çok hızlı ve güçlü bir fonksiyon içerir. Bu fonksiyonu kullanarak verimizi yükleyeceğiz.

library(tidyverse)

# Proje klasörümüzdeki CSV dosyasını okuyalım
netflix_df <- read_csv("netflix_titles.csv")

# Veri setine ilk bakışımızı atalım
glimpse(netflix_df)
## Rows: 8,807
## Columns: 12
## $ show_id      <chr> "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s1…
## $ type         <chr> "Movie", "TV Show", "TV Show", "TV Show", "TV Show", "TV …
## $ title        <chr> "Dick Johnson Is Dead", "Blood & Water", "Ganglands", "Ja…
## $ director     <chr> "Kirsten Johnson", NA, "Julien Leclercq", NA, NA, "Mike F…
## $ cast         <chr> NA, "Ama Qamata, Khosi Ngema, Gail Mabalane, Thabang Mola…
## $ country      <chr> "United States", "South Africa", NA, NA, "India", NA, NA,…
## $ date_added   <chr> "September 25, 2021", "September 24, 2021", "September 24…
## $ release_year <dbl> 2020, 2021, 2021, 2021, 2021, 2021, 2021, 1993, 2021, 202…
## $ rating       <chr> "PG-13", "TV-MA", "TV-MA", "TV-MA", "TV-MA", "TV-MA", "PG…
## $ duration     <chr> "90 min", "2 Seasons", "1 Season", "1 Season", "2 Seasons…
## $ listed_in    <chr> "Documentaries", "International TV Shows, TV Dramas, TV M…
## $ description  <chr> "As her father nears the end of his life, filmmaker Kirst…

Gördüğünüz gibi, artık üzerinde çalışabileceğimiz 8000’den fazla satır içeren zengin bir veri setimiz var!

dplyr ile Netflix Verilerini Keşfetme

Soru 1: Türkiye’de çekilmiş film ve diziler hangileri? (filter)

# 'country' sütununda "Turkey" içerenleri filtreleyelim.
# str_detect() fonksiyonu, bir metin içinde belirli bir kelime olup olmadığını kontrol eder.
netflix_df %>% 
  filter(str_detect(country, "Turkey")) %>%
  select(title, type, release_year) # Sadece ilgili sütunları gösterelim

Soru 2: 2020’den sonra çıkan en uzun 5 film hangisi? (filter, arrange, select)

Bu soruyu cevaplamak için duration sütununu temizlememiz gerekecek. Şu an “120 min” gibi metin formatında. separate() fonksiyonu ile sayıyı ve “min” kelimesini ayıralım.

netflix_df %>%
  filter(type == "Movie") %>% # Sadece filmleri seç
  separate(duration, into = c("sure_dakika", "birim"), sep = " ", convert = TRUE) %>% 
  # "120 min" -> 120, "min"
  filter(release_year >= 2020) %>% # 2020 ve sonrası
  arrange(desc(sure_dakika)) %>% # Süreye göre büyükten küçüğe sırala
  select(title, release_year, sure_dakika) %>% # İlgili sütunları seç
  head(5) # İlk 5'i göster

Soru 3: Her bir “rating” (yaş sınırı) kategorisinde kaç adet içerik var? (group_by, summarise)

netflix_df %>%
  group_by(rating) %>% # Yaş sınırı kategorisine göre grupla
  summarise(icerik_sayisi = n()) %>% # Her gruptaki eleman sayısını (n()) say
  arrange(desc(icerik_sayisi)) # Çoktan aza doğru sırala

Soru 4 (Ustalık Sorusu): Her ülkenin en çok içerik ürettiği tür (listed_in) hangisidir?

Bu karmaşık soru, dplyr’in gücünü tam anlamıyla gösterir.

netflix_df %>%
  # Bazı içeriklerin birden fazla ülkesi var, bunları ayıralım
  separate_rows(country, sep = ", ") %>% 
  # Bazı içeriklerin birden fazla türü var, bunları da ayıralım
  separate_rows(listed_in, sep = ", ") %>%
  # Boş ülke isimlerini veri setinden çıkaralım
  filter(!is.na(country) & country != "") %>%
  # Ülke ve türe göre gruplayıp sayalım
  count(country, listed_in, name = "sayi") %>%
  # Her ülke içinde en yüksek sayıya sahip olanı bulalım
  group_by(country) %>%
  filter(sayi == max(sayi)) %>%
  # Sadece 10'dan fazla içerik üretmiş ülkeleri görelim
  filter(sum(sayi) > 10) %>%
  arrange(desc(sayi))

Bu bölümle birlikte, artık sadece R komutlarını bilen değil, aynı zamanda bu komutları kullanarak gerçek dünya verilerinden anlamlı bilgiler çıkarabilen bir veri kaşifiyiz dostlar!

Alıştırmalar: Şimdi Sıra Sizde!

Dostlar, atölyemizde aletlerimizi kullandık, farklı malzemeler üzerinde çalıştık ve ustalık projemizi tamamladık. Şimdi sıra, bu aletleri tamamen kendi başınıza kullanarak ne kadar harika işler çıkarabileceğinizi görmekte!

Aşağıdaki görevleri, öğrendiğimiz dplyr fiillerini ve %>% (pipe) operatörünü kullanarak çözmeye çalışın. Unutmayın, önemli olan tek bir doğru cevap bulmak değil, çözüme giden yolda bu fiillerle rahatça “düşünebilmektir”.

Kullanılacak Veri Setleri:

  • cars_data (Hazırladığımız düzenli mtcars veri seti)
  • netflix_df (Kaggle’dan indirdiğimiz Netflix veri seti)

Görev Seti 1: cars_data ile Otomobil Analizi

  1. Filtreleme ve Sıralama Sanatı: cars_data veri setini kullanarak, 4’ten fazla silindire sahip (cyl > 4), 110’dan az beygir gücü (hp < 110) olan arabaları bulun ve bu arabaları yakıt verimliliğine (mpg) göre en iyiden en kötüye doğru sıralayın.

  2. Veriden Yeni Bilgi Türetme: mutate() kullanarak wt (ağırlık) sütununu kilograma çevirip (wt_kg adıyla) ve qsec (1/4 mil süresi) sütununu kullanarak arabaların 0’dan 100 km/s hıza yaklaşık ne kadar sürede çıktığını hesaplayan hizlanma_100km adında yeni bir sütun oluşturun. (Not: Bu sadece bir yaklaşımdır, qsec doğrudan 0-100 hızlanması değildir ama pratik için kullanalım). Son olarak sadece model, wt_kg ve hizlanma_100km sütunlarını gösterin.

  3. Grupların Sırrını Çözme: am (0 = Otomatik, 1 = Manuel) vites tipine ve vs (0 = V motor, 1 = Düz motor) motor tipine göre arabaları gruplayarak her bir kombinasyon için (örneğin, Otomatik-V motor, Manuel-Düz motor) ortalama beygir gücünü (hp) ve maksimum yakıt verimliliğini (mpg) bulun.


Görev Seti 2: netflix_df ile İçerik Keşfi

  1. Yönetmen Analizi: Netflix veri setinde (netflix_df), “Quentin Tarantino” tarafından yönetilmiş olan içeriklerin title, release_year ve rating bilgilerini listeleyin. (İpucu: director sütununda NA yani boş değerler olabilir, bunları filtrelerken göz ardı etmeniz gerekebilir.)

  2. Türlere Göre Süre Analizi:

    1. Veri setini sadece “Movie” tipindeki içeriklere göre filtreleyin.
    2. duration sütunundaki ” min” ifadesini kaldırarak bu sütunu sayısal hale getirin.
    3. Her bir listed_in (tür) kategorisi için ortalama film süresini (ortalama_sure) hesaplayın.
    4. Sonucu, en uzun ortalama süreye sahip türden en kısaya doğru sıralayın.
  3. Ustalık Zinciri (Pipe ile Tek Seferde): Tek bir %>% zinciri kullanarak aşağıdaki adımları sırayla uygulayın:

    1. Sadece “TV Show” tipindeki içerikleri filtreleyin.
    2. Satırlarında country bilgisi boş olmayanları seçin.
    3. Her bir country (ülke) için kaç adet TV şovu olduğunu sayın.
    4. Sonucu, en çok TV şovu üreten ülkeden en aza doğru sıralayın.
    5. Sadece ilk 10 ülkeyi gösterin.

Alıştırmalar ve Çözümleri

Aşağıda, alıştırmaların R kodlarını ve bu kodların çalıştırıldığında üreteceği çıktıları bulabilirsiniz. Kendi çözümlerinizle karşılaştırarak ne kadar yol katettiğinizi görebilirsiniz!

# Çalışmaya başlamadan önce gerekli paket ve verileri yüklüyoruz.
library(tidyverse)

# cars_data'yı oluşturalım
cars_data <- mtcars %>% 
  rownames_to_column(var = "model")

# --- Çözüm 1: Filtreleme ve Sıralama Sanatı ---
cars_data %>%
  filter(cyl > 4, hp < 110) %>%
  arrange(desc(mpg))
# --- Çözüm 2: Veriden Yeni Bilgi Türetme ---
cars_data %>%
  mutate(
    wt_kg = wt * 1000 * 0.453592,
    hizlanma_100km = qsec * 1.5 # Çok kaba bir yaklaşım, sadece pratik için :)
  ) %>%
  select(model, wt_kg, hizlanma_100km)
# --- Çözüm 3: Grupların Sırrını Çözme ---
cars_data %>%
  group_by(am, vs) %>%
  summarise(
    ortalama_hp = mean(hp),
    maksimum_mpg = max(mpg),
    .groups = 'drop'
  )
# --- ŞİMDİ NETFLIX BÖLÜMÜNE GEÇİYORUZ ---
# Önce dosyanın var olup olmadığını kontrol edelim. Bu, en sağlam yöntemdir.
if (file.exists("netflix_titles.csv")) {
  
  # Dosya varsa, onu okuyalım
  netflix_df <- read_csv("netflix_titles.csv")
  
  # --- Çözüm 4: Yönetmen Analizi ---
  # Not: Bu kod bloğu sadece dosya bulunduğunda çalışacak.
  print("--- Çözüm 4: Yönetmen Analizi ---")
  print(
    netflix_df %>%
      filter(director == "Quentin Tarantino") %>%
      select(title, release_year, rating)
  )

  # --- Çözüm 5: Türlere Göre Süre Analizi ---
  print("--- Çözüm 5: Türlere Göre Süre Analizi ---")
  print(
    netflix_df %>%
      filter(type == "Movie") %>%
      mutate(sure_dakika = as.integer(str_remove(duration, " min"))) %>%
      group_by(listed_in) %>%
      summarise(ortalama_sure = mean(sure_dakika, na.rm = TRUE), .groups = 'drop') %>%
      arrange(desc(ortalama_sure))
  )
      
  # --- Çözüm 6: Ustalık Zinciri (Pipe ile Tek Seferde) ---
  print("--- Çözüm 6: Ustalık Zinciri (Pipe ile Tek Seferde) ---")
  print(
    netflix_df %>%
      filter(type == "TV Show") %>%
      filter(!is.na(country)) %>%
      count(country, name = "tv_show_sayisi") %>%
      arrange(desc(tv_show_sayisi)) %>%
      head(10)
  )
  
} else {
  # Eğer dosya yoksa, PDF'te bilgilendirici bir not bırakalım.
  cat("Netflix Alıştırmaları Atlandı: 'netflix_titles.csv' dosyası proje klasöründe bulunamadı.")
}
## [1] "--- Çözüm 4: Yönetmen Analizi ---"
## # A tibble: 8 × 3
##   title                               release_year rating
##   <chr>                                      <dbl> <chr> 
## 1 Django Unchained                            2012 R     
## 2 The Hateful Eight: Extended Version         2015 R     
## 3 The Hateful Eight                           2015 R     
## 4 Inglourious Basterds                        2009 R     
## 5 Jackie Brown                                1997 R     
## 6 Kill Bill: Vol. 1                           2003 R     
## 7 Kill Bill: Vol. 2                           2004 R     
## 8 Pulp Fiction                                1994 R     
## [1] "--- Çözüm 5: Türlere Göre Süre Analizi ---"
## # A tibble: 278 × 2
##    listed_in                                                  ortalama_sure
##    <chr>                                                              <dbl>
##  1 Classic Movies, Music & Musicals                                    173 
##  2 Action & Adventure, Cult Movies, Dramas                             172 
##  3 Action & Adventure, Classic Movies, International Movies            166 
##  4 Cult Movies, Dramas, Thrillers                                      158 
##  5 Classic Movies, Dramas, Romantic Movies                             154.
##  6 Action & Adventure, Sci-Fi & Fantasy, Thrillers                     148 
##  7 Classic Movies, Cult Movies, Dramas                                 146.
##  8 Classic Movies, Dramas, Music & Musicals                            145 
##  9 Action & Adventure, Classic Movies, Dramas                          145.
## 10 Action & Adventure, International Movies, Music & Musicals          139.
## # ℹ 268 more rows
## [1] "--- Çözüm 6: Ustalık Zinciri (Pipe ile Tek Seferde) ---"
## # A tibble: 10 × 2
##    country        tv_show_sayisi
##    <chr>                   <int>
##  1 United States             760
##  2 United Kingdom            213
##  3 Japan                     169
##  4 South Korea               158
##  5 India                      79
##  6 Taiwan                     68
##  7 Canada                     59
##  8 France                     49
##  9 Australia                  48
## 10 Spain                      48

Kapanış Meydan Okuması: Öğrenci Not Sistemi Projesi

Dostlar, bu bölüm boyunca dplyr’ın temel fiillerini öğrendik ve farklı veri setleri üzerinde pratik yaptık. Şimdi, tüm bu becerileri bir araya getirme ve bir veri analistinin gerçek hayatta karşılaşabileceği türden bir projeyi baştan sona tamamlama zamanı.

Bu son meydan okumada, sadece komutları kullanmakla kalmayacak, aynı zamanda bir dizi soruyu cevaplamak için veriyi nasıl şekillendireceğinizi ve ondan nasıl yeni bilgiler türeteceğinizi de düşüneceksiniz.

Senaryo: Bir sınıfın vize ve final notları elimizde. Görevimiz, bu ham veriden yola çıkarak kapsamlı bir “başarı analizi tablosu” oluşturmak ve bir dizi kritik soruya yanıt vermek.

Hazırsanız, bu bölümün final projesine başlayalım!

Görevler

Proje Adımları ve Analiz Soruları:

  1. Temel Başarı Tablosunu Oluşturma Aşağıdaki görevleri tek bir %>% zinciri içinde tamamlayarak basari_tablosu adında yeni bir veri çerçevesi oluşturun:

    1. Her öğrenci için GecmeNotu’nu hesaplayın (VizeNotu * 0.30 + FinalNotu * 0.70).
    2. Bu nota göre Sonuc sütununu oluşturun (40 ve üzeri “Geçti”, altı “Kaldı”).
    3. Son olarak, bu tabloyu en yüksek geçme notuna sahip öğrenciden en düşüğe doğru sıralayın.
  2. Sınıf Analizi ve İçgörü Çıkarma Oluşturduğunuz basari_tablosu’nu kullanarak aşağıdaki soruları dplyr ile cevaplayın:

    Soru 2.1: Sınıfta “Geçti” ve “Kaldı” olarak kaçar öğrenci bulunmaktadır?

    Soru 2.2: Sınıfın genel vize, final ve geçme notu ortalamaları nedir?

    Soru 2.3 (Zorlayıcı Soru): “Geçen” ve “Kalan” öğrencilerin vize ve final notu ortalamaları arasında belirgin bir fark var mıdır? (Yani, geçenlerin ortalaması ve kalanların ortalaması nedir?)

    Soru 2.4 (Ustalık Sorusu): Vize notu 50’nin altında olup da final notu sayesinde dersi geçen (“kurtaran”) kaç öğrenci vardır? Bu öğrencilerin listesini gösterin.

Çözümler

Aşağıda, alıştırmaların R kodlarını ve bu kodların çalıştırıldığında üreteceği çıktıları bulabilirsiniz.

# Çalışmaya başlamadan önce gerekli paket ve verileri yüklüyoruz.
library(tidyverse)

# --- Kapanış Meydan Okuması: Öğrenci Not Sistemi Çözümleri ---

# Önce üzerinde çalışacağımız 20 kişilik veri setini oluşturalım
set.seed(42) # Sonuçların tekrarlanabilir olması için
ogrenci_notlari_df <- data.frame(
  OgrenciNo = 202501:(202501 + 19),
  OgrenciAd = paste("Öğrenci", LETTERS[1:20]),
  VizeNotu = sample(20:90, 20, replace = TRUE),
  FinalNotu = sample(30:100, 20, replace = TRUE)
)

# --- Adım 1: Temel Başarı Tablosunu Oluşturma ---
basari_tablosu <- ogrenci_notlari_df %>%
  mutate(
    GecmeNotu = (VizeNotu * 0.30) + (FinalNotu * 0.70),
    Sonuc = ifelse(GecmeNotu >= 40, "Geçti", "Kaldı")
  ) %>%
  arrange(desc(GecmeNotu))

cat("--- Adım 1 Çıktısı: Başarı Tablosu ---\n")
## --- Adım 1 Çıktısı: Başarı Tablosu ---
print(basari_tablosu)
##    OgrenciNo OgrenciAd VizeNotu FinalNotu GecmeNotu Sonuc
## 1     202509 Öğrenci I       56        97      84.7 Geçti
## 2     202511 Öğrenci K       45        98      82.1 Geçti
## 3     202506 Öğrenci F       66        87      80.7 Geçti
## 4     202513 Öğrenci M       60        79      73.3 Geçti
## 5     202508 Öğrenci H       90        65      72.5 Geçti
## 6     202514 Öğrenci N       46        78      68.4 Geçti
## 7     202502 Öğrenci B       84        59      66.5 Geçti
## 8     202503 Öğrenci C       44        72      63.6 Geçti
## 9     202501 Öğrenci A       68        53      57.5 Geçti
## 10    202505 Öğrenci E       68        51      56.1 Geçti
## 11    202515 Öğrenci O       55        55      55.0 Geçti
## 12    202520 Öğrenci T       61        50      53.3 Geçti
## 13    202519 Öğrenci S       77        32      45.5 Geçti
## 14    202510 Öğrenci J       39        47      44.6 Geçti
## 15    202504 Öğrenci D       37        44      41.9 Geçti
## 16    202517 Öğrenci Q       53        35      40.4 Geçti
## 17    202507 Öğrenci G       43        37      38.8 Kaldı
## 18    202516 Öğrenci P       24        35      31.7 Kaldı
## 19    202512 Öğrenci L       22        33      29.7 Kaldı
## 20    202518 Öğrenci R       22        31      28.3 Kaldı
cat("\n\n") # Çıktılar arasına boşluk bırakmak için
# --- Adım 2: Sınıf Analizi ve İçgörü Çıkarma ---

# --- Çözüm 2.1: Geçen ve Kalan Öğrenci Sayısı ---
cat("--- Soru 2.1 Çıktısı: Sınıftaki Geçen ve Kalan Öğrenci Sayısı ---\n")
## --- Soru 2.1 Çıktısı: Sınıftaki Geçen ve Kalan Öğrenci Sayısı ---
print(
  basari_tablosu %>%
    count(Sonuc)
)
##   Sonuc  n
## 1 Geçti 16
## 2 Kaldı  4
cat("\n\n")
# --- Çözüm 2.2: Sınıfın Genel Not Ortalamaları ---
cat("--- Soru 2.2 Çıktısı: Sınıfın Genel Not Ortalamaları ---\n")
## --- Soru 2.2 Çıktısı: Sınıfın Genel Not Ortalamaları ---
print(
  basari_tablosu %>%
    summarise(
      OrtalamaVize = mean(VizeNotu),
      OrtalamaFinal = mean(FinalNotu),
      OrtalamaGecme = mean(GecmeNotu)
    )
)
##   OrtalamaVize OrtalamaFinal OrtalamaGecme
## 1           53          56.9         55.73
cat("\n\n")
# --- Çözüm 2.3: Geçen ve Kalanların Not Ortalamaları ---
cat("--- Soru 2.3 Çıktısı: Geçen ve Kalanların Not Ortalamaları ---\n")
## --- Soru 2.3 Çıktısı: Geçen ve Kalanların Not Ortalamaları ---
print(
  basari_tablosu %>%
    group_by(Sonuc) %>%
    summarise(
      OrtalamaVize = mean(VizeNotu),
      OrtalamaFinal = mean(FinalNotu),
      OgrenciSayisi = n(),
      .groups = 'drop'
    )
)
## # A tibble: 2 × 4
##   Sonuc OrtalamaVize OrtalamaFinal OgrenciSayisi
##   <chr>        <dbl>         <dbl>         <int>
## 1 Geçti         59.3          62.6            16
## 2 Kaldı         27.8          34               4
cat("\n\n")
# --- Çözüm 2.4: Vizesi Düşük Olup Dersi Kurtaranlar ---
cat("--- Soru 2.4 Çıktısı: Vizesi 50 Altında Olup Dersi Kurtaranlar ---\n")
## --- Soru 2.4 Çıktısı: Vizesi 50 Altında Olup Dersi Kurtaranlar ---
print(
  basari_tablosu %>%
    filter(VizeNotu < 50, Sonuc == "Geçti")
)
##   OgrenciNo OgrenciAd VizeNotu FinalNotu GecmeNotu Sonuc
## 1    202511 Öğrenci K       45        98      82.1 Geçti
## 2    202514 Öğrenci N       46        78      68.4 Geçti
## 3    202503 Öğrenci C       44        72      63.6 Geçti
## 4    202510 Öğrenci J       39        47      44.6 Geçti
## 5    202504 Öğrenci D       37        44      41.9 Geçti