9 Pertanyaan: Fungsi pengelompokan (tapply, by, agregat) dan * berlaku keluarga

pertanyaan dibuat di Wed, Oct 3, 2018 12:00 AM

Setiap kali saya ingin melakukan sesuatu "memetakan" py dalam R, saya biasanya mencoba menggunakan fungsi dalam keluarga apply.

Namun, saya tidak pernah benar-benar memahami perbedaan di antara mereka - bagaimana {sapply, lapply, dll} menerapkan fungsi ke input /input yang dikelompokkan, seperti apa outputnya, atau bahkan seperti apa input tersebut. - jadi saya sering melewati semuanya sampai saya mendapatkan yang saya inginkan.

Adakah yang bisa menjelaskan cara menggunakan yang mana saat ini?

Pemahaman saya saat ini (mungkin salah /tidak lengkap) adalah ...

  1. sapply(vec, f): input adalah vektor. output adalah vektor /matriks, di mana elemen i adalah f(vec[i]), memberi Anda sebuah matriks jika f memiliki output multi-elemen

  2. lapply(vec, f): sama dengan sapply, tapi outputnya daftar?

  3.  apply(matrix, 1/2, f): input adalah sebuah matriks. output adalah vektor, di mana elemen i adalah f (baris /kolom i dari matriks)
  4.  tapply(vector, grouping, f): output adalah matriks /array, di mana elemen dalam matriks /array bernilai f pada pengelompokan g vektor, dan g didorong ke baris /nama-nama col
  5.  by(dataframe, grouping, f): biarkan g menjadi pengelompokan. berlaku f untuk setiap kolom grup /bingkai data. cukup cetak pengelompokan dan nilai f di setiap kolom.
  6.  aggregate(matrix, grouping, f): mirip dengan by, tetapi alih-alih mencetak hasil cetak dengan cantik, agregat memasukkan semuanya ke dalam kerangka data.

Pertanyaan sampingan: Saya masih belum belajar plyr atau membentuk kembali - akankah plyr atau reshape mengganti semua ini sepenuhnya?

    
978
  1. ke pertanyaan sampingan Anda: untuk banyak hal plyr adalah pengganti langsung untuk *apply() dan by. plyr (setidaknya bagi saya) tampaknya jauh lebih konsisten karena saya selalu tahu persis format data apa yang diharapkannya dan apa yang akan dimuntahkannya. Itu menyelamatkan saya dari banyak kerumitan.
    2010-08-17 18: 40: 32Z
  2. Juga, saya sarankan menambahkan: doBy dan pilihan & terapkan kemampuan data.table.
    2011-10-10 15: 23: 57Z
  3. sapply hanya lapply dengan tambahan simplify2array pada output. apply memang memaksa untuk vektor atom, tetapi output dapat berupa vektor atau daftar. by membagi dataframe menjadi sub-dataframe, tetapi tidak menggunakan f pada kolom secara terpisah. Hanya jika ada metode untuk kelas 'data.frame' mungkin f bisa diterapkan secara kolom oleh by. aggregate generik sehingga ada berbagai metode untuk kelas berbeda dari argumen pertama.
    2013-01-24 21: 18: 14Z
  4. Mnemonic: l adalah untuk 'daftar', s adalah untuk 'penyederhanaan', t adalah untuk 'per jenis' (setiap tingkat pengelompokan adalah suatu tipe)
    2014-09-16 13: 20: 57Z
  5. Ada juga beberapa fungsi dalam paket Rfast, seperti: Eachcol.apply, apply.condition, dan banyak lagi, yang lebih cepat daripada persamaan R
    2018-11-17 14: 09: 17Z
9 Jawaban                              9                         

R memiliki banyak * fungsi yang berlaku yang dapat dijelaskan dalam file bantuan (mis. ?apply). Ada cukup banyak dari mereka, bahwa penggunaan awal mungkin mengalami kesulitan menentukan mana yang sesuai untuk situasi mereka atau bahkan mengingat semuanya. Mereka mungkin memiliki perasaan umum bahwa "Saya harus menggunakan * menerapkan fungsi di sini", tetapi mungkin sulit untuk menjaga semuanya tetap lurus pada awalnya.

Terlepas dari kenyataan (dicatat dalam jawaban lain) bahwa sebagian besar fungsi * keluarga yang berlaku dicakup oleh paket plyr yang sangat populer, fungsi-fungsi dasar tetap bermanfaat dan patut diketahui.

