Ana içeriğe geç

R Kodunuzu Geliştirmek İçin Beş İpucu

R kodunuzu etkili biçimde geliştirmek için kullanabileceğiniz beş faydalı ipucu: diziler oluşturmak için seq() kullanmaktan which()’i bırakmaya ve daha fazlasına!
· 8 dk. oku

Yapay Zeka ile Keşfedin

@drsimonj burada, R kodunu geliştirmek için diğer R kullanıcılarıyla sık sık paylaştığım beş basit püf noktasını anlatıyorum!

1. 1’den dizi oluşturmak daha eğlenceli

Bir sonraki sefere 1’den başlayan bir dizi oluşturmak için 1:n gibi iki nokta üst üste operatörünü kullanacağınız zaman, seq() deneyin.

# Sequence a vector
x <- runif(10)
seq(x)
#>  [1]  1  2  3  4  5  6  7  8  9 10

# Sequence an integer
seq(nrow(mtcars))
#>  [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
#> [24] 24 25 26 27 28 29 30 31 32

İki nokta üst üste operatörü, fark etmeden her türlü soruna yol açabilecek beklenmedik sonuçlar üretebilir! Boş bir vektörün uzunluğunu diziye çevirmek istediğinizde ne olduğuna bakın:

# Empty vector
x <- c()

1:length(x)
#> [1] 1 0

seq(x)
#> integer(0)

Ayrıca bu yaklaşımın sizi length() gibi işlevleri kullanmaktan da kurtardığını fark edeceksiniz. Belirli bir uzunluktaki bir nesneye uygulandığında, seq() otomatik olarak 1’den nesnenin uzunluğuna kadar bir dizi oluşturur.

2. vector() ile c()’ye alternatif

Bir sonraki sefer boş bir vektörü c() ile oluşturduğunuzda, bunun yerine vector("type", length) kullanmayı deneyin.

# A numeric vector with 5 elements
vector("numeric", 5)
#> [1] 0 0 0 0 0

# A character vector with 3 elements
vector("character", 3)
#> [1] "" "" ""

Bunu yapmak bellek kullanımını iyileştirir ve hızı artırır! Çoğu zaman bir vektöre hangi türde değerlerin gireceğini ve vektörün ne kadar uzun olacağını baştan bilirsiniz. c() kullanmak, R’nin bu iki şeyi de yavaşça hesaplaması gerektiği anlamına gelir. Bu yüzden vector() ile ona hız kazandırın!

Bunun faydasına iyi bir örnek for döngüleridir. İnsanlar genellikle boş bir vektör tanımlayıp onu aşağıdaki gibi c() ile büyüterek döngüler yazar:

x <- c()
for (i in seq(5)) {
  x <- c(x, i)
}
#> x at step 1 : 1
#> x at step 2 : 1, 2
#> x at step 3 : 1, 2, 3
#> x at step 4 : 1, 2, 3, 4
#> x at step 5 : 1, 2, 3, 4, 5

Bunun yerine, türü ve uzunluğu vector() ile önceden tanımlayın ve konumlara indeksle referans verin, şöyle:

n <- 5
x <- vector("integer", n)
for (i in seq(n)) {
  x[i] <- i
}
#> x at step 1 : 1, 0, 0, 0, 0
#> x at step 2 : 1, 2, 0, 0, 0
#> x at step 3 : 1, 2, 3, 0, 0
#> x at step 4 : 1, 2, 3, 4, 0
#> x at step 5 : 1, 2, 3, 4, 5

İşte hızlı bir hız karşılaştırması:

n <- 1e5

x_empty <- c()
system.time(for(i in seq(n)) x_empty <- c(x_empty, i))
#>    user  system elapsed 
#>  15.238   2.327  17.650

x_zeros <- vector("integer", n)
system.time(for(i in seq(n)) x_zeros[i] <- i)
#>    user  system elapsed 
#>   0.007   0.000   0.007

Yeterince ikna edici olmalı!

3. which() işlevini bırakın

Bir dahaki sefere which() kullanacağınız zaman, kullanmamayı deneyin! İnsanlar genellikle bir mantıksal koşuldan indeksler elde etmek ve sonra bu indekslerdeki değerleri seçmek için which()’i kullanır. Buna gerek yok.

5’ten büyük vektör elemanlarını alma:

x <- 3:7

# Using which (not necessary)
x[which(x > 5)]
#> [1] 6 7

# No which
x[x > 5]
#> [1] 6 7

Ya da 5’ten büyük değerlerin sayısını bulma:

# Using which
length(which(x > 5))
#> [1] 2

# Without which
sum(x > 5)
#> [1] 2

Neden which()’i bırakmalısınız? Çoğu zaman gereksizdir ve ihtiyacınız olan tek şey mantıksal vektörlerdir.

Örneğin, R bir mantıksal vektörde TRUE olarak işaretlenen öğeleri seçmenize izin verir:

condition <- x > 5
condition
#> [1] FALSE FALSE FALSE  TRUE  TRUE
x[condition]
#> [1] 6 7

Ayrıca, sum() veya mean() ile birleştirildiğinde, mantıksal vektörler bir koşulu sağlayan değerlerin sayısını veya oranını elde etmek için kullanılabilir:

