Jawaban yang diberikan oleh @ fabian-werner sangat bagus, tetapi objek dapat memiliki beberapa kelas, dan "faktor" mungkin belum tentu yang pertama dikembalikan oleh class(yes)
, jadi saya sarankan modifikasi kecil ini untuk memeriksa semua atribut kelas:
safe.ifelse <- function(cond, yes, no) {
class.y <- class(yes)
if ("factor" %in% class.y) { # Note the small condition change here
levels.y = levels(yes)
}
X <- ifelse(cond,yes,no)
if ("factor" %in% class.y) { # Note the small condition change here
X = as.factor(X)
levels(X) = levels.y
} else {
class(X) <- class.y
}
return(X)
}
Saya juga telah mengajukan permintaan dengan tim Pengembangan R untuk menambahkan opsi yang didokumentasikan untuk memiliki basis :: ifelse () melestarikan atribut berdasarkan pilihan pengguna yang atributnya akan dipertahankan. Permintaannya ada di sini: https://bugs.r-project.org/bugzilla/show_bug.cgi?id=16609 - Sudah ditandai sebagai "WONTFIX" dengan alasan selalu seperti sekarang, tapi saya telah memberikan argumen tindak lanjut tentang mengapa penambahan sederhana mungkin menghemat banyak sakit kepala pengguna R. Mungkin "+1" Anda di utas bug itu akan mendorong tim R Core untuk melihat kembali.
EDIT: Berikut adalah versi yang lebih baik yang memungkinkan pengguna untuk menentukan atribut mana yang harus dipertahankan, baik perilaku "cond" (perilaku ifelse () default), "ya", perilaku sesuai kode di atas, atau "tidak", untuk kasus di mana atribut nilai "tidak" lebih baik:
safe_ifelse <- function(cond, yes, no, preserved_attributes = "yes") {
# Capture the user's choice for which attributes to preserve in return value
preserved <- switch(EXPR = preserved_attributes, "cond" = cond,
"yes" = yes,
"no" = no);
# Preserve the desired values and check if object is a factor
preserved_class <- class(preserved);
preserved_levels <- levels(preserved);
preserved_is_factor <- "factor" %in% preserved_class;
# We have to use base::ifelse() for its vectorized properties
# If we do our own if() {} else {}, then it will only work on first variable in a list
return_obj <- ifelse(cond, yes, no);
# If the object whose attributes we want to retain is a factor
# Typecast the return object as.factor()
# Set its levels()
# Then check to see if it's also one or more classes in addition to "factor"
# If so, set the classes, which will preserve "factor" too
if (preserved_is_factor) {
return_obj <- as.factor(return_obj);
levels(return_obj) <- preserved_levels;
if (length(preserved_class) > 1) {
class(return_obj) <- preserved_class;
}
}
# In all cases we want to preserve the class of the chosen object, so set it here
else {
class(return_obj) <- preserved_class;
}
return(return_obj);
} # End safe_ifelse function
if_else()
dalam paket dplyr yang bisa menggantikanifelse
sementara mempertahankan kelas objek Date yang benar - itu diposting di bawah ini sebagai jawaban baru-baru ini. Saya membawa perhatian ke sini karena ini memecahkan masalah ini dengan menyediakan fungsi yang diuji unit dan didokumentasikan dalam paket CRAN, tidak seperti banyak jawaban lain yang (pada komentar ini) berada di peringkat di depannya.