Bir matrisin veya veri çerçevesinin her satırına bir işlev uygulayın


130

2'ye göre bir matrisim ve bağımsız değişkenlerinden biri olarak 2 vektörü alan bir fonksiyonum olduğunu varsayalım. Fonksiyonu matrisin her satırına uygulamak ve bir n vektörü elde etmek istiyorum. Bu R'de nasıl yapılır?

Örneğin, bir 2B standart Normal dağılımın yoğunluğunu üç noktada hesaplamak istiyorum:

bivariate.density(x = c(0, 0), mu = c(0, 0), sigma = c(1, 1), rho = 0){
    exp(-1/(2*(1-rho^2))*(x[1]^2/sigma[1]^2+x[2]^2/sigma[2]^2-2*rho*x[1]*x[2]/(sigma[1]*sigma[2]))) * 1/(2*pi*sigma[1]*sigma[2]*sqrt(1-rho^2))
}

out <- rbind(c(1, 2), c(3, 4), c(5, 6))

İşlevi her satıra nasıl uygulayabilirim out?

İşleve işaretlerin yanı sıra diğer argümanlar için de belirttiğiniz şekilde değerler nasıl iletilir?

Yanıtlar:


181

Sadece şu apply()işlevi kullanırsınız :

R> M <- matrix(1:6, nrow=3, byrow=TRUE)
R> M
     [,1] [,2]
[1,]    1    2
[2,]    3    4
[3,]    5    6
R> apply(M, 1, function(x) 2*x[1]+x[2])
[1]  4 10 16
R> 

Bu bir matris alır ve her satıra (aptalca) bir işlev uygular. İşleve dördüncü, beşinci, ... argümanlar olarak fazladan argümanlar iletirsiniz apply().


Teşekkürler! Ya matrisin satırları fonksiyonun ilk argümanı değilse? Matrisin her satırına atanan fonksiyonun hangi argümanını nasıl belirleyebilirim?
Tim

Yardımı okuyun apply()- satır bazında süpürür (ikinci argüman 1 olduğunda, sütuna göre) ve mevcut satır (veya sütun) her zaman ilk argümandır. İşler böyle tanımlanır.
Dirk Eddelbuettel

@Tim: Dahili bir Ar işlevini kullanın ve satır ilk arg değilse Dirk yaptı ve satır nerede kendi özel işlev yaparken, do ise ilk arg.
Joris Meys

3
Plyr paketi, bu uygulama türlerinin geniş bir yelpazesini sunar. Aynı zamanda paralel işleme dahil olmak üzere daha fazla işlevsellik sağlar.
Paul Hiemstra

6
@ cryptic0 bu cevap geç, ancak Google çalışanları için uygulamadaki ikinci argüman MARGINargümandır. Burada işlevin satırlara uygulanması anlamına gelir (içindeki ilk boyut dim(M)). 2 olsaydı, işlevi sütunlara uygulardı.
De Novo

17

