Kurs
R Apply Ailesi Üzerine Bir Not
R Apply Ailesi, kullanıcıların bir vektör, liste veya matrisin öğelerine bir fonksiyon uygulamasına olanak tanıyan bir R fonksiyonları kümesidir. Ancak bu işlevsellik artık eski (legacy) kabul edilir ve yeni kodlarda kullanılmamalıdır. Bunun yerine, R’de tüm döngüler için purrr paketi önerilir. purrr, birden çok girdi ve çıktı alan fonksiyonlarla çalışmak için tutarlı bir sözdizimi sağlar; bu da kod yazmayı ve okumayı kolaylaştırır. Ayrıca purrr, modern bilgi işlem ortamları için optimize edilmiş bir dizi fonksiyon sunar ve Apply Ailesi’nden daha hızlı ve verimlidir. Özetle, R Apply Ailesi bazı uygulamalarda hâlâ iş görse de, yeni R projelerinde purrr paketini kullanmanız tavsiye edilir.
Döngülere Alternatif Olarak Apply Fonksiyonları
Bu yazıda, farklı veri yapıları üzerinde R apply() fonksiyonunu, mapply() gibi türevlerini ve apply()’ın bazı akrabalarını nasıl kullanabileceğinizi göreceksiniz. Elbette tüm türevleri ele almak mümkün değil; ancak uygun olduğunda, biraz daha kapsamlı iki örnek üzerinden bu fonksiyonların birlikte kullanımına da giriş yapacaksınız.
Ayrıca, listeleri, vektörleri, dizileri (array) ve veri çerçevelerini daha iyi anlamak için şu R’ye giriş kursuna göz atmanız faydalı olabilir; yine de bu yazıyı takip etmek için mutlaka tüm eğitimi tamamlamanız gerekmez!
apply() Ailesi
apply() ailesi, R’nin temel (base) paketine aittir ve matris, dizi (array), liste ve veri çerçevelerinin dilimlerini yineli bir biçimde işlemek için fonksiyonlar içerir. Bu fonksiyonlar, veriyi çeşitli şekillerde taramaya olanak tanır ve açık döngü yapıları kullanma ihtiyacını ortadan kaldırır. Bir giriş listesi, matris veya dizi üzerinde çalışırlar ve bir veya birkaç isteğe bağlı argümanla birlikte adlandırılmış bir fonksiyonu uygularlar.
Çağrılan fonksiyon şunlardan biri olabilir:
- Ortalama veya toplam gibi bir birleştirme (agregasyon) fonksiyonu (bir sayı ya da skaler döndürür);
- Diğer dönüştürücü veya alt kümeleme fonksiyonları; ve
- Listeler, vektörler, matrisler ve diziler gibi daha karmaşık yapılar üreten diğer vektörleştirilmiş fonksiyonlar.
apply() fonksiyonları, daha karmaşık birleşimlerin temelini oluşturur ve çok az satır kodla işlemler yapmanıza yardım eder. Daha spesifik olarak aile; apply(), lapply() , sapply(), vapply(), mapply(), rapply() ve tapply() fonksiyonlarından oluşur.
Peki bunları nasıl ve ne zaman kullanmalıyız?
Bu, üzerinde işlem yapmak istediğiniz verinin yapısına ve ihtiyaç duyduğunuz çıktı formatına bağlıdır.
R’de apply() Nasıl Kullanılır?
Ailenin “baba”sı apply() ile başlayalım; bu fonksiyon diziler üzerinde çalışır. Basitlik adına, bu eğitim kendini 2B dizilerle, yani matrislerle sınırlar.
R base kılavuzu, çağrının şu şekilde yapıldığını söyler: apply(X, MARGIN, FUN, ...)
burada:
Xbir dizidir; eğer dizinin boyutu 2 ise bir matristir;MARGIN, fonksiyonun nasıl uygulanacağını tanımlar:MARGIN=1olduğunda satırlar üzerinde,MARGIN=2olduğunda sütunlar üzerinde çalışır.MARGIN=c(1,2)kullandığınızda hem satırlara hem sütunlara uygulanır; veFUN, veriye uygulamak istediğiniz fonksiyondur. Herhangi bir R fonksiyonu olabilir; Kullanıcı Tanımlı Fonksiyonlar (UDF) dahil.
Yeni başlayanlar ne olduğunu gözlerinde canlandırmakta zorlanabilir; bu nedenle bir görsel ve biraz kod işinizi görecektir.
5 x 6’lık bir matris oluşturalım ve her sütunun değerlerini toplamak istediğinizi hayal edelim.
Şuna benzer bir şey yazabilirsiniz:
# Construct a 5 x 6 matrix
my_matrix <- matrix(1:30, nrow = 5, ncol = 6)
# Calculate the sum of each column
col_sums <- apply(my_matrix, 2, sum)
# Print the result
print(col_sums)
matrix() fonksiyonu 1’den 30’a kadar değerleri içeren 5 x 6’lık bir matris oluşturur. Ardından apply() fonksiyonunu kullanarak matrisin her sütununa sum() fonksiyonunu uygularız (2, fonksiyonu sütunlara uygulamak istediğimizi belirtir). Ortaya çıkan sütun toplamları vektörü col_sums değişkeninde saklanır ve konsola yazdırılır.
Unutmayın, R’de bir matris, matrisi yukarıdan aşağıya kestiğinizde (boyut ya da kenar 1 boyunca) satır vektörlerinin bir koleksiyonu; soldan sağa (boyut ya da kenar 2 boyunca) kestiğinizde ise sütun vektörlerinin bir listesi olarak görülebilir.
Bu, az önce girdiğiniz ifadenin, şekil 1’de gösterildiği gibi, şu anlama geldiğini belirtir: “X matrisi üzerinde 2. kenar (sütun) boyunca ‘sum’ fonksiyonunu uygula ve her sütunun değerlerini topla.”
Görseli kalabalıklaştırmamak için sadece bir sütun vurgulanmıştır.
Sonuç olarak, her sütunun toplam değerlerini içeren bir satır vektörü elde edersiniz.
Yukarıdaki kodun çıktısı olan satır vektörü, toplamayı matrisin satırları boyunca yapsaydınız da benzer şekilde verilirdi. R sonucu bu şekilde gösterir.
Sonraki not: Çoğu durumda R, dönüş değeri belirtilmemiş olsa bile (ya da daha doğrusu, fonksiyonun dönüş değeri bir değişkene atanmamış olsa da) bir değer döndürebilir. R, basitçe son değerlendirilen nesneyi döndürür. Ancak pratikte, dönüş değerini kontrol etmek istediğinizde ve bu dönüş değerleri üzerinde daha fazla işlem yapmanız gerektiğinde, sonuçları açıkça bir değişkene atamak en iyisidir.
lapply() Fonksiyonu
Bir listenin her öğesine belirli bir fonksiyon uygulayıp sonuçta bir liste elde etmek istediğinizde kullanılır. ?lapply komutunu çalıştırdığınızda, sözdiziminin apply() fonksiyonuna benzediğini görürsünüz.
Farklar şunlardır:
- Veri çerçeveleri, listeler veya vektörler gibi diğer nesneler için de kullanılabilir; ve
- Döndürülen çıktı bir listedir (fonksiyon adındaki “l” bunu açıklar) ve geçirilen nesneyle aynı sayıda öğeye sahiptir.
Nasıl çalıştığını görmek için birkaç matris oluşturup her birinden belirli bir sütunu çıkaralım.
Bu, farklı veri çerçevelerinden karşılaştırmalar veya toplamalar yaparken gerçek veriler üzerinde oldukça yaygın bir işlemdir.
Şekil 2’de gösterilen örnek oyuncağımız şu şekilde kodlanabilir:

