Dapatkah mutasi digunakan ketika mutasi bersyarat (tergantung pada nilai-nilai nilai kolom tertentu)?
Contoh ini membantu menunjukkan apa yang saya maksud.
structure(list(a = c(1, 3, 4, 6, 3, 2, 5, 1), b = c(1, 3, 4,
2, 6, 7, 2, 6), c = c(6, 3, 6, 5, 3, 6, 5, 3), d = c(6, 2, 4,
5, 3, 7, 2, 6), e = c(1, 2, 4, 5, 6, 7, 6, 3), f = c(2, 3, 4,
2, 2, 7, 5, 2)), .Names = c("a", "b", "c", "d", "e", "f"), row.names = c(NA,
8L), class = "data.frame")
a b c d e f
1 1 1 6 6 1 2
2 3 3 3 2 2 3
3 4 4 6 4 4 4
4 6 2 5 5 5 2
5 3 6 3 3 6 2
6 2 7 6 7 7 7
7 5 2 5 2 6 5
8 1 6 3 6 3 2
Saya berharap dapat menemukan solusi untuk masalah saya menggunakan paket dplyr (dan ya saya tahu ini bukan kode yang seharusnya berfungsi, tapi saya rasa ini menjelaskan tujuannya) untuk membuat kolom baru g:
library(dplyr)
df <- mutate(df,
if (a == 2 | a == 5 | a == 7 | (a == 1 & b == 4)){g = 2},
if (a == 0 | a == 1 | a == 4 | a == 3 | c == 4) {g = 3})
Hasil dari kode yang saya cari harus memiliki hasil ini dalam contoh khusus ini:
a b c d e f g
1 1 1 6 6 1 2 3
2 3 3 3 2 2 3 3
3 4 4 6 4 4 4 3
4 6 2 5 5 5 2 NA
5 3 6 3 3 6 2 NA
6 2 7 6 7 7 7 2
7 5 2 5 2 6 5 2
8 1 6 3 6 3 2 3
Apakah ada yang punya ide tentang bagaimana melakukan ini di dplyr? Kerangka data ini hanyalah contoh, kerangka data yang saya tangani jauh lebih besar. Karena kecepatannya saya mencoba menggunakan dplyr, tetapi mungkin ada cara lain yang lebih baik untuk menangani masalah ini?
dplyr::case_when()
jauh lebih jelas daripadaifelse
,Jawaban:
Menggunakan
ifelse
Ditambahkan - if_else: Perhatikan bahwa dalam dplyr 0.5 ada
if_else
fungsi yang didefinisikan sehingga alternatifnya adalah untuk menggantikannyaifelse
denganif_else
; Namun, perhatikan bahwa karenaif_else
lebih ketat daripadaifelse
(kedua kaki kondisi harus memiliki jenis yang sama) sehinggaNA
dalam hal ini harus digantiNA_real_
.Ditambahkan - case_when Karena pertanyaan ini diposting dplyr telah ditambahkan
case_when
sehingga alternatif lain adalah:Ditambahkan - aritmatika / na_if Jika nilainya numerik dan kondisi (kecuali untuk nilai default NA di akhir) adalah saling eksklusif, seperti halnya dalam pertanyaan, maka kita dapat menggunakan ekspresi aritmatika sedemikian sehingga setiap istilah dikalikan oleh hasil yang diinginkan menggunakan
na_if
di akhir untuk mengganti 0 dengan NA.sumber
NA
, saya ingin baris yang tidak memenuhi persyaratan tetap sama?mutate(g = ifelse(condition1, 2, ifelse(condition2, 3, g))
Karena Anda meminta cara lain yang lebih baik untuk menangani masalah, berikut cara lain menggunakan
data.table
:Perhatikan urutan pernyataan bersyarat dibalik untuk mendapatkan yang
g
benar. Tidak ada salinang
buatan, bahkan selama penugasan kedua - diganti di tempat .Pada data yang lebih besar ini akan memiliki kinerja yang lebih baik daripada menggunakan bersarang
if-else
, karena dapat mengevaluasi kasus 'ya' dan 'tidak' , dan bersarang dapat menjadi lebih sulit untuk membaca / memelihara IMHO.Berikut adalah patokan pada data yang relatif lebih besar:
Tidak yakin apakah ini alternatif yang Anda minta, tapi saya harap ini membantu.
sumber
DT_fun
memodifikasi inputnya di tempat, patokan mungkin tidak cukup adil - selain tidak menerima input yang sama dari maju iterasi ke-2 (yang mungkin mempengaruhi waktu karenaDT$g
sudah dialokasikan?), Hasilnya juga menyebar kembali keans1
dan karena itu mungkin ( jika optimizer dianggapnya R perlu? Tidak yakin tentang ini ...) menghindari lain salinan yangDPLYR_fun
danBASE_fun
kebutuhan untuk membuat?data.table
solusi ini hebat, dan saya gunakan didata.table
mana pun saya benar-benar membutuhkan kecepatan untuk operasi di atas meja & saya tidak ingin pergi jauh ke C ++. Meskipun demikian, memang diperlukan kehati-hatian untuk modifikasi!dplyr sekarang memiliki fungsi
case_when
yang menawarkan jika vektor. Sintaksnya sedikit aneh dibandingkanmosaic:::derivedFactor
karena Anda tidak dapat mengakses variabel dengan cara standar dplyr, dan perlu mendeklarasikan mode NA, tetapi ini jauh lebih cepat daripadamosaic:::derivedFactor
.EDIT: Jika Anda menggunakan
dplyr::case_when()
dari sebelum versi 0.7.0 dari paket, maka Anda harus mendahului nama variabel dengan '.$
' (misalnya menulis.$a == 1
di dalamcase_when
).Benchmark : Untuk tolok ukur (menggunakan kembali fungsi dari pos Arun) dan mengurangi ukuran sampel:
Ini memberi:
sumber
case_when
bisa juga ditulis sebagai:df %>% mutate(g = with(., case_when(a %in% c(2,5,7) | (a==1 & b==4) ~ 2L, a %in% c(0,1,3,4) | c==4 ~ 3L, TRUE ~ NA_integer_)))
.$
lagi dalam versi baru dplyrThe
derivedFactor
fungsi darimosaic
paket tampaknya dirancang untuk menangani hal ini. Dengan menggunakan contoh ini, akan terlihat seperti:(Jika Anda ingin hasilnya menjadi numerik bukan faktor, Anda bisa membungkus
derivedFactor
dalamas.numeric
panggilan.)derivedFactor
dapat digunakan untuk sejumlah persyaratan yang sewenang-wenang juga.sumber
.asFactor = F
opsi atau dengan menggunakan fungsi (serupa)derivedVariable
dalam paket yang sama.recode
dari dplyr 0,5 akan melakukan ini. Saya belum menyelidiki hal itu. Lihat blog.rstudio.org/2016/06/27/dplyr-0-5-0case_when
sekarang merupakan implementasi kasus SQL-style yang cukup bersih ketika:Menggunakan dplyr 0.7.4
Manual: http://dplyr.tidyverse.org/reference/case_when.html
sumber