1 Giriş

Veri olarak psych paketindeki bfi (Big Five Inventory, 25 madde + 3 demografik değişken, 2800 gözlem) kullanılacaktır. Hem psikometrik alana yakın hem de zaten NA içerdiği için “tüm maddelere aynı işlemi uygula” görevini gerçekçi kılıyor.


2 Referans Tablosu

Döngü ve Apply Ailesi — Tek Bakışta
Sezgi + minimal sentaks
Yapı Ne Zaman Minimal Örnek
for Belirli sayıda tekrar; her adımda durumu güncellemek gerektiğinde. for (i in 1:5) { ... }
while Tekrar sayısı önceden bilinmiyor; bir koşul sağlanana kadar. while (kosul) { ... }
apply Matris/data.frame'in satırlarına (MARGIN=1) veya sütunlarına (MARGIN=2) tek bir işlev. apply(mat, 2, mean)
sapply Vektör/liste üzerine işlev; çıktı mümkünse vektör, değilse liste. sapply(liste, length)
lapply Vektör/liste üzerine işlev; çıktı **her zaman** liste. lapply(liste, summary)
vapply sapply gibi ama çıktı tipi önceden belirtilir; güvenli sürüm. vapply(liste, length, integer(1))
mapply Birden fazla vektörü paralel olarak işlevle dolaşmak. mapply(f, x, y)
dplyr::across Tidyverse'de bir veri çerçevesinin **birden çok sütununa** aynı işlev(ler)i uygulamak. summarise(across(.cols, .fn))

sapply “akıllı” görünür ama çıktı tipi veriye göre değişir; aynı kod ileride farklı veride liste döndürebilir, matris döndürebilir. Üretim kodunda vapply veya purrr::map_* tercih edilir. lapply “dürüst”tür — her zaman liste verir.


3 Veri Setinin Tanıtımı

3.1 Genel Yapı

psych::bfi, Goldberg (1992) Big Five maddelerinden 25’inin 2800 yetişkin katılımcıdan toplanmış halidir. Her madde 1–6 arası ordinal bir skalada işaretlenmiştir; üç de demografik değişken (yaş, cinsiyet, eğitim) eklidir.

suppressPackageStartupMessages({
  library(psych)
  library(dplyr)
  library(gt)
})

data(bfi, package = "psych")

cat("Boyut    :", paste(dim(bfi), collapse = " x "), "\n")
## Boyut    : 2800 x 28
cat("Sınıf    :", class(bfi), "\n")
## Sınıf    : data.frame
cat("Toplam NA:", sum(is.na(bfi)), "\n")
## Toplam NA: 731

3.2 Boyutlar ve Türkçe Karşılıklar

Maddeler beş kişilik boyutuna karşılık gelir. Sütun isimleri (A1–O5) İngilizce kısaltmadan gelir; raporun anlaşılırlığı için Türkçe karşılıkları aşağıda verilmiştir.

BFI — Beş Faktör ve Türkçe Karşılıkları
Madde Kodu İngilizce Türkçe Örnek Madde (TR)
A1–A5 Agreeableness Uyumluluk Başkalarına karşı ilgisizimdir. (A1)
C1–C5 Conscientiousness Öz-disiplin / Sorumluluk Eşyaları yerli yerine koyarım. (C1)
E1–E5 Extraversion Dışadönüklük Pek konuşkan biri değilim. (E1)
N1–N5 Neuroticism Nevrotiklik Sık sık öfkelenirim. (N1)
O1–O5 Openness Deneyime Açıklık Maceradan hoşlanırım. (O1)

3.3 İlk Bakış: head(), str(), glimpse()

head(bfi[, 1:8], 5)
glimpse(bfi[, 1:8])
## Rows: 2,800
## Columns: 8
## $ A1 <int> 2, 2, 5, 4, 2, 6, 2, 4, 4, 2, 4, 2, 5, 5, 4, 4, 4, 5, 4, 4, 5, 1, 1…
## $ A2 <int> 4, 4, 4, 4, 3, 6, 5, 3, 3, 5, 4, 5, 5, 5, 5, 3, 6, 5, 4, 4, 4, 6, 5…
## $ A3 <int> 3, 5, 5, 6, 3, 5, 5, 1, 6, 6, 5, 5, 5, 5, 2, 6, 6, 5, 5, 6, 2, 6, 6…
## $ A4 <int> 4, 2, 4, 5, 4, 6, 3, 5, 3, 6, 6, 5, 6, 6, 2, 6, 2, 4, 4, 5, 1, 1, 5…
## $ A5 <int> 4, 5, 4, 5, 5, 5, 5, 1, 3, 5, 5, 5, 4, 6, 1, 3, 5, 5, 3, 5, 2, 5, 6…
## $ C1 <int> 2, 5, 4, 4, 4, 6, 5, 3, 6, 6, 4, 5, 5, 4, 5, 5, 4, 5, 5, 1, 4, 5, 4…
## $ C2 <int> 3, 4, 5, 4, 4, 6, 4, 2, 6, 5, 3, 4, 4, 4, 5, 5, 4, 5, 4, 1, 6, 4, 3…
## $ C3 <int> 3, 4, 4, 3, 5, 6, 4, 4, 3, 6, 5, 5, 3, 4, 5, 5, 4, 5, 5, 1, 5, 4, 2…