sum(condition)
#> [1] 2
mean(condition)
#> [1] 0.4

which(), TRUE değerlerinin indekslerini verir:

which(condition)
#> [1] 4 5

Ve sonuçlar yanlış olmasa da, buna gerek yok. Örneğin, insanların which() ve length()’i birleştirerek herhangi bir veya tüm değerlerin TRUE olup olmadığını test ettiklerini sık sık görüyorum. Bunun yerine yalnızca any() veya all() gerekir:

x <- c(1, 2, 12)

# Using `which()` and `length()` to test if any values are greater than 10
if (length(which(x > 10)) > 0)
  print("At least one value is greater than 10")
#> [1] "At least one value is greater than 10"

# Wrapping a boolean vector with `any()`
if (any(x > 10))
  print("At least one value is greater than 10")
#> [1] "At least one value is greater than 10"

# Using `which()` and `length()` to test if all values are positive
if (length(which(x > 0)) == length(x))
  print("All values are positive")
#> [1] "All values are positive"

# Wrapping a boolean vector with `all()`
if (all(x > 0))
  print("All values are positive")
#> [1] "All values are positive"

Ve evet, size biraz zaman da kazandırır...

x <- runif(1e8)

system.time(x[which(x > .5)])
#>    user  system elapsed 
#>   1.156   0.522   1.686

system.time(x[x > .5])
#>    user  system elapsed 
#>   1.071   0.442   1.662

4. O faktörü factor ile toparlayın!

Hiç bir faktörden bazı değerleri çıkarıp artık var olmayan eski seviyelerin (levels) kaldığını gördünüz mü? Bununla başa çıkmak için her tür yaratıcı yöntem görüyorum. En basit çözüm çoğu zaman sadece factor() ile tekrar sarmalamaktır.

Bu örnek dört seviyeli ("a", "b", "c" ve "d") bir faktör oluşturur:

# A factor with four levels
x <- factor(c("a", "b", "c", "d"))
x
#> [1] a b c d
#> Levels: a b c d

plot(x)

R ipuçları

Bir seviyeye ("d") ait tüm gözlemleri düşürürseniz, seviye faktörde hâlâ kayıtlı kalır:

# Drop all values for one level
x <- x[x != "d"]

# But we still have this level!
x
#> [1] a b c
#> Levels: a b c d

plot(x)

örnek

Bunu kaldırmanın çok basit bir yolu, tekrar factor() kullanmaktır:

x <- factor(x)
x
#> [1] a b c
#> Levels: a b c

plot(x)

örnek

Bu, birçok kişiyi çileden çıkaran bir soruna genellikle iyi bir çözümdür. Kendinize bir baş ağrısından tasarruf edin ve o faktörü factor’layın!

5. Önce $’ı alın, sonra güç gelir

Bir koşulu sağlayan satırlardaki bir data.frame sütunundan değerleri çıkarmak istediğinizde, satırlardan önce sütunu $ ile belirtin ve ardından satırları [ ile seçin.

Diyelim ki mtcars veri setini kullanarak 4 silindirli (cyl) araçların beygir gücünü (hp) istiyorsunuz. Aşağıdakilerden herhangi birini yazabilirsiniz:

# rows first, column second - not ideal
mtcars[mtcars$cyl == 4, ]$hp
#>  [1]  93  62  95  66  52  65  97  66  91 113 109

# column first, rows second - much better
mtcars$hp[mtcars$cyl == 4]
#>  [1]  93  62  95  66  52  65  97  66  91 113 109

Buradaki ipucu, ikinci yaklaşımı kullanmanızdır.

Peki neden?

İlk neden: Şu can sıkıcı virgülden kurtulun! Satırları sütundan önce belirttiğinizde, virgülü hatırlamanız gerekir: mtcars[mtcars$cyl == 4,]$hp. Sütunu önce belirttiğinizde ise artık bir vektöre referans verirsiniz ve virgüle gerek kalmaz!

İkinci neden: hız! Bunu daha büyük bir veri çerçevesinde test edelim:

# Simulate a data frame...
n <- 1e7
d <- data.frame(
  a = seq(n),
  b = runif(n)
)

# rows first, column second - not ideal
system.time(d[d$b > .5, ]$a)
#>    user  system elapsed 
#>   0.497   0.126   0.629

# column first, rows second - much better
system.time(d$a[d$b > .5])
#>    user  system elapsed 
#>   0.089   0.017   0.107

Değer, değil mi?

Yine de, bir R data frame ustası olmak istiyorsanız, dplyr öğrenmenizi öneririm. dplyr web sitesinde iyi bir genel bakış edinebilir veya DataCamp’in dplyr ile R’de Veri Manipülasyonu gibi çevrim içi kurslarıyla işi iyice kavrayabilirsiniz.

Kapanış

Okuduğunuz için teşekkürler; umarım sizin için faydalı olmuştur.

En son blog yazılarından haberdar olmak için Twitter’da @drsimonj’i takip edin veya benimle iletişime geçmek için [email protected] adresine e-posta gönderin.

Bu blogu üreten kodu isterseniz, blogR GitHub deposuna göz atın.

Tidyverse’e Giriş: Eğitim yazımıza göz atın.

Konular

İlgili