J'utilise la fonction ifelse()
pour manipuler un vecteur de date. Je m'attendais à ce que le résultat soit de classe Date
, et j'ai été surpris d'obtenir un numeric
vecteur à la place. Voici un exemple:
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)
Ceci est particulièrement surprenant car l'exécution de l'opération sur tout le vecteur renvoie un Date
objet.
dates <- as.Date(c('2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04','2011-01-05'))
dates <- dates - 1
str(dates)
Dois-je utiliser une autre fonction pour opérer sur des Date
vecteurs? Si oui, quelle fonction? Sinon, comment forcer ifelse
à renvoyer un vecteur du même type que l'entrée?
La page d'aide pour ifelse
indique qu'il s'agit d'une fonctionnalité, pas d'un bogue, mais j'ai encore du mal à trouver une explication à ce que j'ai trouvé être un comportement surprenant.
r
datetime
if-statement
Zach
la source
la source
if_else()
dans le package dplyr qui peut remplacerifelse
tout en conservant les classes correctes d'objets Date - elle est publiée ci-dessous en tant que réponse récente. J'attire l'attention sur cela ici car il résout ce problème en fournissant une fonction qui est testée unitaire et documentée dans un package CRAN, contrairement à de nombreuses autres réponses qui (à partir de ce commentaire) ont été classées avant elle.Réponses:
Vous pouvez utiliser
data.table::fifelse
(data.table >= 1.12.3
) oudplyr::if_else
.data.table::fifelse
dplyr::if_else
À partir des
dplyr 0.5.0
notes de version :la source
true
's etfalse
' s.if_else
be NA? J'ai essayé lesNA_
options logiques et rien ne colle et je ne crois pas qu'il y ait unNA_double_
NA
dansas.Date
.NA_real_
, @roarkz. et @Henrik, votre commentaire ici a résolu mon problème.Il se rapporte à la valeur documentée de
ifelse
:Réduit à ses implications,
ifelse
fait perdre aux facteurs leur niveau et les dates perdent leur classe et seul leur mode ("numérique") est restauré. Essayez plutôt ceci:Vous pouvez créer un
safe.ifelse
:Une note plus tard: je vois que Hadley a intégré un
if_else
dans le complexe magrittr / dplyr / tidyr de paquets de mise en forme de données.la source
safe.ifelse <- function(cond, yes, no) structure(ifelse(cond, yes, no), class = class(yes))
ifelse()
n'est toujours pas «sûr» .L'explication de DWin est parfaite. J'ai tripoté et combattu avec cela pendant un moment avant de réaliser que je pouvais simplement forcer la classe après l'instruction ifelse:
Au début, cela me semblait un peu "hackish". Mais maintenant, je pense simplement à cela comme un petit prix à payer pour les rendements de performance que j'obtiens d'ifelse (). De plus, c'est encore beaucoup plus concis qu'une boucle.
la source
for
déclaration de R attribue la valeur des élémentsVECTOR
àNAME
, mais pas à leur classe .La méthode suggérée ne fonctionne pas avec les colonnes de facteurs. J'aimerais suggérer cette amélioration:
Au fait: ifelse craint ... avec une grande puissance vient une grande responsabilité, c'est-à-dire que les conversions de type de matrices 1x1 et / ou numériques [quand il faut les ajouter par exemple] me convient mais cette conversion de type dans ifelse est clairement indésirable. Je suis tombé sur le même `` bug '' d'ifelse plusieurs fois maintenant et cela continue de me voler mon temps :-(
FW
la source
yes
etno
et que vous vérifieriez d'abord qu'il s'agissait des deux facteurs. Vous auriez probablement besoin de convertir en caractère et ensuite de réassembler avec les niveaux "syndiqués".La raison pour laquelle cela ne fonctionnera pas est que la fonction ifelse () convertit les valeurs en facteurs. Une bonne solution de contournement serait de le convertir en caractères avant de l'évaluer.
Cela ne nécessiterait aucune bibliothèque en dehors de la base R.
la source
La réponse fournie par @ fabian-werner est excellente, mais les objets peuvent avoir plusieurs classes, et "factor" n'est pas forcément le premier retourné par
class(yes)
, donc je suggère cette petite modification pour vérifier tous les attributs de classe:J'ai également soumis une demande à l'équipe de développement R pour ajouter une option documentée pour que base :: ifelse () conserve les attributs en fonction de la sélection par l'utilisateur des attributs à préserver. La requête est ici: https://bugs.r-project.org/bugzilla/show_bug.cgi?id=16609 - Elle a déjà été signalée comme "WONTFIX" au motif que cela a toujours été comme il est maintenant, mais j'ai fourni un argument complémentaire sur les raisons pour lesquelles un simple ajout pourrait sauver beaucoup de maux de tête aux utilisateurs de R. Peut-être que votre "+1" dans ce fil de bug encouragera l'équipe R Core à jeter un second regard.
EDIT: Voici une meilleure version qui permet à l'utilisateur de spécifier les attributs à conserver, soit "cond" (comportement ifelse () par défaut), "yes", le comportement selon le code ci-dessus, ou "no", pour les cas où le les attributs de la valeur "non" sont meilleurs:
la source
inherits(y, "factor")
pourrait être "plus correct" que"factor" %in% class.y
inherits
pourrait être le meilleur.