Jawaban ini dimaksudkan untuk bertindak sebagai semacam plang untuk pengguna baru untuk membantu mengarahkan mereka ke fungsi * berlaku yang benar untuk masalah khusus mereka. Catatan, ini tidak dimaksudkan untuk memuntahkan atau mengganti dokumentasi R! Harapannya adalah bahwa jawaban ini membantu Anda untuk memutuskan * mana yang menerapkan fungsi yang sesuai dengan situasi Anda dan kemudian terserah kepada Anda untuk meneliti lebih lanjut. Dengan satu pengecualian,perbedaan kinerja tidak akan diatasi.

  • terapkan - Saat Anda ingin menerapkan fungsi ke baris atau kolom dari matriks (dan analog berdimensi lebih tinggi); umumnya tidak disarankan untuk frame data karena akan memaksa ke matriks terlebih dahulu.

     
    # Two dimensional matrix
    M <- matrix(seq(1,16), 4, 4)
    
    # apply min to rows
    apply(M, 1, min)
    [1] 1 2 3 4
    
    # apply max to columns
    apply(M, 2, max)
    [1]  4  8 12 16
    
    # 3 dimensional array
    M <- array( seq(32), dim = c(4,4,2))
    
    # Apply sum across each M[*, , ] - i.e Sum across 2nd and 3rd dimension
    apply(M, 1, sum)
    # Result is one-dimensional
    [1] 120 128 136 144
    
    # Apply sum across each M[*, *, ] - i.e Sum across 3rd dimension
    apply(M, c(1,2), sum)
    # Result is two-dimensional
         [,1] [,2] [,3] [,4]
    [1,]   18   26   34   42
    [2,]   20   28   36   44
    [3,]   22   30   38   46
    [4,]   24   32   40   48
    

    Jika Anda ingin cara atau jumlah baris /kolom untuk matriks 2D, pastikan untuk melakukannya selidiki colMeans yang sangat dioptimalkan, secepat kilat,  rowMeans, colSums, rowSums.

  • lapply - Saat Anda ingin menerapkan fungsi ke setiap elemen a daftar pada gilirannya dan dapatkan daftar kembali.

    Ini adalah pekerja keras dari banyak fungsi * lainnya yang berlaku. Kulit kembalikan kode mereka dan Anda akan sering menemukan lapply di bawahnya.

     
    x <- list(a = 1, b = 1:3, c = 10:100) 
    lapply(x, FUN = length) 
    $a 
    [1] 1
    $b 
    [1] 3
    $c 
    [1] 91
    lapply(x, FUN = sum) 
    $a 
    [1] 1
    $b 
    [1] 6
    $c 
    [1] 5005
    
  • sapply - Saat Anda ingin menerapkan fungsi ke setiap elemen a daftar pada gilirannya, tetapi Anda ingin vektor kembali, daripada daftar.

    Jika Anda menemukan diri Anda mengetik unlist(lapply(...)), berhentilah dan pertimbangkan  sapply.

     
    x <- list(a = 1, b = 1:3, c = 10:100)
    # Compare with above; a named vector, not a list 
    sapply(x, FUN = length)  
    a  b  c   
    1  3 91
    
    sapply(x, FUN = sum)   
    a    b    c    
    1    6 5005 
    

    Dalam penggunaan sapply yang lebih canggih, ia akan mencoba untuk memaksa hasil ke array multi-dimensi, jika sesuai. Misalnya, jika fungsi kami mengembalikan vektor dengan panjang yang sama, sapply akan menggunakannya sebagai kolom dari matriks:

     
    sapply(1:5,function(x) rnorm(3,x))
    

    Jika fungsi kami mengembalikan matriks 2 dimensi, sapply pada dasarnya akan melakukan hal yang sama, memperlakukan setiap matriks yang dikembalikan sebagai vektor panjang tunggal:

     
    sapply(1:5,function(x) matrix(x,2,2))
    

    Kecuali kami tentukan simplify = "array", dalam hal ini ia akan menggunakan masing-masing matriks untuk membangun array multi-dimensi:

     
    sapply(1:5,function(x) matrix(x,2,2), simplify = "array")
    

    Setiap perilaku ini tentu saja bergantung pada fungsi kami yang mengembalikan vektor atau matriks dengan panjang atau dimensi yang sama.

  • vapply - Saat Anda ingin menggunakan sapply tetapi mungkin perlu peras lebih cepat dari kode Anda.

    Untuk vapply, Anda pada dasarnya memberi R contoh hal seperti apa fungsi Anda akan kembali, yang dapat menghemat waktu paksaan dikembalikan nilai-nilai yang cocok dalam satu vektor atom.

     
    x <- list(a = 1, b = 1:3, c = 10:100)
    #Note that since the advantage here is mainly speed, this
    # example is only for illustration. We're telling R that
    # everything returned by length() should be an integer of 
    # length 1. 
    vapply(x, FUN = length, FUN.VALUE = 0L) 
    a  b  c  
    1  3 91
    
  • mapply - Untuk saat Anda memiliki beberapa struktur data (mis. vektor, daftar) dan Anda ingin menerapkan fungsi ke elemen 1 masing-masing, dan kemudian elemen ke-2 dari masing-masing, dll, memaksa hasilnya ke vektor /array seperti pada sapply.

    Ini multivarian dalam arti bahwa fungsi Anda harus menerima beberapa argumen.

     
    #Sums the 1st elements, the 2nd elements, etc. 
    mapply(sum, 1:5, 1:5, 1:5) 
    [1]  3  6  9 12 15
    #To do rep(1,4), rep(2,3), etc.
    mapply(rep, 1:4, 4:1)   
    [[1]]
    [1] 1 1 1 1
    
    [[2]]
    [1] 2 2 2
    
    [[3]]
    [1] 3 3
    
    [[4]]
    [1] 4
    
  • Peta - Pembungkus ke mapply dengan SIMPLIFY = FALSE, sehingga dijamin untuk mengembalikan daftar.

     
    Map(sum, 1:5, 1:5, 1:5)
    [[1]]
    [1] 3
    
    [[2]]
    [1] 6
    
    [[3]]
    [1] 9
    
    [[4]]
    [1] 12
    
    [[5]]
    [1] 15
    
  • rapply - Untuk saat Anda ingin menerapkan fungsi ke setiap elemen dari struktur daftar bersarang , secara rekursif.

    Untuk memberi Anda gambaran tentang seberapa jarang rapply, saya lupa tentangnya saat pertama kali memposting jawaban ini! Jelas, saya yakin banyak orang menggunakannya, tapi YMMV. rapply paling baik digambarkan dengan fungsi yang ditentukan pengguna untuk diterapkan:

     
    # Append ! to string, otherwise increment
    myFun <- function(x){
        if(is.character(x)){
          return(paste(x,"!",sep=""))
        }
        else{
          return(x + 1)
        }
    }
    
    #A nested list structure
    l <- list(a = list(a1 = "Boo", b1 = 2, c1 = "Eeek"), 
              b = 3, c = "Yikes", 
              d = list(a2 = 1, b2 = list(a3 = "Hey", b3 = 5)))
    
    
    # Result is named vector, coerced to character          
    rapply(l, myFun)
    
    # Result is a nested list like l, with values altered
    rapply(l, myFun, how="replace")
    
  • menyadap - Untuk saat Anda ingin menerapkan fungsi ke subset dari a vektor dan himpunan bagian didefinisikan oleh beberapa vektor lain, biasanya a faktor.

    Domba hitam dari keluarga * berlaku, semacam. File bantuan ini menggunakan frasa "ragged array" dapat menjadi sedikit membingungkan , tetapi sebenarnya membingungkan cukup sederhana.

    Vektor:

     
    x <- 1:20
    

    Faktor (dengan panjang yang sama!) yang mendefinisikan grup:

     
    y <- factor(rep(letters[1:5], each = 4))
    

    Tambahkan nilai di x dalam setiap subkelompok yang ditentukan oleh y:

     
    tapply(x, y, sum)  
     a  b  c  d  e  
    10 26 42 58 74 
    

    Contoh yang lebih kompleks dapat ditangani di mana subkelompok didefinisikan oleh kombinasi unik dari daftar beberapa faktor. tapply adalah serupa semangatnya dengan fungsi split-apply-menggabungkan yang ada umum dalam R (aggregate, by, ave, ddply, dll.) status kambing hitam.

