Hafta_3 Veri Temizleme

Yazar

Enes Cetinkaya

Yayınlanma Tarihi

19 Ekim 2026

Veri Hazırlığı

Kod
library(readr)
library(dplyr)
library(tidyr)
library(stringr)
library(lubridate)
library(haven)
library(here)

ogrenci <- read_csv(here("veri", "OKUL2026_ogrenci.csv"))

Görev 1 - Uç değer taraması

Kod
range(ogrenci$calisma_saati)
[1]  0.0 37.4
Kod
range(ogrenci$kurs_saati)
[1]  0.0 39.1
Kod
range(as.numeric(str_replace(ogrenci$ekran_suresi, ",", ".")))
[1]  0.2 10.3

Cevap:

  • calisma_saati: 0 ile 37.4 arasında. 0 mantıklı, hiç ders çalışmayan öğrenci olabilir. 37.4 de çalışkan bir öğrencinin haftalık ders çalışma süresi olabilir. Mantıklı.

  • kurs_saati: 0 ile 39.1 arasında. 0 mantıklı, kursa gitmeyen öğrenci olabilir. 39.1 saat dönem içinde düşündüğümüzde yine olabilecek bir süre.

  • ekran_suresi: metin olarak geldiği için virgülü noktaya çevirip baktım. 0.2 ile 10.3 arasında. İki değer de mantıklı.

Görev 2 - Kendi temizliğim

Kod
ogrenci_v1 <- ogrenci %>%
  mutate(
    # 1. tutarsız etiketler (ham veride "Kız" yazımı da var)
    cinsiyet = case_when(
      cinsiyet %in% c("Kiz", "Kız", "K", "kiz", "1") ~ "Kiz",
      cinsiyet %in% c("Erkek", "E", "erkek", "2")    ~ "Erkek"
    ),
    cinsiyet = factor(cinsiyet, levels = c("Kiz", "Erkek")),

    # 2. kodlanmış eksik
    anne_egitim = if_else(anne_egitim == 999, NA_real_, anne_egitim),

    # 3. kodlanmış eksik + imkânsız değer
    devamsizlik_gun = case_when(
      devamsizlik_gun == -99 ~ NA_real_,
      devamsizlik_gun > 200  ~ NA_real_,
      .default = devamsizlik_gun
    ),

    # 4. metin olarak gelen sayı
    ekran_suresi = as.numeric(str_replace(ekran_suresi, ",", ".")),

    # 5. iki biçimli tarih
    kayit_tarihi = as.Date(parse_date_time(kayit_tarihi,
                                           orders = c("dmy", "ymd")))
  )

saveRDS(ogrenci_v1, here("cikti", "ogrenci_v1.rds"))
Kod
table(ogrenci_v1$cinsiyet, useNA = "ifany")

  Kiz Erkek 
 8810  9204 
Kod
class(ogrenci_v1$kayit_tarihi)
[1] "Date"
Kod
sum(is.na(ogrenci_v1$ekran_suresi))
[1] 0
Kod
all.equal(ogrenci_v1, readRDS(here("veri", "OKUL2026_temiz.rds")))

Cevap:

  • Ham veride kızların bir kısmı "Kız" diye yazılmış bu yazımı listeye eklemeseydim 6312 satır NA oluyordu.

  • Cinsiyet tablosunun toplamı 18014 (Kiz 8810, Erkek 9204).

  • kayit_tarihi “Date”.

  • ekran_suresi’nde NA sayısı 0.

Görev 3 - Eksiklik sınaması

Kod
ogrenci %>%
  mutate(anne_eksik = anne_egitim == 999) %>%
  group_by(anne_eksik) %>%
  summarise(
    n           = n(),
    sed_ort     = mean(sosyoekonomik_indeks),
    turkce_ort  = mean(turkce_puan),
    calisma_ort = mean(calisma_saati)
  )
# A tibble: 2 × 5
  anne_eksik     n  sed_ort turkce_ort calisma_ort
  <lgl>      <int>    <dbl>      <dbl>       <dbl>
1 FALSE      16573  0.00187       500.        6.59
2 TRUE        1441 -0.0246        499.        6.65

Cevap:

