Ich benutze die Funktion ifelse()
, um einen Datumsvektor zu manipulieren. Ich erwartete, dass das Ergebnis von Klasse sein würde Date
, und war überrascht, numeric
stattdessen einen Vektor zu erhalten. Hier ist ein Beispiel:
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)
Dies ist besonders überraschend, da die Ausführung der Operation über den gesamten Vektor ein Date
Objekt zurückgibt .
dates <- as.Date(c('2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04','2011-01-05'))
dates <- dates - 1
str(dates)
Sollte ich eine andere Funktion verwenden, um Date
Vektoren zu bearbeiten? Wenn ja, welche Funktion? Wenn nicht, wie erzwinge ich ifelse
die Rückgabe eines Vektors des gleichen Typs wie die Eingabe?
Die Hilfeseite für ifelse
zeigt an, dass dies eine Funktion ist, kein Fehler, aber ich habe immer noch Schwierigkeiten, eine Erklärung für das zu finden, was ich als überraschendes Verhalten empfunden habe.
r
datetime
if-statement
Zach
quelle
quelle
if_else()
Das dplyr-Paket enthält jetzt eine Funktion, dieifelse
bei Beibehaltung der korrekten Klassen von Datumsobjekten ersetzt werden kann. Sie wird unten als aktuelle Antwort aufgeführt. Ich mache hier darauf aufmerksam, da es dieses Problem löst, indem es eine Funktion bereitstellt, die in einem CRAN-Paket getestet und dokumentiert ist, im Gegensatz zu vielen anderen Antworten, die (ab diesem Kommentar) davor eingestuft wurden.Antworten:
Sie können
data.table::fifelse
(data.table >= 1.12.3
) oder verwendendplyr::if_else
.data.table::fifelse
dplyr::if_else
Aus
dplyr 0.5.0
Versionshinweisen :quelle
true
's undfalse
' s Ebenen waren.if_else
be NA zu haben? Ich habe versucht, die logischenNA_
Optionen und nichts bleibt hängen und ich glaube nicht, dass es einenNA_double_
NA
inas.Date
.NA_real_
@roarkz. und @Henrik, dein Kommentar hier hat mein Problem gelöst.Es bezieht sich auf den dokumentierten Wert von
ifelse
:Auf die Implikationen
ifelse
reduziert, verlieren Faktoren ihre Level und Daten verlieren ihre Klasse und nur ihr Modus ("numerisch") wird wiederhergestellt. Versuchen Sie stattdessen Folgendes:Sie könnten ein
safe.ifelse
:Ein späterer Hinweis: Ich sehe, dass Hadley einen
if_else
in den magrittr / dplyr / tidyr-Komplex von Datenformungspaketen eingebaut hat.quelle
safe.ifelse <- function(cond, yes, no) structure(ifelse(cond, yes, no), class = class(yes))
ifelse()
nicht "sicher" ist .DWins Erklärung ist genau richtig. Ich spielte eine Weile damit herum, bevor mir klar wurde, dass ich die Klasse nach der ifelse-Aussage einfach zwingen konnte:
Anfangs fühlte sich das für mich ein wenig "hackisch" an. Aber jetzt sehe ich es nur als einen kleinen Preis für die Performance-Renditen, die ich von ifelse () bekomme. Außerdem ist es immer noch viel prägnanter als eine Schleife.
quelle
for
Anweisung weist der Wert der Elemente inVECTOR
zuNAME
, nicht aber ihre Klasse .Die vorgeschlagene Methode funktioniert nicht mit Faktorspalten. Ich möchte diese Verbesserung vorschlagen:
Übrigens: ifelse saugt ... mit großer Kraft geht eine große Verantwortung einher, dh Typkonvertierungen von 1x1-Matrizen und / oder Zahlen [wenn sie zum Beispiel hinzugefügt werden sollten] sind für mich in Ordnung, aber diese Typkonvertierung in ifelse ist eindeutig unerwünscht. Ich bin jetzt mehrmals auf den gleichen 'Bug' von ifelse gestoßen und er stiehlt mir immer wieder meine Zeit :-(
FW
quelle
yes
und sindno
und dass Sie zuerst überprüfen würden, ob sie beide Faktoren sind. Sie müssten wahrscheinlich in Charakter konvertieren und sich dann mit den "gewerkschaftlich organisierten" Ebenen neu bündeln.Der Grund, warum dies nicht funktioniert, liegt darin, dass die Funktion ifelse () die Werte in Faktoren konvertiert. Eine gute Problemumgehung wäre, es vor der Auswertung in Zeichen umzuwandeln.
Dies würde keine Bibliothek außer Basis R erfordern.
quelle
Die Antwort von @ fabian-werner ist großartig, aber Objekte können mehrere Klassen haben, und "Faktor" muss nicht unbedingt der erste sein, der von zurückgegeben wird. Daher empfehle
class(yes)
ich diese kleine Änderung, um alle Klassenattribute zu überprüfen:Ich habe auch eine Anfrage an das R-Entwicklungsteam gesendet, um eine dokumentierte Option hinzuzufügen, mit der base :: ifelse () Attribute beibehalten soll, basierend auf der Benutzerauswahl, welche Attribute beibehalten werden sollen. Die Anfrage ist hier: https://bugs.r-project.org/bugzilla/show_bug.cgi?id=16609 - Sie wurde bereits als "WONTFIX" gekennzeichnet, da sie immer so war, wie sie jetzt ist. Aber ich habe ein nachfolgendes Argument geliefert, warum eine einfache Hinzufügung viele Kopfschmerzen von R-Benutzern ersparen könnte. Vielleicht ermutigt Ihr "+1" in diesem Bug-Thread das R Core-Team, einen zweiten Blick darauf zu werfen.
BEARBEITEN: Hier ist eine bessere Version, mit der der Benutzer angeben kann, welche Attribute beibehalten werden sollen, entweder "cond" (Standardverhalten von ifelse ()), "yes", das Verhalten gemäß dem obigen Code oder "no" für Fälle, in denen die Attribute des "no" -Werts sind besser:
quelle
inherits(y, "factor")
könnte "korrekter" sein als"factor" %in% class.y
inherits
könnte am besten sein.