@ 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开发团队提交了一个请求,要求添加一个文档化的选项,以使base :: ifelse()根据用户选择要保留的属性来保留属性。该请求位于此处:https : //bugs.r-project.org/bugzilla/show_bug.cgi?id=16609-由于它一直是现在的样子,因此已被标记为“ WONTFIX”,但是我提供了一个后续论据,说明为什么简单的添加可能会节省很多R用户的头痛。也许您在该错误线程中的“ +1”会鼓励R Core团队重新审视。
编辑:这是一个更好的版本,允许用户指定要保留的属性,即“ cond”(默认ifelse()行为),“ yes”,上述代码的行为或“ no”(对于以下情况) “否”值的属性更好:
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程序包中的功能来解决此问题,这与许多其他答案(截至本评论处)均排在其前面不同。