1264
2017-10-03 19: 54: 11Z
  1. Percayalah Anda akan menemukan bahwa by adalah murni split-lapply dan aggregate adalah tapply di inti mereka. Saya pikir domba hitam membuat bahan yang bagus.
    2011-09-14 03: 42: 55Z
  2. Respons yang fantastis! Ini harus menjadi bagian dari dokumentasi R resmi :). Satu saran kecil: mungkin menambahkan beberapa peluru tentang penggunaan aggregate dan by juga? (Saya akhirnya memahaminya setelah uraian Anda!, Tetapi itu cukup umum, jadi mungkin berguna untuk memisahkan dan memiliki beberapa contoh spesifik untuk kedua fungsi tersebut.)
    2011-09-14 18: 54: 28Z
  3. @ grauJika saya secara aktif memangkas hal-hal dari jawaban ini untuk menghindari (a) terlalu lama dan (b) menulis ulang dokumentasi. Saya memutuskan bahwa sementara aggregate, by, dll. Didasarkan pada * fungsi berlaku, cara Anda mendekati menggunakannya cukup berbeda dari perspektif pengguna sehingga harus diringkas dalam jawaban terpisah. Saya mungkin berusaha jika saya punya waktu, atau mungkin orang lain akan mengalahkan saya untuk itu dan mendapatkan upvote saya.
    2011-09-14 23: 03: 22Z
  4. juga, ?Map sebagai kerabat mapply
    2012-02-16 05: 53: 24Z
  5. @ jsanders - Saya tidak akan setuju dengan itu sama sekali. data.frame s adalah bagian yang mutlak sentral dari R dan sebagai objek list sering dimanipulasi menggunakan lapply khususnya. Mereka juga bertindak sebagai wadah untuk mengelompokkan vektor /faktor dari banyak jenis bersama-sama dalam dataset persegi panjang tradisional. Meskipun data.table dan plyr mungkin menambahkan jenis sintaksis tertentu yang mungkin lebih nyaman bagi sebagian orang, 49910 memperluas dan bertindak pada data.frame s.
    2014-08-20 06: 08: 15Z

