Her şeyden önce, R’daki en temel veri yapısı olan
vektör üzerinde çalışalım. Bir vektör, basitçe sıralı
bir elemanlar listesidir. Veri çerçevelerinin o karmaşık
[satır, sütun]
yapısına geçmeden önce, bir vektörün
elemanlarına nasıl erişeceğimizi ve onları nasıl seçeceğimizi anlamamız
çok önemlidir.
R’daki ana dilimleme (slicing) aletimiz [ ]
(köşeli parantezler) operatörüdür.
Bir vektördeki belirli bir elemana ulaşmak için, köşeli parantez içine o elemanın sıra numarasını (indeksini) yazarız. Unutmayın, R’da sayma her zaman 1’den başlar!
# Örnek bir vektör oluşturalım: Haftanın sıcaklıkları
sicakliklar <- c(22.5, 24.0, 23.1, 21.8, 25.2, 26.0, 24.5)
# 3. günün sıcaklığını öğrenelim
sicakliklar[3]
## [1] 23.1
# Vektörün içindeki eleman sayısını(vektörün uzunluğunu) öğrenelim
length(sicakliklar)
## [1] 7
# Son elemanı öğrenelim (length() fonksiyonu bize vektörün uzunluğunu verir)
sicakliklar[length(sicakliklar)]
## [1] 24.5
c()
Fonksiyonu ile Manuel SeçimBirden fazla, ama sırası ardışık olmayan elemanları seçmek için, sıra
numaralarını c()
fonksiyonu ile bir vektör haline getirip
[ ]
içine yazarız.
# Sadece hafta sonu sıcaklıklarını (6. ve 7. günler) alalım
sicakliklar[c(6, 7)]
## [1] 26.0 24.5
# Sadece 1., 3. ve 5. günlerin sıcaklıklarını alalım
sicakliklar[c(1, 3, 5)]
## [1] 22.5 23.1 25.2
seq()
Fonksiyonu ile Programatik SeçimPeki ya her iki günde bir olan sıcaklıkları (1., 3., 5., 7.) almak
isteseydik? Bunları elle yazmak yerine, seq()
(sequence -
dizi) fonksiyonu ile bir sayı dizisi oluşturabiliriz.
seq()
fonksiyonu üç temel argüman alır:
from
(başlangıç), to
(bitiş) ve
by
(artış miktarı).
# 1'den başlayıp vektörün sonuna kadar (length(sicakliklar))
# 2'şer 2'şer giden bir sayı dizisi oluşturalım
tek_gunler_indeksi <- seq(from = 1, to = length(sicakliklar), by = 2)
tek_gunler_indeksi
## [1] 1 3 5 7
# Şimdi bu ürettiğimiz indeksi kullanarak sıcaklıkları seçelim
sicakliklar[tek_gunler_indeksi]
## [1] 22.5 23.1 25.2 24.5
Bu yöntem, özellikle çok uzun vektörlerle çalışırken inanılmaz derecede güçlüdür!
:
Operatörü ileEğer ardışık bir eleman grubunu seçmek istiyorsak, :
operatörü imdadımıza yetişir.
# Hafta içi sıcaklıklarını (1'den 5'e kadar olan günler) alalım
sicakliklar[1:5]
## [1] 22.5 24.0 23.1 21.8 25.2
# 3. günden 6. güne kadar olan sıcaklıklar
sicakliklar[3:6]
## [1] 23.1 21.8 25.2 26.0
-
(Eksi) İşareti ileBazen belirli elemanlar dışındaki her şeyi almak
isteyebiliriz. Bunun için, hariç tutmak istediğimiz sıra numaralarının
başına -
(eksi) işareti koyarız.
# Hafta sonu (6. ve 7. günler) DIŞINDAKİ tüm sıcaklıkları alalım
sicakliklar[-c(6, 7)]
## [1] 22.5 24.0 23.1 21.8 25.2
# Sadece ilk gün DIŞINDAKİ tüm sıcaklıklar
sicakliklar[-1]
## [1] 24.0 23.1 21.8 25.2 26.0 24.5
# Son gün DIŞINDAKİ tüm sıcaklıklar
# 1.yöntem
sicakliklar[-length(sicakliklar)]
## [1] 22.5 24.0 23.1 21.8 25.2 26.0
# 2. yöntem
# 1'den başla, (toplam uzunluk - 1)'e kadar olan elemanları seç
sicakliklar[1:(length(sicakliklar) - 1)]
## [1] 22.5 24.0 23.1 21.8 25.2 26.0
# 3. yöntem
# head(vektör, kaç eleman almak istediğin)
head(sicakliklar, n = length(sicakliklar) - 1)
## [1] 22.5 24.0 23.1 21.8 25.2 26.0
# 3. yöntemin pratik hali
# n'e negatif bir sayı vermek, sondan o kadar elemanı çıkarır.
head(sicakliklar, n = -1)
## [1] 22.5 24.0 23.1 21.8 25.2 26.0
Bu bölümde de mtcars
veri setimizin düzenlenmiş hali
olan cars_data
’yı kullanacağız.
# Önceki bölümlerden hatırlayacağımız üzere, veri setimizi hazırlıyoruz.
library(tibble)
cars_data <- mtcars %>%
rownames_to_column(var = "model")
print(cars_data)
## model mpg cyl disp hp drat wt qsec vs am gear carb
## 1 Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
## 2 Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
## 3 Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
## 4 Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
## 5 Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
## 6 Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
## 7 Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
## 8 Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
## 9 Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
## 10 Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
## 11 Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
## 12 Merc 450SE 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3
## 13 Merc 450SL 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3
## 14 Merc 450SLC 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3
## 15 Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
## 16 Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
## 17 Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
## 18 Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1
## 19 Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
## 20 Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1
## 21 Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1
## 22 Dodge Challenger 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2
## 23 AMC Javelin 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2
## 24 Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
## 25 Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2
## 26 Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1
## 27 Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
## 28 Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
## 29 Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
## 30 Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
## 31 Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
## 32 Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2
# bu komut ile tüm veri seti gelir pek tercih edilmez.
# çünkü veri satır sayısı çok fazla olduğunda bu komut anlamsız olur
# onun yerine veri setinin ilk 6 satırını görmek fikir verir.
print(head(cars_data))
## model mpg cyl disp hp drat wt qsec vs am gear carb
## 1 Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
## 2 Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
## 3 Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
## 4 Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
## 5 Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
## 6 Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
# veya son 6 satırını da görebiliriz.
print(tail(cars_data))
## model mpg cyl disp hp drat wt qsec vs am gear carb
## 27 Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.7 0 1 5 2
## 28 Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.9 1 1 5 2
## 29 Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.5 0 1 5 4
## 30 Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.5 0 1 5 6
## 31 Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.6 0 1 5 8
## 32 Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.6 1 1 4 2
# Eğer gerekli ise hem head() komutu için hem de tail komutu için
# geçerli olan metod () içine görülmek istenen
# veri setinin atandığı isim ve satır sayısı yazılabilir.
print(head(cars_data,10))
## model mpg cyl disp hp drat wt qsec vs am gear carb
## 1 Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
## 2 Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
## 3 Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
## 4 Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
## 5 Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
## 6 Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
## 7 Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
## 8 Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
## 9 Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
## 10 Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
# veya
print(tail(cars_data,10))
## model mpg cyl disp hp drat wt qsec vs am gear carb
## 23 AMC Javelin 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2
## 24 Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
## 25 Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2
## 26 Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1
## 27 Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
## 28 Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
## 29 Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
## 30 Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
## 31 Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
## 32 Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2
Vektörleri dilimlemenin temel mantığını anladıktan sonra, şimdi R’daki en önemli veri yapısı olan veri çerçevelerini (data frames) nasıl dilimleyeceğimizi öğrenmeye hazırız.
Bir veri çerçevesi, iki boyutlu bir tablo gibidir: hem satırları hem
de sütunları vardır. Bu nedenle, [ ]
(köşeli parantez)
operatörünü kullanırken bu iki boyutu da dikkate almamız gerekir.
Temel kuralımız şudur:
veri_df[satir_indeksi, sutun_indeksi]
İki boyut arasına koyduğumuz o küçük virgül
(,
), R’a “Soldaki kurallar satırlar için, sağdaki
kurallar sütunlar için geçerli” demenin yoludur.
Bir tablodaki tek bir hücreye ulaşmak için hem satır hem de sütun numarasını belirtiriz.
# 3. satırın 5. sütunundaki değeri görelim (3. arabanın 'hp' yani beygir gücü)
cars_data[3,5]
## [1] 93
En Önemli Kural: Eğer sütun indeksi kısmını boş bırakırsak, R bunu “tüm sütunları istiyorum” olarak anlar.
# Sadece 5. satırı ve tüm sütunlarını alalım
cars_data[5, ]
# Sadece 3'ten 9'a kadar olan satırları alalım
cars_data[3:9, ]
# Sadece 2., 5. ve 10. satırları alalım
cars_data[c(2, 5, 10), ]
En Önemli Kural: Eğer satır indeksi kısmını boş bırakırsak, R bunu “tüm satırları istiyorum” olarak anlar.
# Sadece "model" sütununu alalım.
# Sütunları, sıra numarası yerine isimleriyle çağırmak daha güvenilirdir.
cars_data[, "model"]
## [1] "Mazda RX4" "Mazda RX4 Wag" "Datsun 710"
## [4] "Hornet 4 Drive" "Hornet Sportabout" "Valiant"
## [7] "Duster 360" "Merc 240D" "Merc 230"
## [10] "Merc 280" "Merc 280C" "Merc 450SE"
## [13] "Merc 450SL" "Merc 450SLC" "Cadillac Fleetwood"
## [16] "Lincoln Continental" "Chrysler Imperial" "Fiat 128"
## [19] "Honda Civic" "Toyota Corolla" "Toyota Corona"
## [22] "Dodge Challenger" "AMC Javelin" "Camaro Z28"
## [25] "Pontiac Firebird" "Fiat X1-9" "Porsche 914-2"
## [28] "Lotus Europa" "Ford Pantera L" "Ferrari Dino"
## [31] "Maserati Bora" "Volvo 142E"
# Sadece "model", "mpg" ve "hp" sütunlarını alalım
cars_data[, c("model", "mpg", "hp")]
# Sadece 3'ten 9'a kadar olan sütunları alalım (disp'ten vs'ye kadar)
cars_data[, 3:9]
Hem satır hem de sütun için kurallar belirleyerek, verinin tam istediğimiz “dikdörtgen” dilimini alabiliriz.
# İlk 5 arabanın sadece "model" ve "mpg" bilgilerini alalım
cars_data[1:5, c("model", "mpg")]
Bu temel dilimleme teknikleri, Base R’da veri manipülasyonunun mutlak
temelidir. Bir sonraki adımda, bu dilimleme işlemini “koşullara”
bağlayarak nasıl filtreleme yapabileceğimizi, yani dplyr
’ın
filter()
fiilinin arkasındaki asıl sihri keşfedeceğiz.
Şimdiye kadar, bir veri çerçevesinden dilimler alırken hep sıra
numaralarını kullandık (cars_data[1:5, ]
). Ancak Base R’ın
asıl gücü, bu dilimleme işlemini koşullara bağlamamıza
izin verdiğinde ortaya çıkar. Buna mantıksal indeksleme (logical
indexing) denir ve bu, dplyr
’ın
filter()
fiilinin arkasındaki temel mekanizmadır.
Mantık çok basittir: R’a bir koşul veririz, o da bize her satır için
“Bu koşul doğru mu, yanlış mı?” diye cevap veren bir
TRUE
/FALSE
listesi (vektörü) döndürür. Daha
sonra bu listeyi, satırları seçmek için kullanırız.
Soru: cars_data
içindeki 6 silindirli
(cyl == 6
) arabaları nasıl buluruz?
Adım 1: Koşulu Yazmak Önce R’a bu soruyu sorarız. R,
her bir arabanın silindir sayısını kontrol eder ve bize bir
DOĞRU
/YANLIŞ
listesi verir.
# Koşulumuz: Silindir sayısı 6'ya eşit mi? (== operatörü "eşit mi?" demektir)
kosul <- cars_data$cyl == 6
# R'ın bize verdiği cevabın ilk birkaç satırına bakalım
head(kosul)
## [1] TRUE TRUE FALSE TRUE FALSE TRUE
Adım 2: TRUE
/FALSE
Listesini
Kullanarak Filtrelemek Şimdi, R’ın bize verdiği bu
TRUE
/FALSE
“cevap anahtarını” [ ]
operatörünün satır kısmına koyarız. R, bu listede TRUE
olarak işaretlenmiş tüm satırları bizim için seçecektir.
# Sadece 'kosul'un TRUE olduğu satırları ve tüm sütunları getir
alt_kume <- cars_data[kosul, ]
# Sonuca bakalım
alt_kume
Elbette, bu iki adımı genellikle tek bir satırda, birleştirerek yazarız:
# Tek satırda filtreleme
cars_data[cars_data$cyl == 6, ]
# Birden fazla koşul: 6'dan fazla silindirli (`>=`) VE (&) 150'den fazla beygir gücü olanlar
cars_data[cars_data$cyl >= 6 & cars_data$hp > 150, ]
subset()
Fonksiyonu: Daha Okunaklı Bir AlternatifGördüğünüz gibi, [ ]
operatörü çok güçlüdür ama koşullar
arttıkça kod biraz okunaksız hale gelebilir. Base R, bu iş için
subset()
adında daha “konuşkan” bir alternatif sunar.
# 6 silindirli ve 120'den fazla beygir gücü olan arabaların
# sadece model, mpg ve hp sütunlarını seçelim.
subset(cars_data,
subset = (cyl == 6 & hp > 120),
select = c(model, mpg, hp))
Artık sadece veriyi dilimlemeyi değil, aynı zamanda belirli kurallara göre filtreleyerek ondan anlamlı alt kümeler oluşturmayı da öğrendik. Bir sonraki adımda ise, bu filtrelenmiş veya ham veriye nasıl yeni bilgiler, yani yeni sütunlar ekleyeceğimizi keşfedeceğiz!
Veriyi sadece süzmek veya seçmek yeterli değildir. Çoğu zaman, mevcut
sütunları kullanarak yeni bilgiler hesaplamamız gerekir. Örneğin, “Doğum
Tarihi” sütunundan “Yaş” sütununu türetmek gibi. Bu, dplyr
dünyasında mutate()
fiilinin görevidir. Base R’da ise bu
işi yapmanın birkaç şık ve güçlü yolu vardır.
$
(Dolar İşareti) OperatörüBir veri çerçevesine yeni bir sütun eklemenin veya mevcut bir sütunu
güncellemenin en yaygın ve en sezgisel yolu, $
operatörünü
kullanmaktır.
# 'wt' sütununu (1000 lbs cinsinden) kullanarak ağırlığı kilogram (kg) cinsinden hesaplayalım.
# 'wt_kg' adında YENİ bir sütun oluşturuyoruz.
cars_data$wt_kg <- cars_data$wt * 1000 * 0.453592
# 'hp' (beygir gücü) sütununu kullanarak 'hp_per_cyl' (silindir başına beygir gücü)
# adında YENİ bir sütun daha oluşturalım.
cars_data$hp_per_cyl <- cars_data$hp / cars_data$cyl
# Şimdi de MEVCUT 'mpg' sütununu güncelleyelim. (Mili kilometreye çevirelim, 1 mil ~ 1.6 km)
cars_data$mpg <- cars_data$mpg * 1.60934
# Yaptığımız değişikliklere, sadece ilgili sütunları seçerek göz atalım.
head(cars_data[, c("model", "mpg", "wt_kg", "hp_per_cyl")])
ifelse()
ile Koşullu Olarak Yeni Sütun EklemeBazen yeni bir sütunun değeri, bir koşula bağlı olarak değişebilir.
dplyr
’da bu iş için case_when()
’i görmüştük.
Base R’daki en yakın ve en pratik karşılığı ifelse()
fonksiyonudur.
ifelse()
’in mantığı şudur:
ifelse(koşul, koşul doğruysa_bunu_yap, koşul yanlışsa_bunu_yap)
# 32.18 km'den (yaklaşık 20 mil) fazla gidenlere "Verimli", diğerlerine "Verimsiz" diyelim.
cars_data$Verimlilik <- ifelse(cars_data$mpg > 32.18, "Verimli", "Verimsiz")
# Sonuca bakalım
head(cars_data[, c("model", "mpg", "Verimlilik")])
transform()
Fonksiyonu: Birden Fazla Sütunu Tek
Seferde EklemeEğer birden fazla yeni sütun eklemek veya mevcut sütunları aynı anda
güncellemek istiyorsak, her biri için ayrı ayrı $
ile
yazmak yerine transform()
fonksiyonunu kullanabiliriz. Bu,
dplyr
’ın mutate
fonksiyonunun birden fazla
işlem yapabilmesine çok benzer.
# 'cars_data' veri setini al, ve aşağıdaki işlemleri yaparak yeni bir versiyonunu oluştur:
# 1. 'wt_kg' adında yeni bir sütun ekle.
# 2. 'hp_per_cyl' adında yeni bir sütun ekle.
cars_data_donusturulmus <- transform(cars_data,
wt_kg_yeni = wt * 1000 * 0.453592,
hp_per_cyl_yeni = hp / cyl
)
head(cars_data_donusturulmus)
Artık veriyi sadece seçip süzmeyi değil, aynı zamanda onu yeni ve
daha zengin bilgilerle nasıl genişleteceğimizi de öğrendik. Bir sonraki
adımda, bu zenginleşmiş veriyi nasıl anlamlı bir şekilde
sıralayacağımızı, yani arrange()
fiilinin arkasındaki Base
R sırrını çözeceğiz.
order()
Fonksiyonunun SırrıVeri analizinde en sık yaptığımız işlerden biri, bir tabloyu belirli
bir sütuna göre küçükten büyüğe veya büyükten küçüğe doğru sıralamaktır.
dplyr
dünyasında bu işi arrange()
fiiliyle ne
kadar kolay yaptığımızı görmüştük. Base R’da ise bu işin arkasındaki
mekanizma, order()
adında çok zeki ama biraz farklı çalışan
bir fonksiyondur.
order()
’ın Mantığı: Sıralama Değil, Sıralama Tarifi
Vermek!arrange()
’ten farklı olarak, order()
fonksiyonu veriyi doğrudan sıralamaz. Onun yerine, size
o veriyi doğru bir şekilde sıralamak için gereken
“tarifi”, yani satırların hangi sırayla
dizilmesi gerektiğini gösteren bir indeks (sıra numaraları)
listesi verir.
Bu tarifi aldıktan sonra, bu tarifi [ ]
(köşeli
parantezler) operatörüne vererek veri setimizi yeniden düzenleriz.
Adım Adım Mantığı Anlayalım:
Soru: cars_data
içindeki arabaları, en
yüksek beygir gücünden (hp
) en düşüğe doğru nasıl
sıralarız?
Adım 1: “Tarifi” Almak Önce order()
fonksiyonuna hangi sütuna göre sıralama yapmak istediğimizi söyleriz.
decreasing = TRUE
argümanı, sıralamayı büyükten küçüğe
(azalan) yapmasını sağlar.
# Bize, arabaları en yüksek beygir gücüne göre sıralayacak
# doğru satır sıralamasını veren "tarifi" oluştur.
hp_siralama_tarifi <- order(cars_data$hp, decreasing = TRUE)
# Bu tarifin içine bakalım. Bu bir sayı vektörüdür.
# Örneğin ilk sayı '31' ise, bu "en başa 31. satırı koymalısın" demektir.
hp_siralama_tarifi
## [1] 31 29 7 24 17 16 15 12 13 14 5 25 30 22 23 10 11 28 1 2 4 32 6 21 9
## [26] 3 27 18 26 20 8 19
Adım 2: “Tarifi” Uygulamak Şimdi,
order()
’dan aldığımız bu hp_siralama_tarifi
vektörünü, [ ]
operatörlerinin satır kısmına koyarak veri
çerçevemizi bu tarife göre yeniden dizeriz.
# cars_data'yı al, ama satırları 'hp_siralama_tarifi'nin söylediği sırada diz.
sirali_arabalar <- cars_data[hp_siralama_tarifi, ]
# Sonucun ilk birkaç satırına bakarak en yüksek beygir gücüne sahip
# arabaların en üste geldiğini teyit edelim.
head(sirali_arabalar[, c("model", "hp")])
Tıpkı arrange(cyl, desc(hp))
gibi, order()
ile de birden fazla sütuna göre sıralama yapabiliriz.
order()
fonksiyonu, verdiğiniz sütunları soldan sağa doğru
birincil, ikincil, üçüncül sıralama kriteri olarak kullanır.
# Arabaları önce silindir sayısına (küçükten büyüğe),
# sonra da beygir gücüne (büyükten küçüğe) göre sıralayalım.
# İkinci sütunun başına '-' koymak, sadece o sütunu tersten sıralar.
cift_siralama_tarifi <- order(cars_data$cyl, -cars_data$hp)
# Tarifi uygulayalım
cift_sirali_arabalar <- cars_data[cift_siralama_tarifi, ]
# Sonucun ilk birkaç satırına bakalım.
head(cift_sirali_arabalar[, c("model", "cyl", "hp")])
order()
fonksiyonunun bu iki adımlı mantığını anlamak,
Base R ile veri manipülasyonunda ustalaşmanın en önemli adımlarından
biridir. Artık veriyi istediğimiz düzene sokabildiğimize göre, bir
sonraki ve son adımda, bu veriyi gruplara ayırıp her bir grup için nasıl
özet istatistikler çıkaracağımızı, yani dplyr
’ın en güçlü
ikilisi olan group_by()
ve summarise()
’ın Base
R’daki karşılıklarını keşfedeceğiz.
group_by
+
summarise
Karşılığı)Veri analizinin en temel görevlerinden biri, veriyi belirli kategorilere ayırıp her bir kategori için özet istatistikler hesaplamaktır. “Her bir ürün kategorisinin ortalama satışı nedir?” veya “Farklı vites tiplerindeki arabaların ortalama beygir gücü nedir?” gibi soruları bu şekilde cevaplarız.
dplyr
’da bu işi group_by()
ve
summarise()
ikilisiyle sihirli bir kolaylıkta yapıyorduk.
Base R’da ise bu görevi yerine getiren, biraz farklı çalışan ama aynı
derecede güçlü birkaç fonksiyon bulunur.
tapply()
: Bir Vektörü Gruplara Ayırıp Özetlemektapply()
fonksiyonu, bir veri vektörünü
(X
), bir faktör veya kategorik vektöre
(INDEX
) göre gruplara ayırır ve her bir gruba belirli bir
fonksiyonu (FUN
) uygular.
Sözdizimi şöyledir: tapply(X, INDEX, FUN)
# Soru: Her bir silindir (cyl) grubu için ortalama beygir gücü (hp) nedir?
# `tapply` ile çözüm:
# hp vektörünü al, cyl vektörüne göre grupla, her gruba mean fonksiyonunu uygula.
tapply(cars_data$hp, cars_data$cyl, mean)
## 4 6 8
## 82.63636 122.28571 209.21429
# Soru: Her vites tipi (am) için en yüksek yakıt verimliliği (mpg) nedir?
tapply(cars_data$mpg, cars_data$am, max)
## 0 1
## 39.26790 54.55663
tapply
hızlı ve etkilidir, ancak çıktısı genellikle bir
vektör veya dizi olur ve bazen data.frame
’e çevirmek için
ek adımlar gerektirebilir.
aggregate()
: Veri Çerçevesi Halinde Gruplu
Özetleraggregate()
fonksiyonu, tapply
’a çok benzer
bir iş yapar ama en büyük avantajı, sonucunu her zaman düzenli bir
veri çerçevesi (data.frame
) olarak
vermesidir. Bu, dplyr
’ın summarise
çıktısına
çok daha yakındır.
Sözdizimi şöyledir:
aggregate(FORMÜL, data = VERI_SETI, FUN = FONKSIYON)
# Soru: Her bir silindir (cyl) grubu için ortalama beygir gücü (hp) ve
# ortalama yakıt tüketimini (mpg) bulalım.
# Formül: cbind(Sütun1, Sütun2) ~ GruplamaSütunu
aggregate(cbind(mpg, hp) ~ cyl,
data = cars_data,
FUN = mean)
# Birden fazla gruplama değişkeni de kullanabiliriz:
# Vites tipi (am) ve motor tipine (vs) göre gruplayalım
aggregate(hp ~ am + vs,
data = cars_data,
FUN = mean)
Dostlar, bu bölümle birlikte Base R’ın temel veri manipülasyonu
aletlerini keşfetme yolculuğumuzu tamamladık. dplyr
’ın
modern ve akıcı dünyası ile Base R’ın temel, hızlı ve bağımsız dünyası
arasında artık rahatça geçiş yapabilecek bilgiye sahipsiniz.
Aşağıdaki tablo, bu iki farklı yaklaşımın özet bir karşılaştırmasını sunuyor. Hangi görevi hangi aletle yapabileceğinizi bir bakışta görebilirsiniz.
Görev | dplyr Yaklaşımı | Base R Yaklaşımı |
---|---|---|
Filtreleme | filter(cyl == 6) |
[cars_data$cyl == 6, ] veya
subset() |
Sütun Seçme | select(mpg, hp) |
[, c("mpg", "hp")] |
Yeni Sütun | mutate(yeni = hp/cyl) |
$yeni <- ... veya
transform() |
Sıralama | arrange(desc(mpg)) |
[order(cars_data$mpg, decreasing = TRUE), ] |
Gruplu Özet | group_by() %>% summarise() |
aggregate() veya tapply() |
Unutmayın, en iyi usta, tek bir alete bağlı kalan değil, elindeki iş için en doğru aleti seçebilendir. Artık sizin de alet çantanız her duruma hazır!
Dostlar, atölyemizin klasik el aletlerini tek tek tanıdık. Şimdi, bu aletleri kullanarak baştan sona küçük bir keşif projesi yapma zamanı. Bu projede, bir şirket yöneticisinin bizden isteyebileceği türden soruları, sadece Base R fonksiyonları kullanarak cevaplayacağız.
Senaryomuz: Bir şirketin İnsan Kaynakları
departmanı, çalışan verilerini içeren bir .csv
dosyasını
bize verdi ve bu verilerden anlamlı içgörüler çıkarmamızı istedi.
İlk olarak, üzerinde çalışacağımız örnek veri setini oluşturalım ve
calisan_verileri.csv
adıyla çalışma dizinimize kaydedelim.
Bu, write.csv()
fonksiyonunu da görmemiz için harika bir
fırsat.
# Tekrarlanabilir bir örnek veri seti için "tohum" belirliyoruz
set.seed(123)
# 30 kişilik bir çalışan veri çerçevesi oluşturalım
calisanlar_df <- data.frame(
CalisanID = 1001:1030,
Ad = sample(c("Ali", "Ayşe", "Mehmet", "Fatma", "Can", "Zeynep", "Murat", "Elif"), 30, replace = TRUE),
Soyad = sample(c("Yılmaz", "Kaya", "Demir", "Çelik", "Şahin", "Öztürk"), 30, replace = TRUE),
Cinsiyet = sample(c("Erkek", "Kadın"), 30, replace = TRUE),
DogumTarihi = sample(seq(as.Date('1970/01/01'), as.Date('2000/01/01'), by="day"), 30),
Memleket = sample(c
("İstanbul", "Ankara", "İzmir", "Bursa", "Adana"), 30,replace = TRUE),
EgitimSeviyesi = sample(ordered(c("Lise", "Lisans", "Yüksek Lisans"),
levels = c("Lise", "Lisans", "Yüksek Lisans")), 30, replace = TRUE),
Departman = sample(c("IT", "İK", "Pazarlama", "Satış"), 30, replace = TRUE),
Pozisyon = sample(c("Uzman", "Kıdemli Uzman", "Yönetici"), 30, replace = TRUE),
Maas = round(runif(30, min=15000, max=50000)),
IseBaslamaTarihi = sample(seq(as.Date('2015/01/01'), as.Date('2023/01/01'), by="day"), 30)
)
# Bu veri çerçevesini bir CSV dosyası olarak kaydedelim.
# row.names = FALSE, satır numaralarının dosyaya yazılmasını engeller.
write.csv(calisanlar_df, "calisan_verileri.csv", row.names = FALSE)
Artık bir veri analisti gibi davranabiliriz. İlk işimiz, bize verilen CSV dosyasını R’a yüklemek ve içeriğine hızlıca bir göz atmak.
# write.csv ile kaydettiğimiz dosyayı read.csv ile geri okuyoruz.
sirket_verileri <- read.csv("calisan_verileri.csv")
# Verinin ilk 6 satırına bakalım
cat("--- Veri Setinin İlk 6 Satırı ---\n")
## --- Veri Setinin İlk 6 Satırı ---
print(head(sirket_verileri))
## CalisanID Ad Soyad Cinsiyet DogumTarihi Memleket EgitimSeviyesi
## 1 1001 Murat Yılmaz Erkek 1972-01-25 İstanbul Yüksek Lisans
## 2 1002 Murat Öztürk Kadın 1987-12-10 İzmir Lise
## 3 1003 Mehmet Demir Erkek 1984-11-10 İzmir Lisans
## 4 1004 Zeynep Çelik Erkek 1995-03-08 İstanbul Lise
## 5 1005 Mehmet Öztürk Erkek 1999-07-04 İzmir Lisans
## 6 1006 Ayşe Yılmaz Erkek 1989-07-06 Adana Yüksek Lisans
## Departman Pozisyon Maas IseBaslamaTarihi
## 1 IT Yönetici 44991 2017-01-26
## 2 IT Kıdemli Uzman 44882 2020-05-18
## 3 Pazarlama Uzman 25356 2017-09-14
## 4 Pazarlama Uzman 20147 2021-10-30
## 5 İK Uzman 39640 2022-11-08
## 6 IT Uzman 18633 2022-11-18
# Verinin yapısını (sütun tipleri vb.) inceleyelim
cat("\n--- Veri Setinin Yapısı (str) ---\n")
##
## --- Veri Setinin Yapısı (str) ---
str(sirket_verileri)
## 'data.frame': 30 obs. of 11 variables:
## $ CalisanID : int 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 ...
## $ Ad : chr "Murat" "Murat" "Mehmet" "Zeynep" ...
## $ Soyad : chr "Yılmaz" "Öztürk" "Demir" "Çelik" ...
## $ Cinsiyet : chr "Erkek" "Kadın" "Erkek" "Erkek" ...
## $ DogumTarihi : chr "1972-01-25" "1987-12-10" "1984-11-10" "1995-03-08" ...
## $ Memleket : chr "İstanbul" "İzmir" "İzmir" "İstanbul" ...
## $ EgitimSeviyesi : chr "Yüksek Lisans" "Lise" "Lisans" "Lise" ...
## $ Departman : chr "IT" "IT" "Pazarlama" "Pazarlama" ...
## $ Pozisyon : chr "Yönetici" "Kıdemli Uzman" "Uzman" "Uzman" ...
## $ Maas : int 44991 44882 25356 20147 39640 18633 16180 49979 16221 26844 ...
## $ IseBaslamaTarihi: chr "2017-01-26" "2020-05-18" "2017-09-14" "2021-10-30" ...
# Sayısal sütunlar için temel istatistiksel özet
cat("\n--- Sayısal Verilerin Özeti (summary) ---\n")
##
## --- Sayısal Verilerin Özeti (summary) ---
summary(sirket_verileri)
## CalisanID Ad Soyad Cinsiyet
## Min. :1001 Length:30 Length:30 Length:30
## 1st Qu.:1008 Class :character Class :character Class :character
## Median :1016 Mode :character Mode :character Mode :character
## Mean :1016
## 3rd Qu.:1023
## Max. :1030
## DogumTarihi Memleket EgitimSeviyesi Departman
## Length:30 Length:30 Length:30 Length:30
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
## Pozisyon Maas IseBaslamaTarihi
## Length:30 Min. :16180 Length:30
## Class :character 1st Qu.:25104 Class :character
## Mode :character Median :32132 Mode :character
## Mean :32813
## 3rd Qu.:40527
## Max. :49979
Ham veri harika, ama genellikle ondan yeni bilgiler türetmemiz gerekir.
# Tarih sütunlarının 'Date' formatında olduğundan emin olalım
sirket_verileri$DogumTarihi <- as.Date(sirket_verileri$DogumTarihi)
sirket_verileri$IseBaslamaTarihi <- as.Date(sirket_verileri$IseBaslamaTarihi)
# a. 'DogumTarihi' sütunundan 'Yas' adında yeni bir sütun oluşturalım
# Sys.Date() bugünün tarihini verir. Farkı güne çevirip 365.25'e bölerek yaşı buluruz.
sirket_verileri$Yas <- as.integer((Sys.Date() - sirket_verileri$DogumTarihi) / 365.25)
# b. 'IseBaslamaTarihi'nden 'Kidem_Yil' adında yeni bir sütun oluşturalım
sirket_verileri$Kidem_Yil <- as.integer((Sys.Date() - sirket_verileri$IseBaslamaTarihi) / 365.25)
# c. 'Maas' sütununa göre 'MaasKategori' adında yeni bir sütun oluşturalım
# cut() fonksiyonu, sayısal bir veriyi kategorilere ayırmak için harikadır.
sirket_verileri$MaasKategori <- cut(sirket_verileri$Maas,
breaks = c(0, 20000, 40000, Inf),
labels = c("Düşük", "Orta", "Yüksek"))
# Eklediğimiz yeni sütunlarla veri setinin ilk satırlarına tekrar bakalım
head(sirket_verileri[, c("Ad", "Yas", "Kidem_Yil", "MaasKategori")])
Şimdi İK yöneticisinden gelen bazı spesifik soruları cevaplayalım.
# Soru 1: "IT departmanında çalışan ve 40 yaşından büyük olanların listesi kimlerdir?"
cat("--- IT Departmanındaki 40 Yaş Üstü Çalışanlar ---\n")
## --- IT Departmanındaki 40 Yaş Üstü Çalışanlar ---
it_ve_yasli <- sirket_verileri[sirket_verileri$Departman == "IT" & sirket_verileri$Yas > 40, ]
print(it_ve_yasli)
## CalisanID Ad Soyad Cinsiyet DogumTarihi Memleket EgitimSeviyesi
## 1 1001 Murat Yılmaz Erkek 1972-01-25 İstanbul Yüksek Lisans
## 16 1016 Mehmet Çelik Kadın 1982-07-12 Adana Lisans
## 17 1017 Elif Şahin Kadın 1980-05-10 İzmir Lisans
## 26 1026 Mehmet Şahin Kadın 1982-11-19 İstanbul Lise
## 30 1030 Ayşe Demir Erkek 1971-11-17 Bursa Lise
## Departman Pozisyon Maas IseBaslamaTarihi Yas Kidem_Yil MaasKategori
## 1 IT Yönetici 44991 2017-01-26 53 8 Yüksek
## 16 IT Uzman 25999 2020-06-09 43 5 Orta
## 17 IT Kıdemli Uzman 32240 2018-02-27 45 7 Orta
## 26 IT Uzman 32024 2021-10-05 42 3 Orta
## 30 IT Yönetici 23024 2019-02-15 53 6 Orta
# Soru 2: "Şirketteki en yüksek maaşlı 5 çalışanın kim olduğunu ve maaşlarını bulun."
cat("\n--- En Yüksek Maaşlı 5 Çalışan ---\n")
##
## --- En Yüksek Maaşlı 5 Çalışan ---
# Önce maaşa göre tersten sıralama için "tarifi" alıyoruz
maas_siralama_tarifi <- order(sirket_verileri$Maas, decreasing = TRUE)
# Bu tarife göre veri setini sıralıyoruz
sirali_veri <- sirket_verileri[maas_siralama_tarifi, ]
# Sadece ilk 5 satırı ve ilgili sütunları gösteriyoruz
print(head(sirali_veri[, c("Ad", "Soyad", "Departman", "Maas")], 5))
## Ad Soyad Departman Maas
## 8 Zeynep Şahin İK 49979
## 28 Ayşe Yılmaz İK 49417
## 21 Ali Yılmaz IT 49225
## 11 Fatma Şahin İK 47027
## 1 Murat Yılmaz IT 44991
Yöneticimiz, departmanlar ve eğitim seviyeleri hakkında genel bir tablo görmek istiyor.
# Soru 1: "Her bir departmanın ortalama maaşı ve ortalama yaşı nedir?"
cat("--- Departman Bazında Ortalama Maaş ve Yaş ---\n")
## --- Departman Bazında Ortalama Maaş ve Yaş ---
departman_ozeti <- aggregate(cbind(Maas, Yas) ~ Departman,
data = sirket_verileri,
FUN = mean)
print(departman_ozeti)
## Departman Maas Yas
## 1 İK 39733.71 34.57143
## 2 IT 33981.55 39.27273
## 3 Pazarlama 30233.78 35.55556
## 4 Satış 20119.67 40.33333
# Soru 2: "Eğitim seviyesine göre çalışan dağılımı nasıldır?"
cat("\n--- Eğitim Seviyesine Göre Çalışan Dağılımı ---\n")
##
## --- Eğitim Seviyesine Göre Çalışan Dağılımı ---
# table() fonksiyonu, bir kategorik değişkenin frekans tablosunu oluşturur.
print(table(sirket_verileri$EgitimSeviyesi))
##
## Lisans Lise Yüksek Lisans
## 10 14 6
# Ustalık Sorusu: "Her bir departmandaki en kıdemli çalışanın kim olduğunu ve kıdemini bulun."
# Bu karmaşık soru için by() fonksiyonu harikadır. Veriyi departmanlara böler ve her bir parçaya
# istediğimiz işlemi uygular.
cat("\n--- Departmanların En Kıdemlileri ---\n")
##
## --- Departmanların En Kıdemlileri ---
by(sirket_verileri, sirket_verileri$Departman, function(df) {
# Her bir departman dilimi (df) için, kıdemi en yüksek olanı bul
en_kidemli_satir <- df[which.max(df$Kidem_Yil), ]
# Sadece ilgili bilgileri geri döndür
return(en_kidemli_satir[, c("Ad", "Soyad", "Kidem_Yil")])
})
## sirket_verileri$Departman: İK
## Ad Soyad Kidem_Yil
## 13 Zeynep Yılmaz 9
## ------------------------------------------------------------
## sirket_verileri$Departman: IT
## Ad Soyad Kidem_Yil
## 1 Murat Yılmaz 8
## ------------------------------------------------------------
## sirket_verileri$Departman: Pazarlama
## Ad Soyad Kidem_Yil
## 10 Can Kaya 9
## ------------------------------------------------------------
## sirket_verileri$Departman: Satış
## Ad Soyad Kidem_Yil
## 7 Ayşe Demir 8