คำตอบที่ได้รับจาก @ fabian-werner นั้นยอดเยี่ยม แต่วัตถุสามารถมีหลายคลาสได้และ "factor" อาจไม่จำเป็นต้องเป็นคำตอบแรกที่ส่งกลับมาclass(yes)
ดังนั้นฉันขอแนะนำการปรับเปลี่ยนขนาดเล็กเพื่อตรวจสอบแอตทริบิวต์ของคลาสทั้งหมด:
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)
}
ฉันได้ส่งคำขอไปยังทีม R Development เพื่อเพิ่มตัวเลือกที่เป็นเอกสารเพื่อให้ base :: ifelse () รักษาแอตทริบิวต์ตามการเลือกของผู้ใช้ที่ต้องการเก็บรักษาแอตทริบิวต์ คำขออยู่ที่นี่: https://bugs.r-project.org/bugzilla/show_bug.cgi?id=16609 - ได้รับการตั้งค่าสถานะเป็น "WONTFIX" โดยอ้างว่าเป็นวิธีที่เป็นอยู่ตอนนี้ แต่ฉันได้ให้เหตุผลในการติดตามว่าทำไมการเพิ่มอย่างง่ายอาจช่วยให้ผู้ใช้ปวดหัวจำนวนมาก บางที "+1" ของคุณในเธรดข้อผิดพลาดนั้นอาจกระตุ้นให้ทีม R Core พิจารณาอีกครั้ง
แก้ไข: นี่เป็นรุ่นที่ดีกว่าที่อนุญาตให้ผู้ใช้ระบุว่าจะเก็บรักษาแอตทริบิวต์ใดไว้ไม่ว่าจะเป็น "cond" (พฤติกรรมเริ่มต้น ifelse ()), "ใช่" พฤติกรรมตามรหัสด้านบนหรือ "ไม่" สำหรับกรณีที่ คุณลักษณะของค่า "ไม่" ดีกว่า:
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()
ในแพ็คเกจ dplyr ที่สามารถใช้แทนifelse
ในขณะที่รักษาคลาสของวัตถุ Date ได้อย่างถูกต้องซึ่งโพสต์ด้านล่างนี้เป็นคำตอบล่าสุด ฉันให้ความสนใจกับมันที่นี่เพราะมันแก้ปัญหานี้ได้โดยจัดให้มีฟังก์ชั่นที่ผ่านการทดสอบหน่วยและจัดทำเอกสารในแพ็คเกจ CRAN ซึ่งแตกต่างจากคำตอบอื่น ๆ อีกมากมายที่อยู่ในอันดับต้น ๆ