İşlem, şekil 2’nin sol tarafında gösterilmiştir.
Yine ilgi nesnesini, yani Mylist listesini belirterek başlarsınız. Standart R seçim operatörü [ kullanılır ve ilk parametreyi atlar (bu da “herhangi biri” anlamına gelir; bu yüzden iki virgül görürsünüz).
Ardından ikinci parametreyi, yani 2’yi belirlersiniz: kenarımız ‘sütun’dur. Böylece listedeki tüm matrislerden ikinci sütunu çıkarırsınız.
Yukarıdaki koda ilişkin birkaç not:
[gösterimi, seçim operatörüdür. Örneğin, B’nin üçüncü satırındaki tüm öğeleri çıkarmak için:B[3,]yazmanız gerektiğini hatırlayın;[[ ]]gösterimi, listelerle uğraştığımızı ifade eder: [[2]] listedeki ikinci öğe demektir. Bu, R’nin verdiği çıktıda da gösterilir;- Çıktı, girdi kadar sayıda öğe içeren bir listedir; ve
- Her matristen tek bir öğe de çıkarabilirdiniz:
lapply(MyList,"[", 1, 2)
Şekil 2’nin sağ tarafında alternatif bir çıkarımı görebilirsiniz: bu kez ilk parametreyi atlayıp her matrisin ilk satırını alırsınız.
Şimdi siz deneyin! Listedeki her matristen ikinci sütunu seçin:
sapply() Fonksiyonu
sapply(), lapply() gibi çalışır; ancak çıktıyı mümkün olan en basit veri yapısına indirmeye çalışır. Nitekim sapply(), lapply() için bir “sarma” (wrapper) fonksiyondur.
Bir örnek yardımcı olabilir: Diyelim ki son örnekteki gibi tek bir öğe çıkarma işlemini tekrarlamak istiyorsunuz; ancak şimdi her matris için ikinci satırın ilk öğesini (2 ve 1 indeksleri) alacaksınız.
lapply() fonksiyonunu uygularsanız, sapply()’a simplify=FALSE parametresini geçmediğiniz sürece bir liste elde edersiniz. Bu parametreyle birlikte bir liste döner. Aşağıdaki kod parçasında nasıl çalıştığını görün:
Benzer şekilde unlist() gibi bir fonksiyon, lappy()’ye bir vektör döndürmesini “söyleyebilir”!
Her neyse, kafa karışıklığını önlemek için bu fonksiyonları ‘yerel formatlarında’ kullanmak ve zorunlu olmadıkça dönüşümlerden kaçınmak en iyisidir.
rep() Fonksiyonu
apply() fonksiyonlarıyla birlikte sık kullanılan bir başka fonksiyon rep()’tir. Bir vektöre veya faktöre x uygulandığında, değerlerini belirtilen sayıda tekrarlar.
Bu kez, MyList içine lapply() ile yukarıda ürettiğiniz vektörlerden birini kullanalım.
Ancak bu defa, MyList listesindeki her öğenin birinci satır ve birinci sütunundaki değerleri seçiyorsunuz (ve bir vektör almak için sapply() kullanıyorsunuz):
Yukarıdaki kodun, Z değerlerini c(3,1,2) ile belirtildiği sayıda tekrarladığını görürsünüz: birinciden üç kez, ikinciden bir kez ve üçüncünden iki kez:
Kullanışlı, değil mi?
mapply() Fonksiyonu
mapply(), ‘çok değişkenli’ (multivariate) apply anlamına gelir. Amacı, normalde argüman olarak vektör kabul etmeyen bir fonksiyonun argümanlarını vektörleştirebilmektir.
Kısacası, mapply() bir Fonksiyonu Birden Fazla Liste veya Birden Fazla Vektör Argümanına uygular.
mapply()’e bir örnek bakalım: rep() fonksiyonunu tekrarlı çağırarak 4 x 4’lük bir matris oluşturuyorsunuz:
Ancak, rep() fonksiyonunun sonuçlarını c() ile birleştirmek yerine daha verimli bir yol olduğunu görürsünüz: mapply() çağırdığınızda, rep() fonksiyonunun eylemini vektörleştirirsiniz.
apply() ile İlgili Fonksiyonlar
Benzer yapıda fonksiyonlar zaman zaman apply() ailesinin öğeleriyle birlikte kullanılır: bu eğitimde bunlardan yalnızca birkaçına genel bir bakış sunulacaktır.
Sweep() Fonksiyonu
sweep() fonksiyonu muhtemelen apply() ailesine en yakın olanıdır. Seçtiğiniz MARGIN öğeleri üzerinde (burada matris durumu ile sınırlı) farklı eylemleri tekrarlamak istediğinizde kullanırsınız.
Kümeleme gibi senaryolarda, veriyi tekrarlı olarak normalize edip merkezlemek ya da “standartlaştırmak” gerekebilir.
Bu ne demek?
Bir veri grubunda çok sayıda veri noktasına sahip olduğunuzu varsayın. Önce verinin merkezini (“kütle merkezi”) bulur, ardından bu verinin bu merkeze göre ne kadar yayıldığına bakarsınız. Size bu bilgiyi verecek iki temel büyüklük ortalama ve standart sapmadır.
Veri noktalarınızın verinizin bir matrisindeki sütun vektörleri olduğunu varsayalım ve bu yazının başında oluşturduğunuz B matrisini kullanalım; ancak şimdi adına dataPoints diyelim.
Önce sütun başına ortalamaları ve yayılımı ya da standart sapmayı apply() fonksiyonlarından biriyle bulursunuz. Ardından tüm noktaları merkezlerine göre kaydırırsınız. Bu, önce bulduğunuz ortalamanın, veriyi standart sapmalarına göre normalize etmek için kullanılacağı anlamına gelir:
Tek bir sweep() çağrısıyla merkezlenmiş noktaları ürettiniz. Bu fonksiyon şu öğeleri bekler:
- bir giriş dizisi; burada bir matris,
- bir MARGIN; sütunları belirtmek için
2, - bir özet istatistik (burada
mean), ve - uygulanacak bir fonksiyon. Çıkarma için aritmetik
“-”operatörünü kullanırsınız.
Bu şu anlama gelir: “MyPoints veri kümesinin sütunlarındaki öğeleri al ve her birinden dataPoints_means ortalamasını çıkar”.
Şimdi sweep()’i tekrar çağırıp, az önce bulduğunuz tüm değerleri kendi standart sapmalarına bölersiniz. Bu adıma “normalize etme” denir. Yine MARGIN=2 seçer ve standart sapmalar vektörü dataPoints_sdev’i işleç olarak verirsiniz. Sonra bölme operatörünü “/” geçersiniz.
R’den istediğiniz şey şudur: “Az önce oluşturduğun yeni nesnenin, dataPoints_Trans1’in sütunlarındaki öğeleri al ve bunları (“/”) kendi standart sapmaları dataPoints_sdev ile böl”.
Elbette aynı sonucu daha hızlı ve özlü biçimde (R’de sıkça olduğu gibi!) ve farklı adlar kullanmadan, iç içe bir sweep() çağrısıyla tek satırda da elde edebilirdiniz:
İstatistiksel olarak, bir korelasyon matrisi oluşturmuş oldunuz ve standartlaştırılmış veriler, PCA ile boyut indirgeme, sinyal analizi ve diğer pek çok gelişmiş yöntemin temelini oluşturur.
aggregate() Fonksiyonu
Bu fonksiyon stats paketinde yer alır ve şu şekilde kullanılır: aggregate(x, by, FUN, ..., simplify = TRUE).
Başka bir deyişle, apply() fonksiyonuna benzer şekilde çalışır: nesneyi, fonksiyonu belirtirsiniz ve sapply()’da olduğu gibi basitleştirip basitleştirmeyeceğinizi söylersiniz. Kritik fark, hangi değişken ya da veri çerçevesi alanına göre toplama (agregasyon) yapmak istediğimizi belirleyen by yan tümcesinin kullanımıdır.
Bir sonraki bölüm bunun nasıl çalıştığını gösterecek.
aggregate() Örneği
Mydf adlı, bir ürünün satışlarına ilişkin veriler içeren ve DepPC değişkeninin bazı değerlerinin tekrarlandığı oyuncak veri setini düşünün.
Bu değişken, veriyi bir coğrafi konuma göre sınıflandırır; posta kodunun bir bölümü gibi (buradaki sayılar, Paris’i kapsayan Île de France bölgesinin departmanlarına karşılık gelir).
Satış sütunları üzerinde bazı istatistikler yapmak istiyorsunuz. Bunlar; zamanla artan bir sıra numarası olan DProgr, ürünün satışı (Qty miktarı) ve ürünün teslim edilip edilmediğini söyleyen mantıksal Delivered değişkenidir (T ya da F).
Öncelikle, veri setini tanımak için adını yazarak tamamını göstermek dışında, birkaç basit şey yapabilirsiniz (burada yalnızca 120 kayıt var; ama binlerce satırlık gerçek bir dosyada yaptığınızı hayal edin!).
Veriyi keşfedelim:
Not: Veri çerçevesinin içerdiği satır ve sütun sayısını görmek isterseniz nrow(Mydf) ve ncol(Mydf) da çağırabilirsiniz.
Veri üzerinde yapılabilecek pek çok başka sorgu vardır.
Burada örneğin, ürünün hangi departmanda daha iyi sattığını bilmekle ilgileniyorsunuz. Bu yüzden veriyi departmana göre gruplayıp, her departman DepPC için satışları, yani Qty’yi, aggregate() fonksiyonunun yardımıyla toplamalısınız:
Yani, aggregate() R’a aynı departmana ait tüm Qty değerlerini toplamak istediğinizi söyler.
R, siz aksi söylemediğiniz için toplamı ‘x’ adlı bir değişkene atadı.
Çıktı bu haliyle oldukça okunaklıdır; ancak departman sayısı arttıkça daha az okunaklı olabilir. Bu durumlarda grafiksel çıktılara başvurabilirsiniz: aggregate() fonksiyonu ile birlikte R’nin grafik sistemlerinden birini kullanarak sonuçları çizersiniz:
Bu, her departman için satışları verir.
Aynı soruyu yalnızca teslim edilmiş ürünler için de sorabilirsiniz. Bunu yapmak için önce, teslim edilenin doğru (T) olduğu verileri artık aşina olduğunuz "[" alt kümeleme operatörü ile alt kümeye ayırırsınız.
Not: Burada sonucu, ebeveyn veri çerçevesi Mydf’den aynı sütun adlarını miras alan yeni bir veri çerçevesi olan Y adlı bir değişkene atarsınız. Bunu, okunabilirlik için çizim çağrısı içinde toplama ifadesini tekrarlamamak adına yapıyorsunuz:
Görüldüğü gibi, aggregate() ile olduğu gibi, veriye vektörleştirilmiş biçimde farklı sorular sorabilir ve bunu çoğunlukla ggplot2 gibi kullanışlı bir grafik sistemiyle birlikte yaparsınız; mesele bu.
Üstelik bunu elde etmek için çok az satır kod yeterlidir.
Döngülere ve Apply Fonksiyonlarına Alternatif Olarak Vektörleştirme?
Aynı temanın bazı varyasyonlarını gördünüz: “yapılandırılmış bir veri kümesi üzerinde yineli şekilde işlem yapmak”. Bu anlamda, bu fonksiyonlar yalnızca döngülere alternatif olarak değil, işleri vektörleştirilmiş biçimde yapmanın bir yolu olarak da görülebilir.
Burada “vektörleştirilmiş”i geniş anlamda kullanıyoruz; hangi apply() fonksiyonlarının gerçekten vektörleştirilmiş olduğuna dair tartışmaya girmeyeceğiz (örneğin buradaki tartışmaya bakın).
Pratikte, hangi apply() fonksiyonunu kullanacağınıza karar vermek için şunları göz önünde bulundurmalısınız:
- Girdinin veri türü: üzerinde işlem yapacağınız nesne (vektör, matris, dizi…, liste, veri çerçevesi ya da bunların bir birleşimi)
- Ne yapmayı amaçladığınız: geçirmek istediğiniz
FUNfonksiyonu - Verinin hangi alt kümeleri: satırlar, sütunlar ya da hepsi mi?
- Fonksiyondan hangi tür veriyi almak istiyorsunuz? Çünkü üzerinde ek işlemler yapmak isteyebilirsiniz (yeni bir nesne mi istiyorsunuz, yoksa girdi nesnesini doğrudan dönüştürmek mi?)
Benzer soruları, ele aldığımız aggregate(), by(), sweep() vb. ilişkili fonksiyonlar için de sorabilirsiniz.
Ancak çok daha fazlası var! Şimdi keşfetmeyi bırakmayın! DataCamp’in R’de Diziler (Arrays) eğitimine göz atın.
Bu eğitimin devamı olarak, DataCamp’in Introduction to R veya Intermediate R kurslarını almayı düşünebilirsiniz.