Anne eğitimi eksik olanlarla olmayanlar arasında üç değişkende de neredeyse hiç fark yok, bu yüzden eksiklik rastgele görünüyor. Bu karşılaştırma ise eksikliğin anne eğitiminin kendi değerine bağlı olup olmadığını (MNAR) gösteremez, sonuç MCAR ile tutarlı ama onu kanıtlamaz.

Görev 4 - across

Kod
ogrenci_v1 %>%
  summarise(across(m01:m25, ~ sum(is.na(.)))) %>%
  pivot_longer(everything(), names_to = "madde", values_to = "eksik") %>%
  arrange(desc(eksik))
# A tibble: 25 × 2
   madde eksik
   <chr> <int>
 1 m12     360
 2 m19     360
 3 m01       0
 4 m02       0
 5 m03       0
 6 m04       0
 7 m05       0
 8 m06       0
 9 m07       0
10 m08       0
# ℹ 15 more rows

Cevap:

Yalnızca m12 ve m19’da eksik var, ikisinde de 360. Testte bazı öğrencilerin soruyu boş bırakması beklenen bir durum ancak toplam puan hesaplanırken bu eksiklerin nasıl ele alınacağına karar vermek gerekiyor.

Görev 5 - PISA’da eksik veri

Kod
pisa <- readRDS(here("veri", "PISA2025_TR_stu.rds"))

1. Seçtiğim anket maddeleri: ST034Q01TA ve ST438Q01DA.

Kod
pisa %>%
  summarise(across(c(ST004D01T, ST001D01T, ESCS, PV1MATH,
                     ST034Q01TA, ST438Q01DA),
                   ~ sum(is.na(.))))
# A tibble: 1 × 6
  ST004D01T ST001D01T  ESCS PV1MATH ST034Q01TA ST438Q01DA
      <int>     <int> <int>   <int>      <int>      <int>
1         0         0   253       0         72        168

3.

Kod
pisa %>%
  mutate(
    escs_eksik = is.na(ESCS),
    cinsiyet   = as_factor(ST004D01T)
  ) %>%
  group_by(escs_eksik) %>%
  summarise(
    n         = n(),
    mat_ort   = mean(PV1MATH),
    kiz_orani = mean(cinsiyet == "Female")
  )
# A tibble: 2 × 4
  escs_eksik     n mat_ort kiz_orani
  <lgl>      <int>   <dbl>     <dbl>
1 FALSE       7449    468.     0.535
2 TRUE         253    382.     0.372

Cevap:

1. ST004D01T, ST001D01T ve PV1MATH’te eksik yok. ESCS’de 253, ST034Q01TA’da 72, ST438Q01DA’da 168 eksik var.

2. OKUL2026’da eksikler sayı olarak kodlanmış ve R onları gerçek değer sanıyor. PISA’nın özgün SPSS dosyasında eksik kodlar “kullanıcı tanımlı eksik değer” olarak işaretli. Ders dosyasında bunlar NA’ya çevrilmiş. Özgün dosyada eksik cevap dört türe ayrılıyordu: geçerli atlama, uygulanmadı, geçersiz ve cevap yok. Hepsi tek bir NA’da birleşince eksikliğin türü, yani neden eksik olduğu bilgisi kayboldu.

3. ESCS’si eksik olan öğrencilerin matematik ortalaması 382, olmayanların 468. Eksik olanlarda kız oranı da daha düşük (%37’ye karşı %53.5). Eksiklik rastgele görünmüyor. Yalnızca PV1MATH kullandım, ağırlık kullanmadım. Sonuç örneklemdeki öğrenciler için geçerli.

Hatalı Çıktı

Kod
ogrenci %>%
  filter(devamsizlik_gun > 20) %>%
  summarise(n = n(), mat_ort = mean(mat_puan))
# A tibble: 1 × 2
      n mat_ort
  <int>   <dbl>
1   309    427.

Cevap:

1. Ham veride 309 satır seçilirdi: 285 öğrenciye ek olarak devamsızlığı 365, 400 ve 999 girilmiş 24 imkânsız değer. −99 olarak kodlanmış eksikler 20’den küçük olduğu için seçilmezdi.

2. Hayır. Veri yalnızca devamsızlık ile matematik puanı arasında bir ilişki olduğunu gösteriyor, “düşürüyor” demek neden-sonuç iddiasıdır ve bu veriden çıkarılamaz.