İlk beş satıra ve sütun yapısına bakınca veri çerçevesinin tamamen sayısal olduğunu, maddelerde NA bulunduğunu ve demografik değişkenlerin (gender, education, age) sonda yer aldığını görüyoruz. Bu görüntü, “tüm maddelere aynı işlemi uygula” sorusunu doğal bir biçimde gündeme getiriyor: 25 sütunu elle yazmak istemiyoruz.


4 Uygulama: Tek Soru, Üç Çözüm

Soru: bfi veri setindeki 25 madde sütunu için her birinin ortalama, standart sapma ve NA sayısını hesapla. Sonucu bir tablo olarak ver.

Aynı soruyu sırayla: (1) for döngüsü, (2) sapply, (3) dplyr::across ile çözüp karşılaştıracağız.

maddeler <- bfi[, 1:25]
cat("Madde sayısı:", ncol(maddeler), "\n")
## Madde sayısı: 25
cat("Gözlem sayısı:", nrow(maddeler), "\n")
## Gözlem sayısı: 2800

4.1 1. Yol — for Döngüsü

sonuc_for <- data.frame(
  Madde     = character(),
  Ortalama  = numeric(),
  SS        = numeric(),
  NA_Sayisi = integer(),
  stringsAsFactors = FALSE
)

for (j in seq_along(maddeler)) {
  x <- maddeler[[j]]
  sonuc_for[j, "Madde"]     <- names(maddeler)[j]
  sonuc_for[j, "Ortalama"]  <- mean(x, na.rm = TRUE)
  sonuc_for[j, "SS"]        <- sd(x,   na.rm = TRUE)
  sonuc_for[j, "NA_Sayisi"] <- sum(is.na(x))
}

head(sonuc_for, 5)

4.2 2. Yol — sapply

ozet_fn <- function(x) {
  c(Ortalama  = mean(x, na.rm = TRUE),
    SS        = sd(x,   na.rm = TRUE),
    NA_Sayisi = sum(is.na(x)))
}

sonuc_sapply <- t(sapply(maddeler, ozet_fn))
sonuc_sapply <- data.frame(
  Madde = rownames(sonuc_sapply),
  sonuc_sapply,
  row.names = NULL
)

head(sonuc_sapply, 5)

4.3 3. Yol — dplyr::across

sonuc_across <- maddeler |>
  summarise(across(
    everything(),
    list(Ortalama  = ~ mean(.x, na.rm = TRUE),
         SS        = ~ sd(.x,   na.rm = TRUE),
         NA_Sayisi = ~ sum(is.na(.x))),
    .names = "{.col}__{.fn}"
  )) |>
  tidyr::pivot_longer(
    everything(),
    names_to  = c("Madde", "Istatistik"),
    names_sep = "__",
    values_to = "Deger"
  ) |>
  tidyr::pivot_wider(
    names_from  = Istatistik,
    values_from = Deger
  )

head(sonuc_across, 5)

5 Karşılaştırma

ort_for     <- round(sonuc_for$Ortalama, 4)
ort_sapply  <- round(sonuc_sapply$Ortalama, 4)
ort_across  <- round(sonuc_across$Ortalama, 4)

all.equal(ort_for, ort_sapply)
## [1] TRUE
all.equal(ort_for, ort_across)
## [1] TRUE

Üç yöntem de aynı sayıları üretiyor.

5.1 Hız: microbenchmark

suppressPackageStartupMessages(library(microbenchmark))

hiz <- microbenchmark(
  for_dongu = {
    s <- data.frame(O = numeric(25), S = numeric(25), N = integer(25))
    for (j in seq_along(maddeler)) {
      x <- maddeler[[j]]
      s$O[j] <- mean(x, na.rm = TRUE)
      s$S[j] <- sd(x,   na.rm = TRUE)
      s$N[j] <- sum(is.na(x))
    }
  },
  sapply_yolu = t(sapply(maddeler, ozet_fn)),
  across_yolu = maddeler |>
    summarise(across(everything(),
                     list(O = ~mean(.x, na.rm = TRUE),
                          S = ~sd(.x,   na.rm = TRUE),
                          N = ~sum(is.na(.x))))),
  times = 50
)

print(hiz)
## Unit: microseconds
##         expr      min       lq     mean    median       uq      max neval
##    for_dongu 2058.938 2173.902 2341.359 2228.4730 2321.707 4052.645    50
##  sapply_yolu  497.535  572.524  632.252  595.7505  615.369 2871.968    50
##  across_yolu 3124.610 3254.375 3618.339 3362.6150 3594.142 8244.239    50

6 Hangisi Ne Zaman?

for döngüsü — Her adımın çıktısı bir sonrakine bağlıysa (Markov zinciri, EM iterasyonu, kümülatif güncelleme). Yani bağımsız tekrar değil, dizili tekrar varsa.

sapply / vapply / lapply — Tekrarlar bağımsız olduğunda (her sütun, her grup, her simülasyon iterasyonu). En klasik R sezgisi: “vektörel düşün, döngüyü R’a yaptır.”

dplyr::across — Veri çerçevesi üzerinde çalışıyorsan, sonuç yeniden bir veri çerçevesi olacaksa ve okuyucunun niyetini hızla yakalaması önemliyse. Rapor kodu, analiz pipeline’ı için ideal.