Saya memiliki kerangka data dengan banyak kolom. Untuk setiap baris dalam kerangka data, saya ingin memanggil fungsi di baris, dan input fungsi menggunakan beberapa kolom dari baris itu. Sebagai contoh, katakanlah saya memiliki data ini dan testFunc ini yang menerima dua argumen:
> df <- data.frame(x=c(1,2), y=c(3,4), z=c(5,6))
> df
x y z
1 1 3 5
2 2 4 6
> testFunc <- function(a, b) a + b
Katakanlah saya ingin menerapkan testFunc ini ke kolom x dan z. Jadi, untuk baris 1 saya ingin 1 + 5, dan untuk baris 2 saya ingin 2 + 6. Apakah ada cara untuk melakukan ini tanpa menulis perulangan for, mungkin dengan fungsi yang berlaku keluarga?
Saya mencoba ini:
> df[,c('x','z')]
x z
1 1 5
2 2 6
> lapply(df[,c('x','z')], testFunc)
Error in a + b : 'b' is missing
Tapi ada kesalahan, ada ide?
EDIT: fungsi sebenarnya yang ingin saya panggil bukanlah jumlah yang sederhana, tetapi itu adalah power.t.test. Saya menggunakan + b hanya untuk tujuan contoh. Tujuan akhirnya adalah untuk dapat melakukan sesuatu seperti ini (ditulis dalam pseudocode):
df = data.frame(
delta=c(delta_values),
power=c(power_values),
sig.level=c(sig.level_values)
)
lapply(df, power.t.test(delta_from_each_row_of_df,
power_from_each_row_of_df,
sig.level_from_each_row_of_df
))
di mana hasilnya adalah vektor output untuk power.t.test untuk setiap baris df.
dplyr
caranya.Jawaban:
Anda dapat menerapkan
apply
ke subset dari data asli.atau jika fungsi Anda hanya menggunakan versi vektor:
Jika ingin digunakan
testFunc
EDIT Untuk mengakses kolom dengan nama dan bukan indeks, Anda dapat melakukan sesuatu seperti ini:
sumber
apply
pada data.frame besar itu akan menyalin seluruh objek (untuk mengkonversi ke matriks). Ini juga akan menyebabkan masalah Jika Anda memiliki objek kelas yang berbeda di dalam data.frame.A
data.frame
adalahlist
, jadi ...Untuk fungsi vektor
do.call
biasanya merupakan taruhan yang bagus. Namun nama-nama argumen ikut bermain. Di sini AndatestFunc
dipanggil dengan args x dan y di tempat a dan b. The...
memungkinkan args tidak relevan untuk diteruskan tanpa menyebabkan kesalahan:Untuk fungsi non-vektor ,
mapply
akan berfungsi, tetapi Anda harus mencocokkan urutan args atau secara eksplisit menamainya:Kadang
apply
- kadang akan bekerja - seperti ketika semua argumen dari jenis yang sama sehingga memaksadata.frame
ke matriks tidak menyebabkan masalah dengan mengubah tipe data. Contoh Anda dari jenis ini.Jika fungsi Anda dipanggil dalam fungsi lain di mana argumen dilewati, ada metode yang jauh lebih licin daripada ini. Pelajari baris pertama tubuh
lm()
jika Anda ingin pergi rute itu.sumber
Vectorize
sebagai pembungkus untukmapply
fungsi vektorMenggunakan
mapply
sumber
Jawaban baru dengan
dplyr
paketJika fungsi yang ingin Anda terapkan adalah vektor, maka Anda bisa menggunakan
mutate
fungsi daridplyr
paket:Jawaban lama dengan
plyr
paketMenurut pendapat saya, alat yang paling cocok untuk tugas ini adalah
mdply
dariplyr
paket.Contoh:
Sayangnya, seperti yang ditunjukkan Bertjan Broeksema , pendekatan ini gagal jika Anda tidak menggunakan semua kolom bingkai data dalam
mdply
panggilan. Sebagai contoh,sumber
dplyr::mutate_each
. Sebagai contoh:iris %>% mutate_each(funs(half = . / 2),-Species)
.Orang lain telah dengan benar menunjukkan bahwa
mapply
dibuat untuk tujuan ini, tetapi (demi kelengkapan) metode yang lebih sederhana secara konseptual hanya menggunakanfor
loop.sumber
Banyak fungsi sudah vektorisasi, sehingga tidak perlu untuk iterasi (baik
for
loop atau*pply
fungsi). AndatestFunc
adalah salah satu contohnya. Anda cukup menelepon:Secara umum, saya akan merekomendasikan mencoba pendekatan vektorisasi seperti itu terlebih dahulu dan melihat apakah mereka memberi Anda hasil yang Anda inginkan.
Atau, jika Anda perlu memberikan beberapa argumen ke fungsi yang tidak di-vektor-kan,
mapply
mungkin yang Anda cari:sumber
Berikut ini adalah pendekatan alternatif. Ini lebih intuitif.
Satu aspek kunci yang saya rasa beberapa jawaban tidak diperhitungkan, yang saya tunjukkan untuk anak cucu, berlaku () memungkinkan Anda melakukan perhitungan baris dengan mudah, tetapi hanya untuk data matriks (semua angka)
operasi pada kolom masih dimungkinkan untuk kerangka data:
Untuk beroperasi pada baris, kita buat transposnya terlebih dahulu.
Kelemahannya adalah saya percaya R akan membuat salinan tabel data Anda. Yang bisa jadi masalah memori. (Ini benar-benar menyedihkan, karena secara program sederhana untuk tdf hanya menjadi sebuah iterator ke df asli, sehingga menghemat memori, tetapi R tidak mengizinkan pointer atau iterator referensi.)
Selain itu, pertanyaan terkait, adalah bagaimana cara beroperasi pada setiap sel individu dalam kerangka data.
sumber
Saya datang ke sini mencari nama fungsi rapi - yang saya tahu ada. Menambahkan ini untuk referensi masa depan (saya) dan untuk
tidyverse
penggemar:purrrlyr:invoke_rows
(purrr:invoke_rows
dalam versi yang lebih lama).Dengan koneksi ke metode statistik standar seperti pada pertanyaan awal, paket sapu mungkin akan membantu.
sumber
Jawaban @ user20877984 sangat bagus. Karena mereka menyimpulkannya jauh lebih baik daripada jawaban saya sebelumnya, berikut ini adalah upaya saya (yang mungkin masih jelek) pada penerapan konsep:
Menggunakan
do.call
secara dasar:Bekerja pada set data lengkap:
lapply
yangpower.t.test
fungsi untuk masing-masing baris dari nilai yang ditetapkan:sumber
2
, mengapa tidak melamar saja1
?data.table
memiliki cara yang sangat intuitif untuk melakukan ini juga:The
:=
operator dapat disebut dalam tanda kurung untuk menambahkan kolom baru menggunakan fungsiJuga mudah untuk menerima konstanta sebagai argumen dengan menggunakan metode ini:
sumber
Jika kolom data.frame adalah tipe yang berbeda,
apply()
memiliki masalah. Kehalusan tentang iterasi baris adalah bagaimanaapply(a.data.frame, 1, ...)
konversi tipe implisit ke tipe karakter ketika kolom adalah tipe yang berbeda; misalnya. kolom faktor dan angka. Berikut ini contohnya, menggunakan faktor dalam satu kolom untuk memodifikasi kolom angka:Pengurangan gagal karena kolom dikonversi ke tipe karakter.
Salah satu perbaikannya adalah dengan kembali mengonversi kolom kedua ke nomor:
Namun konversi dapat dihindari dengan memisahkan dan menggunakan kolom
mapply()
:mapply()
diperlukan karena[[ ]]
tidak menerima argumen vektor. Jadi iterasi kolom dapat dilakukan sebelum pengurangan dengan melewatkan vektor[]
, dengan kode yang sedikit lebih jelek:sumber
Fungsi yang sangat bagus untuk ini adalah
adply
dariplyr
, terutama jika Anda ingin menambahkan hasilnya ke kerangka data asli. Fungsi ini dan sepupunyaddply
telah menyelamatkan saya dari banyak sakit kepala dan baris kode!Atau, Anda dapat memanggil fungsi yang Anda inginkan.
sumber