Toplam veya ortalama gibi ortak işlevleri uygulamak istemeniz durumunda, rowSumsveya yaklaşımdan rowMeansdaha hızlı oldukları için kullanmalısınız apply(data, 1, sum). Aksi takdirde, devam edin apply(data, 1, fun). FUN bağımsız değişkeninden sonra ek bağımsız değişkenler iletebilirsiniz (Dirk'in zaten önerdiği gibi):

set.seed(1)
m <- matrix(round(runif(20, 1, 5)), ncol=4)
diag(m) <- NA
m
     [,1] [,2] [,3] [,4]
[1,]   NA    5    2    3
[2,]    2   NA    2    4
[3,]    3    4   NA    5
[4,]    5    4    3   NA
[5,]    2    1    4    4

O zaman bunun gibi bir şey yapabilirsiniz:

apply(m, 1, quantile, probs=c(.25,.5, .75), na.rm=TRUE)
    [,1] [,2] [,3] [,4] [,5]
25%  2.5    2  3.5  3.5 1.75
50%  3.0    2  4.0  4.0 3.00
75%  4.0    3  4.5  4.5 4.00

15

Burada, bir matrisin her satırına bir işlev uygulamanın kısa bir örneği verilmiştir. (Burada, uygulanan işlev her satırı 1'e normalleştirir.)

Not: gelen sonuç apply()gerekiyordu aktarılmış kullanarak t()giriş matris olarak aynı düzeni olsun A.

A <- matrix(c(
  0, 1, 1, 2,
  0, 0, 1, 3,
  0, 0, 1, 3
), nrow = 3, byrow = TRUE)

t(apply(A, 1, function(x) x / sum(x) ))

Sonuç:

     [,1] [,2] [,3] [,4]
[1,]    0 0.25 0.25 0.50
[2,]    0 0.00 0.25 0.75
[3,]    0 0.00 0.25 0.75

6

İlk adım, fonksiyon nesnesini yapmak ve ardından onu uygulamak olacaktır. Aynı sayıda satıra sahip bir matris nesnesi istiyorsanız, onu önceden tanımlayabilir ve gösterildiği gibi nesne [] formunu kullanabilirsiniz (aksi takdirde döndürülen değer bir vektöre basitleştirilecektir):

bvnormdens <- function(x=c(0,0),mu=c(0,0), sigma=c(1,1), rho=0){
     exp(-1/(2*(1-rho^2))*(x[1]^2/sigma[1]^2+
                           x[2]^2/sigma[2]^2-
                           2*rho*x[1]*x[2]/(sigma[1]*sigma[2]))) * 
     1/(2*pi*sigma[1]*sigma[2]*sqrt(1-rho^2))
     }
 out=rbind(c(1,2),c(3,4),c(5,6));

 bvout<-matrix(NA, ncol=1, nrow=3)
 bvout[] <-apply(out, 1, bvnormdens)
 bvout
             [,1]
[1,] 1.306423e-02
[2,] 5.931153e-07
[3,] 9.033134e-15

Varsayılan parametrelerinizden başka kullanmak istiyorsanız, çağrı, işlevden sonra adlandırılmış bağımsız değişkenleri içermelidir:

bvout[] <-apply(out, 1, FUN=bvnormdens, mu=c(-1,1), rho=0.6)

apply () daha yüksek boyutlu dizilerde de kullanılabilir ve MARGIN argümanı bir vektör olabileceği gibi tek bir tamsayı da olabilir.


4

Uygula işi iyi yapar, ancak oldukça yavaştır. Sapply ve vapply kullanmak faydalı olabilir. dplyr'ın rowwise da yararlı olabilir Herhangi bir veri çerçevesinin satır bazında çarpımının nasıl yapılacağına dair bir örnek görelim.

a = data.frame(t(iris[1:10,1:3]))
vapply(a, prod, 0)
sapply(a, prod)

Vapply / sapply / apply'ı kullanmadan önce değişkene atamanın zamanı çok azalttığı için iyi bir uygulama olduğunu unutmayın. Mikro kıyaslama sonuçlarını görelim

a = data.frame(t(iris[1:10,1:3]))
b = iris[1:10,1:3]
microbenchmark::microbenchmark(
    apply(b, 1 , prod),
    vapply(a, prod, 0),
    sapply(a, prod) , 
    apply(iris[1:10,1:3], 1 , prod),
    vapply(data.frame(t(iris[1:10,1:3])), prod, 0),
    sapply(data.frame(t(iris[1:10,1:3])), prod) ,
    b %>%  rowwise() %>%
        summarise(p = prod(Sepal.Length,Sepal.Width,Petal.Length))
)

T () 'nin nasıl kullanıldığına dikkatlice bakın


b <- t(iris[1:10, 1:3])Ve kullandıysanız, geçerli aileyi karşılaştırmak daha adil olabilir apply(b, 2 prod).
DaSpeeg

2

Veri kümesinin değişen bir bölümünü tek bir değer yerine kullanmak istiyorsanız başka bir yaklaşım kullanmaktır rollapply(data, width, FUN, ...). Bir genişlik vektörünün kullanılması, veri kümesinin değişen bir penceresine bir işlev uygulamanıza olanak tanır. Bunu, çok verimli olmasa da uyarlanabilir bir filtreleme rutini oluşturmak için kullandım.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.