Pada catatan samping, berikut adalah bagaimana berbagai fungsi plyr sesuai dengan fungsi dasar *apply (dari intro ke dokumen plyr dari halaman web plyr http://had.co.nz/plyr/)

 
Base function   Input   Output   plyr function 
---------------------------------------
aggregate        d       d       ddply + colwise 
apply            a       a/l     aaply / alply 
by               d       l       dlply 
lapply           l       l       llply  
mapply           a       a/l     maply / mlply 
replicate        r       a/l     raply / rlply 
sapply           l       a       laply 

Salah satu tujuan plyr adalah untuk menyediakan konvensi penamaan yang konsisten untuk setiap fungsi, menyandikan tipe data input dan output dalam nama fungsi. Ini juga memberikan konsistensi dalam output, di mana output dari dlply() mudah dilewati hingga ldply() untuk menghasilkan output yang bermanfaat, dll.

Secara konsep, mempelajari plyr tidak lebih sulit daripada memahami fungsi-fungsi dasar *apply.

plyr dan reshape fungsi telah menggantikan hampir semua fungsi ini dalam penggunaan saya setiap hari. Tapi, juga dari dokumen Intro ke Plyr:

  

Fungsi terkait tapply dan sweep tidak memiliki fungsi yang sesuai di plyr, dan tetap berguna. merge berguna untuk menggabungkan ringkasan dengan data asli.

    
180
2010-08-17 19: 20: 09Z
  1. Ketika saya mulai belajar R dari awal, saya menemukan plyr JAUH lebih mudah untuk dipelajari daripada *apply() keluarga fungsi. Bagi saya, ddply() sangat intuitif karena saya terbiasa dengan fungsi agregasi SQL. ddply() menjadi palu saya untuk memecahkan banyak masalah, beberapa di antaranya dapat diselesaikan dengan lebih baik dengan perintah lain.
    2010-08-17 19: 23: 29Z
  2. Saya kira saya berpendapat bahwa konsep di balik plyr fungsi mirip dengan *apply fungsi, jadi jika Anda bisa melakukan satu, Anda bisa melakukan yang lain, tetapi plyr fungsi lebih mudah untuk ingat. Tapi saya sepenuhnya setuju dengan palu ddply()!
    2010-08-17 19: 36: 22Z
  3. Mengerti, aku harus segera mengambil plyr segera! Penamaan awalannya sendiri adalah emas ...
    2010-08-17 22: 28: 44Z
  4. +1 Untuk menambahkan catatan tentang tapply dan sweep. Senang mengetahui apa yang bisa dan tidak bisa dilakukan plyr.
    2012-06-22 19: 01: 29Z
  5. Paket plyr memiliki fungsi join() yang melakukan tugas yang mirip dengan penggabungan. Mungkin lebih tepat untuk menyebutkannya dalam konteks plyr.
    2014-01-02 23: 04: 26Z

Dari slide 21 dari http://www.slideshare.net/hadley /plyr-one-data-analitik-strategi :

terapkan, sapply, lapply, oleh, agregat

(Semoga jelas bahwa apply berkorespondensi dengan @4980 Hadley dan aaply berkorespondensi dengan @ Hadley aggregate dll. Slide 20 dari slideshare yang sama akan menjelaskan jika Anda tidak mendapatkannya dari gambar ini.)

(di sebelah kiri adalah input, di atas adalah output)

    
127
2012-02-15 23: 42: 48Z
  1. apakah ada kesalahan ketik pada slide? Sel kiri atas seharusnya aaply
    2016-09-16 18: 16: 25Z

Pertama mulai dengan jawaban yang sangat bagus dari Joran - keraguan apa pun bisa lebih baik dari itu.

Kemudian mnemonik berikut dapat membantu mengingat perbedaan di antara masing-masing. Sementara beberapa jelas, yang lain mungkin kurang begitu --- untuk ini Anda akan menemukan pembenaran dalam diskusi Joran.

  •  ddply adalah daftar yang berlaku yang berlaku pada daftar atau vektor dan mengembalikan daftar.
  •  lapply adalah sederhana sapply (fungsi default untuk mengembalikan vektor atau matriks jika memungkinkan)
  •  lapply adalah terverifikasi terapkan (memungkinkan tipe objek kembali ditentukan sebelumnya)
  •  vapply adalah rekursif berlaku untuk daftar bersarang, mis. Daftar dalam daftar
  •  rapply adalah tagged berlaku ketika tag mengidentifikasi subset
  •  tapply adalah generik : menerapkan fungsi ke baris atau kolom matriks (atau, lebih umum, ke dimensi array)

Membangun Latar Belakang yang Tepat

Jika menggunakan keluarga apply masih terasa agak asing bagi Anda, mungkin Anda kehilangan sudut pandang kunci.

Dua artikel ini dapat membantu. Mereka memberikan latar belakang yang diperlukan untuk memotivasi teknik pemrograman fungsional yang disediakan oleh apply kelompok fungsi.

Pengguna Lisp akan mengenali paradigma dengan segera. Jika Anda tidak terbiasa dengan Lisp, begitu Anda mengenal FP, Anda akan mendapatkan sudut pandang yang kuat untuk digunakan dalam R - dan apply akan jauh lebih masuk akal.

95
2017-05-23 10: 31: 37Z

Karena saya menyadari bahwa (sangat bagus) jawaban dari pos ini kurang dari apply dan by penjelasan. Inilah kontribusi saya.

OLEH

Fungsi aggregate, seperti yang dinyatakan dalam dokumentasi dapat, sebagai "pembungkus" untuk by. Kekuatan tapply muncul ketika kita ingin menghitung tugas yang tidak bisa ditangani oleh by. Salah satu contohnya adalah kode ini:

 tapply

Jika kita mencetak dua objek ini,

ct <- tapply(iris$Sepal.Width , iris$Species , summary )
cb <- by(iris$Sepal.Width , iris$Species , summary )

 cb
iris$Species: setosa
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.300   3.200   3.400   3.428   3.675   4.400 
-------------------------------------------------------------- 
iris$Species: versicolor
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.000   2.525   2.800   2.770   3.000   3.400 
-------------------------------------------------------------- 
iris$Species: virginica
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.200   2.800   3.000   2.974   3.175   3.800 


ct
$setosa
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.300   3.200   3.400   3.428   3.675   4.400 

$versicolor
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.000   2.525   2.800   2.770   3.000   3.400 

$virginica
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.200   2.800   3.000   2.974   3.175   3.800 
dan ct, kita "pada dasarnya" memiliki hasil yang sama dan satu-satunya perbedaan adalah dalam bagaimana mereka ditampilkan dan cb atribut yang berbeda, masing-masing class untuk by dan cb untuk array.

Seperti yang saya katakan, kekuatan ct muncul ketika kita tidak bisa menggunakan by; kode berikut adalah salah satu contoh:

 tapply

R mengatakan bahwa argumen harus memiliki panjang yang sama, katakan "kami ingin menghitung

 tapply(iris, iris$Species, summary )
Error in tapply(iris, iris$Species, summary) : 
  arguments must have same length
dari semua variabel di summary di sepanjang faktor iris": tetapi R tidak bisa melakukan itu karena tidak tahu cara menanganinya.

Dengan fungsi Species R mengirim metode khusus untuk kelas by dan kemudian membiarkan fungsi data frame bekerja bahkan jika panjang argumen pertama (dan tipenya juga) berbeda.

 summary

memang berhasil dan hasilnya sangat mengejutkan. Ini adalah objek dari kelas

bywork <- by(iris, iris$Species, summary )

bywork
iris$Species: setosa
  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width          Species  
 Min.   :4.300   Min.   :2.300   Min.   :1.000   Min.   :0.100   setosa    :50  
 1st Qu.:4.800   1st Qu.:3.200   1st Qu.:1.400   1st Qu.:0.200   versicolor: 0  
 Median :5.000   Median :3.400   Median :1.500   Median :0.200   virginica : 0  
 Mean   :5.006   Mean   :3.428   Mean   :1.462   Mean   :0.246                  
 3rd Qu.:5.200   3rd Qu.:3.675   3rd Qu.:1.575   3rd Qu.:0.300                  
 Max.   :5.800   Max.   :4.400   Max.   :1.900   Max.   :0.600                  
-------------------------------------------------------------- 
iris$Species: versicolor
  Sepal.Length    Sepal.Width     Petal.Length   Petal.Width          Species  
 Min.   :4.900   Min.   :2.000   Min.   :3.00   Min.   :1.000   setosa    : 0  
 1st Qu.:5.600   1st Qu.:2.525   1st Qu.:4.00   1st Qu.:1.200   versicolor:50  
 Median :5.900   Median :2.800   Median :4.35   Median :1.300   virginica : 0  
 Mean   :5.936   Mean   :2.770   Mean   :4.26   Mean   :1.326                  
 3rd Qu.:6.300   3rd Qu.:3.000   3rd Qu.:4.60   3rd Qu.:1.500                  
 Max.   :7.000   Max.   :3.400   Max.   :5.10   Max.   :1.800                  
-------------------------------------------------------------- 
iris$Species: virginica
  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width          Species  
 Min.   :4.900   Min.   :2.200   Min.   :4.500   Min.   :1.400   setosa    : 0  
 1st Qu.:6.225   1st Qu.:2.800   1st Qu.:5.100   1st Qu.:1.800   versicolor: 0  
 Median :6.500   Median :3.000   Median :5.550   Median :2.000   virginica :50  
 Mean   :6.588   Mean   :2.974   Mean   :5.552   Mean   :2.026                  
 3rd Qu.:6.900   3rd Qu.:3.175   3rd Qu.:5.875   3rd Qu.:2.300                  
 Max.   :7.900   Max.   :3.800   Max.   :6.900   Max.   :2.500     
yang sepanjang by (katakanlah, untuk masing-masing) menghitung Species dari setiap variabel.

Perhatikan bahwa jika argumen pertama adalah summary, fungsi yang dikirim harus memiliki metode untuk kelas objek tersebut. Sebagai contoh adalah kita menggunakan kode ini dengan fungsi data frame kita akan memiliki kode ini yang sama sekali tidak masuk akal:

 mean

AGREGAT

 by(iris, iris$Species, mean)
iris$Species: setosa
[1] NA
------------------------------------------- 
iris$Species: versicolor
[1] NA
------------------------------------------- 
iris$Species: virginica
[1] NA
Warning messages:
1: In mean.default(data[x, , drop = FALSE], ...) :
  argument is not numeric or logical: returning NA
2: In mean.default(data[x, , drop = FALSE], ...) :
  argument is not numeric or logical: returning NA
3: In mean.default(data[x, , drop = FALSE], ...) :
  argument is not numeric or logical: returning NA
dapat dilihat sebagai cara penggunaan aggregate yang berbeda jika kita menggunakannya sedemikian rupa.  tapply

Dua perbedaan langsung adalah bahwa argumen kedua

at <- tapply(iris$Sepal.Length , iris$Species , mean)
ag <- aggregate(iris$Sepal.Length , list(iris$Species), mean)

 at
    setosa versicolor  virginica 
     5.006      5.936      6.588 
 ag
     Group.1     x
1     setosa 5.006
2 versicolor 5.936
3  virginica 6.588
harus menjadi daftar sementara aggregate dapat (tidak wajib) menjadi daftar dan bahwa output dari tapply adalah bingkai data sedangkan yang dari aggregate adalah tapply.

Kekuatan array adalah ia dapat menangani subset data dengan mudah dengan argumen aggregate dan memiliki metode untuk subset objek dan ts juga.

Elemen-elemen ini membuat formula lebih mudah untuk digunakan dengan aggregate dalam beberapa situasi. Berikut ini beberapa contoh (tersedia dalam dokumentasi):

 tapply

Kita dapat mencapai hal yang sama dengan

ag <- aggregate(len ~ ., data = ToothGrowth, mean)

 ag
  supp dose   len
1   OJ  0.5 13.23
2   VC  0.5  7.98
3   OJ  1.0 22.70
4   VC  1.0 16.77
5   OJ  2.0 26.06
6   VC  2.0 26.14
tetapi sintaksnya sedikit lebih sulit dan output (dalam beberapa keadaan) kurang dapat dibaca:  tapply

Ada saat-saat lain ketika kami tidak dapat menggunakan

att <- tapply(ToothGrowth$len, list(ToothGrowth$dose, ToothGrowth$supp), mean)

 att
       OJ    VC
0.5 13.23  7.98
1   22.70 16.77
2   26.06 26.14
atau by dan kami harus menggunakan tapply.  aggregate

Kami tidak dapat memperoleh hasil sebelumnya dengan

 ag1 <- aggregate(cbind(Ozone, Temp) ~ Month, data = airquality, mean)

 ag1
  Month    Ozone     Temp
1     5 23.61538 66.73077
2     6 29.44444 78.22222
3     7 59.11538 83.88462
4     8 59.96154 83.96154
5     9 31.44828 76.89655
dalam satu panggilan tetapi kami harus menghitung rata-rata sepanjang tapply untuk setiap elemen dan kemudian menggabungkannya (juga perhatikan bahwa kami harus memanggil Month, karena metode na.rm = TRUE dari fungsi formula memiliki secara default aggregate):  na.action = na.omit

sementara dengan

ta1 <- tapply(airquality$Ozone, airquality$Month, mean, na.rm = TRUE)
ta2 <- tapply(airquality$Temp, airquality$Month, mean, na.rm = TRUE)

 cbind(ta1, ta2)
       ta1      ta2
5 23.61538 65.54839
6 29.44444 79.10000
7 59.11538 83.90323
8 59.96154 83.96774
9 31.44828 76.90000
kami tidak dapat mencapai hal itu pada kenyataannya panggilan fungsi berikut mengembalikan kesalahan (tetapi kemungkinan besar itu terkait dengan fungsi yang disediakan, by):  mean

Lain kali hasilnya sama dan perbedaannya hanya di kelas (dan kemudian bagaimana itu ditampilkan /dicetak dan tidak hanya - contoh, cara subset itu) objek:

 
by(airquality[c("Ozone", "Temp")], airquality$Month, mean, na.rm = TRUE)

Kode sebelumnya mencapai tujuan dan hasil yang sama, pada beberapa titik alat apa yang digunakan hanyalah masalah selera dan kebutuhan pribadi; dua objek sebelumnya memiliki kebutuhan yang sangat berbeda dalam hal subset.

    
44
2015-08-28 10: 03: 08Z
  1. Seperti yang telah saya katakan, kekuatan oleh muncul ketika kita tidak dapat menggunakan tapply; kode berikut adalah salah satu contoh: INI ADALAH KATA-KATA YANG ANDA TELAH DIGUNAKAN DI ATAS. Dan Anda telah memberikan contoh perhitungan ringkasan. Baiklah katakanlah bahwa ringkasan statistik hanya dapat dihitung yang perlu dibersihkan: misalnya
    byagg <- by(airquality[c("Ozone", "Temp")], airquality$Month, summary)
    aggagg <- aggregate(cbind(Ozone, Temp) ~ Month, data = airquality, summary)
    
    ini adalah penggunaan data.frame(tapply(unlist(iris[,-5]),list(rep(iris[,5],ncol(iris[-5])),col(iris[-5])),summary)) tapply . With the right splitting there is nothing you cant do with tapply`
    2017-12-24 20: 23: 13Z

Ada banyak jawaban hebat yang membahas perbedaan dalam kasus penggunaan untuk setiap fungsi. Tidak ada jawaban yang membahas perbedaan kinerja. Itu wajar karena berbagai fungsi mengharapkan berbagai input dan menghasilkan berbagai output, namun kebanyakan dari mereka memiliki tujuan umum bersama untuk mengevaluasi secara seri /kelompok. Jawaban saya akan fokus pada kinerja. Karena di atas penciptaan input dari vektor termasuk dalam pengaturan waktu, juga fungsi . The only thing is it returns a matrix. Please be careful by saying we cant use tidak diukur.

Saya telah menguji dua fungsi yang berbeda, apply dan sum sekaligus. Volume yang diuji adalah 50M pada input dan 50K pada output. Saya juga menyertakan dua paket populer saat ini yang tidak banyak digunakan pada saat pertanyaan diajukan, length dan data.table. Keduanya pasti layak untuk dilihat jika Anda bertujuan untuk kinerja yang baik.

 dplyr

 
library(dplyr)
library(data.table)
set.seed(123)
n = 5e7
k = 5e5
x = runif(n)
grp = sample(k, n, TRUE)

timing = list()

# sapply
timing[["sapply"]] = system.time({
    lt = split(x, grp)
    r.sapply = sapply(lt, function(x) list(sum(x), length(x)), simplify = FALSE)
})

# lapply
timing[["lapply"]] = system.time({
    lt = split(x, grp)
    r.lapply = lapply(lt, function(x) list(sum(x), length(x)))
})

# tapply
timing[["tapply"]] = system.time(
    r.tapply <- tapply(x, list(grp), function(x) list(sum(x), length(x)))
)

# by
timing[["by"]] = system.time(
    r.by <- by(x, list(grp), function(x) list(sum(x), length(x)), simplify = FALSE)
)

# aggregate
timing[["aggregate"]] = system.time(
    r.aggregate <- aggregate(x, list(grp), function(x) list(sum(x), length(x)), simplify = FALSE)
)

# dplyr
timing[["dplyr"]] = system.time({
    df = data_frame(x, grp)
    r.dplyr = summarise(group_by(df, grp), sum(x), n())
})

# data.table
timing[["data.table"]] = system.time({
    dt = setnames(setDT(list(x, grp)), c("x","grp"))
    r.data.table = dt[, .(sum(x), .N), grp]
})

# all output size match to group count
sapply(list(sapply=r.sapply, lapply=r.lapply, tapply=r.tapply, by=r.by, aggregate=r.aggregate, dplyr=r.dplyr, data.table=r.data.table), 
       function(x) (if(is.data.frame(x)) nrow else length)(x)==k)
#    sapply     lapply     tapply         by  aggregate      dplyr data.table 
#      TRUE       TRUE       TRUE       TRUE       TRUE       TRUE       TRUE 
    
31
2015-12-08 22: 50: 30Z
  1. Apakah normal jika dplyr lebih rendah dari fungsi applt?
    2016-06-08 09: 35: 21Z
  2. @ DimitriPetrenko Saya tidak berpikir begitu, tidak yakin mengapa itu ada di sini. Yang terbaik adalah menguji terhadap data Anda sendiri, karena ada banyak faktor yang ikut berperan.
    2016-06-08 11: 48: 54Z

Mungkin perlu disebutkan

# print timings
as.data.table(sapply(timing, `[[`, "elapsed"), keep.rownames = TRUE
              )[,.(fun = V1, elapsed = V2)
                ][order(-elapsed)]
#          fun elapsed
#1:  aggregate 109.139
#2:         by  25.738
#3:      dplyr  18.978
#4:     tapply  17.006
#5:     lapply  11.524
#6:     sapply  11.326
#7: data.table   2.686
. ave adalah sepupu ramah ave. Ia mengembalikan hasil dalam bentuk yang dapat Anda pasang langsung ke dalam bingkai data Anda.  tapply

Tidak ada dalam paket dasar yang berfungsi seperti

dfr <- data.frame(a=1:20, f=rep(LETTERS[1:5], each=4))
means <- tapply(dfr$a, dfr$f, mean)
##  A    B    C    D    E 
## 2.5  6.5 10.5 14.5 18.5 

## great, but putting it back in the data frame is another line:

dfr$m <- means[dfr$f]

dfr$m2 <- ave(dfr$a, dfr$f, FUN=mean) # NB argument name FUN is needed!
dfr
##   a f    m   m2
##   1 A  2.5  2.5
##   2 A  2.5  2.5
##   3 A  2.5  2.5
##   4 A  2.5  2.5
##   5 B  6.5  6.5
##   6 B  6.5  6.5
##   7 B  6.5  6.5
##   ...
untuk seluruh frame data (karena ave seperti by untuk frame data). Tapi Anda bisa memperdayainya:  tapply     
22
2014-11-06 00: 00: 25Z

Terlepas dari semua jawaban hebat di sini, ada 2 fungsi dasar lainnya yang layak disebutkan, fungsi

dfr$foo <- ave(1:nrow(dfr), dfr$f, FUN=function(x) {
    x <- dfr[x,]
    sum(x$m*x$m2)
})
dfr
##     a f    m   m2    foo
## 1   1 A  2.5  2.5    25
## 2   2 A  2.5  2.5    25
## 3   3 A  2.5  2.5    25
## ...
yang berguna dan fungsi outer yang tidak jelas

eapply adalah fungsi yang sangat berguna disembunyikan sebagai yang lebih biasa. Jika Anda membaca bantuan untuk outer, uraiannya berbunyi:

 outer

yang membuatnya tampak seperti ini hanya berguna untuk hal-hal jenis aljabar linier. Namun, ini dapat digunakan seperti

The outer product of the arrays X and Y is the array A with dimension  
c(dim(X), dim(Y)) where element A[c(arrayindex.x, arrayindex.y)] =   
FUN(X[arrayindex.x], Y[arrayindex.y], ...).
untuk menerapkan fungsi ke dua vektor input. Perbedaannya adalah bahwa mapply akan menerapkan fungsi ke dua elemen pertama dan kemudian kedua kedua dll, sedangkan mapply akan menerapkan fungsi untuk setiap kombinasi satu elemen dari vektor pertama dan satu dari yang kedua. Misalnya:  outer

Saya telah menggunakan ini secara pribadi ketika saya memiliki vektor nilai dan vektor kondisi dan ingin melihat nilai mana yang memenuhi kondisi mana.

 A<-c(1,3,5,7,9)
 B<-c(0,3,6,9,12)

mapply(FUN=pmax, A, B)

> mapply(FUN=pmax, A, B)
[1]  1  3  6  9 12

outer(A,B, pmax)

 > outer(A,B, pmax)
      [,1] [,2] [,3] [,4] [,5]
 [1,]    1    3    6    9   12
 [2,]    3    3    6    9   12
 [3,]    5    5    6    9   12
 [4,]    7    7    7    9   12
 [5,]    9    9    9    9   12
seperti eapply kecuali bahwa alih-alih menerapkan fungsi ke setiap elemen dalam daftar, itu berlaku fungsi untuk setiap elemen di lingkungan. Misalnya jika Anda ingin menemukan daftar fungsi yang ditentukan pengguna di lingkungan global:

 lapply

Sejujurnya saya tidak menggunakan ini terlalu banyak tetapi jika Anda membangun banyak paket atau membuat banyak lingkungan, ini mungkin berguna.

    
22
2016-06-03 13: 37: 53Z

Baru-baru ini saya menemukan fungsi

A<-c(1,3,5,7,9)
B<-c(0,3,6,9,12)
C<-list(x=1, y=2)
D<-function(x){x+1}

> eapply(.GlobalEnv, is.function)
$A
[1] FALSE

$B
[1] FALSE

$C
[1] FALSE

$D
[1] TRUE 
yang agak berguna dan menambahkannya di sini demi kelengkapan:

Gagasan dasarnya adalah untuk menyapu melalui baris-atau kolom-bijaksana dan mengembalikan array yang dimodifikasi. Sebuah contoh akan memperjelas ini (sumber: datacamp ) :

Katakanlah Anda memiliki sebuah matriks dan ingin membuat standar dengan bijaksana kolom:

 sweep

NB: untuk contoh sederhana ini hasil yang sama tentu saja dapat dicapai dengan lebih mudah

dataPoints <- matrix(4:15, nrow = 4)

# Find means per column with `apply()`
dataPoints_means <- apply(dataPoints, 2, mean)

# Find standard deviation with `apply()`
dataPoints_sdev <- apply(dataPoints, 2, sd)

# Center the points 
dataPoints_Trans1 <- sweep(dataPoints, 2, dataPoints_means,"-")
print(dataPoints_Trans1)
##      [,1] [,2] [,3]
## [1,] -1.5 -1.5 -1.5
## [2,] -0.5 -0.5 -0.5
## [3,]  0.5  0.5  0.5
## [4,]  1.5  1.5  1.5
# Return the result
dataPoints_Trans1
##      [,1] [,2] [,3]
## [1,] -1.5 -1.5 -1.5
## [2,] -0.5 -0.5 -0.5
## [3,]  0.5  0.5  0.5
## [4,]  1.5  1.5  1.5
# Normalize
dataPoints_Trans2 <- sweep(dataPoints_Trans1, 2, dataPoints_sdev, "/")

# Return the result
dataPoints_Trans2
##            [,1]       [,2]       [,3]
## [1,] -1.1618950 -1.1618950 -1.1618950
## [2,] -0.3872983 -0.3872983 -0.3872983
## [3,]  0.3872983  0.3872983  0.3872983
## [4,]  1.1618950  1.1618950  1.1618950
    
8
2017-06-16 16: 03: 27Z
  1. Apakah ini terkait dengan pengelompokan?
    2017-06-16 16: 55: 03Z
  2. @ Frank: Ya, jujur ​​saja dengan Anda, judul posting ini agak menyesatkan: ketika Anda membaca pertanyaan itu sendiri, ini tentang "keluarga yang berlaku". apply(dataPoints, 2, scale) adalah fungsi tingkat tinggi seperti yang lain yang disebutkan di sini, mis. sweep, apply, sapply Jadi pertanyaan yang sama dapat ditanyakan tentang jawaban yang diterima dengan lebih dari 1.000 upvote dan contoh-contoh yang diberikan di dalamnya. Lihat saja contoh yang diberikan untuk lapply di sana.
    2017-06-16 17: 03: 57Z
  3. Oh benar, bagus.
    2017-06-16 18: 08: 14Z
  4. sweep memiliki nama yang menyesatkan, standar yang menyesatkan, dan nama parameter yang menyesatkan :). Lebih mudah bagi saya untuk memahaminya dengan cara ini: 1) STATS adalah vektor atau nilai tunggal yang akan diulang untuk membentuk matriks dengan ukuran yang sama dengan input pertama, 2) FUN akan diterapkan pada input pertama dan matriks baru ini. Mungkin lebih baik diilustrasikan oleh: apply. Biasanya lebih efisien daripada sweep(matrix(1:6,nrow=2),2,7:9,list) karena di mana apply loop, apply dapat menggunakan fungsi vektor.
    2018-03-24 15: 04: 09Z
sweep
sumber ditempatkan sini