Menerapkan fungsi ke setiap baris matriks atau bingkai data

130

Misalkan saya memiliki matriks dengan 2 dan fungsi yang mengambil 2-vektor sebagai salah satu argumennya. Saya ingin menerapkan fungsi ke setiap baris matriks dan mendapatkan vektor-n. Bagaimana melakukan ini di R?

Misalnya, saya ingin menghitung kepadatan distribusi Normal standar 2D pada tiga titik:

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))

Bagaimana cara menerapkan fungsi ke setiap baris out?

Bagaimana cara melewatkan nilai untuk argumen lain selain poin ke fungsi dengan cara yang Anda tentukan?

Tim
sumber

Jawaban:

181

Anda cukup menggunakan apply()fungsinya:

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> 

Ini mengambil matriks dan menerapkan fungsi (konyol) ke setiap baris. Anda meneruskan argumen tambahan ke fungsi sebagai argumen keempat, kelima, ... ke apply().

Dirk Eddelbuettel
sumber
Terima kasih! Bagaimana jika baris dari matriks tersebut bukan argumen pertama dari fungsinya? Bagaimana cara menentukan arg dari fungsi yang ditugaskan ke setiap baris matriks?
Tim
Baca bantuan untuk apply()- ini menyapu demi baris (jika argumen kedua adalah 1, selain itu dengan kolom), dan baris saat ini (atau kolom) selalu merupakan argumen pertama. Begitulah cara hal-hal didefinisikan.
Dirk Eddelbuettel
@ Tim: jika Anda menggunakan fungsi R internal dan baris tersebut bukan argumen pertama, lakukan seperti yang dilakukan Dirk dan buat fungsi kustom Anda sendiri di mana baris adalah argumen pertama.
Joris Meys
3
Paket plyr menyediakan berbagai macam fungsi terapan ini. Ini juga menyediakan lebih banyak fungsionalitas, termasuk pemrosesan paralel.
Paul Hiemstra
6
@ cryptic0 jawaban ini terlambat, tetapi untuk googler, argumen kedua yang diterapkan adalah MARGINargumennya. Di sini artinya menerapkan fungsi ke baris (dimensi pertama dalam dim(M)). Jika jumlahnya 2, itu akan menerapkan fungsi ke kolom.
De Novo
17

Jika Anda ingin menerapkan fungsi umum seperti sum atau mean, Anda harus menggunakan rowSumsatau rowMeanskarena lebih cepat daripada apply(data, 1, sum)pendekatan. Jika tidak, tetaplah dengan apply(data, 1, fun). Anda bisa meneruskan argumen tambahan setelah argumen FUN (seperti yang sudah disarankan Dirk):

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

Kemudian Anda dapat melakukan sesuatu seperti ini:

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
aL3xa
sumber
15

Berikut adalah contoh singkat penerapan fungsi ke setiap baris matriks. (Di sini, fungsi yang diterapkan menormalkan setiap baris ke 1.)

Catatan: Hasil dari apply()harus dialihkan menggunakan t()untuk mendapatkan tata letak yang sama dengan matriks masukan 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) ))

Hasil:

     [,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
Viliam Simko
sumber
6

Langkah pertama adalah membuat objek fungsi, lalu menerapkannya. Jika Anda menginginkan objek matriks yang memiliki jumlah baris yang sama, Anda dapat menentukannya sebelumnya dan menggunakan bentuk objek [] seperti yang diilustrasikan (jika tidak, nilai yang dikembalikan akan disederhanakan menjadi vektor):

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

Jika Anda ingin menggunakan selain parameter default Anda, panggilan harus menyertakan argumen bernama setelah fungsi:

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

apply () juga bisa digunakan pada larik berdimensi lebih tinggi dan argumen MARGIN bisa berupa vektor serta bilangan bulat tunggal.

IRTFM
sumber
4

Melamar berhasil dengan baik, tetapi cukup lambat. Menggunakan sapply dan vapply bisa bermanfaat. rowwise dplyr juga bisa berguna Mari kita lihat contoh bagaimana melakukan produk bijak baris dari setiap bingkai data.

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

Perhatikan bahwa menugaskan ke variabel sebelum menggunakan vapply / sapply / apply adalah praktik yang baik karena mengurangi banyak waktu. Mari kita lihat hasil microbenchmark

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))
)

Perhatikan dengan cermat bagaimana t () digunakan

Pratham
sumber
Mungkin lebih adil untuk membandingkan keluarga apply jika Anda menggunakan b <- t(iris[1:10, 1:3])dan apply(b, 2 prod).
DaSpeeg
2

Pendekatan lain jika Anda ingin menggunakan bagian yang bervariasi dari kumpulan data alih-alih satu nilai adalah dengan menggunakan rollapply(data, width, FUN, ...). Menggunakan vektor dengan lebar memungkinkan Anda untuk menerapkan fungsi pada jendela yang bervariasi dari kumpulan data. Saya telah menggunakan ini untuk membangun rutinitas pemfilteran adaptif, meskipun tidak terlalu efisien.

DWAHL
sumber