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.
| 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.
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
## Sınıf : data.frame
## Toplam NA: 731
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) |
head(), str(), glimpse()## 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.
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.
## Madde sayısı: 25
## Gözlem sayısı: 2800
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)sapplyozet_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)dplyr::acrosssonuc_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)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
## [1] TRUE
Üç yöntem de aynı sayıları üretiyor.
microbenchmarksuppressPackageStartupMessages(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
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.