Estoy usando la función ifelse()
para manipular un vector de fecha. Esperaba que el resultado fuera de clase Date
, y me sorprendió obtener un numeric
vector en su lugar. Aquí hay un ejemplo:
dates <- as.Date(c('2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04', '2011-01-05'))
dates <- ifelse(dates == '2011-01-01', dates - 1, dates)
str(dates)
Esto es especialmente sorprendente porque realizar la operación en todo el vector devuelve un Date
objeto.
dates <- as.Date(c('2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04','2011-01-05'))
dates <- dates - 1
str(dates)
¿Debo estar usando alguna otra función para operar en Date
vectores? Si es así, ¿qué función? Si no es así, ¿cómo fuerzo ifelse
a devolver un vector del mismo tipo que la entrada?
La página de ayuda ifelse
indica que esta es una característica, no un error, pero todavía estoy luchando por encontrar una explicación de lo que me pareció un comportamiento sorprendente.
r
datetime
if-statement
Zach
fuente
fuente
if_else()
en el paquete dplyr que puede sustituir a laifelse
vez que conserva las clases correctas de objetos Date: se publica a continuación como una respuesta reciente. Estoy llamando la atención aquí, ya que resuelve este problema al proporcionar una función que está probada y documentada en un paquete CRAN, a diferencia de muchas otras respuestas que (a partir de este comentario) se clasificaron por delante.Respuestas:
Puede usar
data.table::fifelse
(data.table >= 1.12.3
) odplyr::if_else
.data.table::fifelse
dplyr::if_else
De las
dplyr 0.5.0
notas de la versión :fuente
true
'syfalse
'.if_else
ser NA? He intentado lasNA_
opciones lógicas y no hay nada pegado y no creo que haya unNA_double_
NA
enas.Date
.NA_real_
, @roarkz. y @Henrik, tu comentario aquí resolvió mi problema.Se relaciona con el valor documentado de
ifelse
:Reducido a sus implicaciones, los
ifelse
factores pierden sus niveles y las fechas pierden su clase y solo se restaura su modo ("numérico"). Intenta esto en su lugar:Podrías crear un
safe.ifelse
:Una nota posterior: veo que Hadley ha incorporado
if_else
el complejo magrittr / dplyr / tidyr de paquetes de modelado de datos.fuente
safe.ifelse <- function(cond, yes, no) structure(ifelse(cond, yes, no), class = class(yes))
ifelse()
no es "seguro" .La explicación de DWin es acertada. Jugueteé y luché con esto por un tiempo antes de darme cuenta de que podía simplemente forzar a la clase después de la declaración ifelse:
Al principio, esto me pareció un poco "hack". Pero ahora solo lo considero un pequeño precio a pagar por los rendimientos de rendimiento que obtengo de ifelse (). Además, sigue siendo mucho más conciso que un bucle.
fuente
for
declaración de R asigna el valor de los elementosVECTOR
aNAME
, pero no su clase .El método sugerido no funciona con columnas de factores. Me gustaría sugerir esta mejora:
Por cierto: ifelse apesta ... con gran poder conlleva una gran responsabilidad, es decir, las conversiones de tipo de matrices 1x1 y / o numéricos [cuando deberían agregarse, por ejemplo] está bien para mí, pero esta conversión de tipo en ifelse es claramente no deseada. Me topé con el mismo 'error' de ifelse varias veces ahora y sigue robando mi tiempo :-(
FW
fuente
yes
yno
y que usted primero comprobar para ver que eran ambos factores. Probablemente necesite convertir a personaje y luego volver a combinar con los niveles "sindicalizados".La razón por la cual esto no funcionará es porque, la función ifelse () convierte los valores en factores. Una buena solución sería convertirlo en caracteres antes de evaluarlo.
Esto no requeriría ninguna biblioteca aparte de la base R.
fuente
La respuesta proporcionada por @ fabian-werner es excelente, pero los objetos pueden tener varias clases, y "factor" puede no ser necesariamente el primero que devuelva
class(yes)
, por lo que sugiero esta pequeña modificación para verificar todos los atributos de clase:También he enviado una solicitud con el equipo de Desarrollo de R para agregar una opción documentada para tener base :: ifelse () preservar atributos en función de la selección del usuario de qué atributos preservar. La solicitud está aquí: https://bugs.r-project.org/bugzilla/show_bug.cgi?id=16609 - Ya se ha marcado como "WONTFIX" porque siempre ha sido así, pero he proporcionado un argumento de seguimiento sobre por qué una simple adición podría ahorrarle muchos dolores de cabeza a los usuarios de R. Quizás su "+1" en ese hilo de errores alentará al equipo de R Core a echar un segundo vistazo.
EDITAR: Aquí hay una versión mejor que permite al usuario especificar qué atributos conservar, ya sea "cond" (comportamiento predeterminado ifelse ()), "sí", el comportamiento según el código anterior o "no", para los casos en que los atributos del valor "no" son mejores:
fuente
inherits(y, "factor")
podría ser "más correcto" que"factor" %in% class.y
inherits
podría ser el mejor