Saya tahu ada beberapa pertanyaan serupa di sekitar sini, tetapi tidak satu pun dari mereka yang membahas masalah yang sebenarnya saya alami.
set.seed(4)
df = data.frame(
Key = c("A", "B", "A", "D", "A"),
Val1 = rnorm(5),
Val2 = runif(5),
Val3 = 1:5
)
Saya ingin memusatkan nilai dari nilai kolom untuk baris di mana Kunci == "A" Nama kolom direferensikan melalui grep
:
cols = grep("Val", names(df), value = TRUE)
Biasanya untuk mencapai apa yang saya inginkan dalam hal ini saya akan menggunakan data.table
seperti ini:
library(data.table)
df = as.data.table(df)
df[Key == "A", (cols) := 0]
Dan output yang diinginkan adalah seperti ini:
Key Val1 Val2 Val3
1 A 0.000000 0.00000000 0
2 B -1.383814 0.55925762 2
3 A 0.000000 0.00000000 0
4 D 1.437151 0.05632773 4
5 A 0.000000 0.00000000 0
Namun kali ini saya perlu menggunakan dplyr
karena saya sedang mengerjakan proyek tim di mana semua orang menggunakannya. Data yang baru saja saya berikan bersifat ilustratif dan data saya yang sebenarnya adalah> 5m baris dengan 16 kolom nilai yang akan diperbarui. Satu-satunya solusi yang bisa saya lakukan adalah menggunakan mutate_at
seperti ini:
df %>% mutate_at(.vars = vars(cols), .funs = function(x) ifelse(df$Key == "A", 0, x))
Namun, ini tampaknya sangat lambat pada data saya yang sebenarnya. Saya berharap menemukan solusi yang lebih elegan dan, yang lebih penting, lebih cepat.
Saya telah mencoba banyak kombinasi menggunakan map
, menghapus tanda kutip menggunakan !!
, menggunakan get
dan :=
(yang mengganggu bisa tertutup oleh :=
data.table) dll, tapi saya pikir pemahaman saya tentang bagaimana pekerjaan ini tidak cukup dalam untuk membangun solusi yang valid.
sumber
Jawaban:
Dengan perintah dplyr ini,
Anda sebenarnya mengevaluasi pernyataan df $ Key == "A", n kali, di mana n = jumlah kolom yang Anda miliki.
Salah satu penyelesaiannya adalah menentukan terlebih dahulu baris yang ingin Anda ubah:
Cara yang lebih bersih dan lebih baik, ditunjukkan dengan benar oleh @IceCreamToucan (lihat komentar di bawah), adalah dengan menggunakan fungsi ganti, sambil memberikan parameter tambahan:
Kita dapat menguji semua pendekatan ini, dan saya pikir dplyr dan data.table sebanding.
sumber
df %>% mutate_at(vars(contains('Val')), replace, df$Key == 'A', 0)
replace
metode ini sedikit lebih lambat daripadaidx
metode awal Anda .dplyr::if_else()
lebih cepat dari pangkalanifelse()
.