Używam funkcji ifelse()
do manipulowania wektorem daty. Spodziewałem się, że wynik będzie klasowy Date
i byłem zaskoczony, że numeric
zamiast tego otrzymałem wektor. Oto przykład:
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)
Jest to szczególnie zaskakujące, ponieważ wykonanie operacji na całym wektorze zwraca Date
obiekt.
dates <- as.Date(c('2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04','2011-01-05'))
dates <- dates - 1
str(dates)
Czy powinienem używać innej funkcji do operowania na Date
wektorach? Jeśli tak, jaka funkcja? Jeśli nie, jak zmusić ifelse
do zwrócenia wektora tego samego typu co dane wejściowe?
Strona pomocy dla ifelse
wskazuje, że jest to funkcja, a nie błąd, ale wciąż staram się znaleźć wyjaśnienie tego, co uważam za zaskakujące zachowanie.
r
datetime
if-statement
Zach
źródło
źródło
if_else()
pakiecie dplyr jest teraz funkcja , która może zastąpićifelse
, zachowując poprawne klasy obiektów Date - została opublikowana poniżej jako ostatnia odpowiedź. Zwracam na to uwagę, ponieważ rozwiązuje ten problem, udostępniając funkcję, która jest przetestowana jednostkowo i udokumentowana w pakiecie CRAN, w przeciwieństwie do wielu innych odpowiedzi, które (jak w tym komentarzu) były przed nim.Odpowiedzi:
Możesz użyć
data.table::fifelse
(data.table >= 1.12.3
) lubdplyr::if_else
.data.table::fifelse
dplyr::if_else
Z
dplyr 0.5.0
informacji o wersji :źródło
true
's ifalse
' s.if_else
be NA?NA_
NA_double_
NA
was.Date
.NA_real_
, @roarkz. i @Henrik, twój komentarz tutaj rozwiązał mój problem.To dotyczy udokumentowanego Stosunek z
ifelse
:Sprowadzając się do jego konsekwencji,
ifelse
powoduje , że czynniki tracą swoje poziomy, a daty tracą swoją klasę i przywracany jest tylko ich tryb („numeryczny”). Spróbuj tego zamiast tego:Możesz stworzyć
safe.ifelse
:Późniejsza uwaga: widzę, że Hadley wbudował
if_else
w kompleks magrittr / dplyr / tidyr pakietów kształtujących dane.źródło
safe.ifelse <- function(cond, yes, no) structure(ifelse(cond, yes, no), class = class(yes))
ifelse()
nie jest „bezpieczny” .Wyjaśnienie DWina jest trafne. Bawiłem się i walczyłem z tym przez chwilę, zanim zdałem sobie sprawę, że mogę po prostu zmusić klasę po stwierdzeniu ifelse:
Na początku wydawało mi się to trochę „hakerskie”. Ale teraz myślę o tym jako o niewielkiej cenie za zwroty wydajności, które otrzymuję od ifelse (). Poza tym jest o wiele bardziej zwięzły niż pętla.
źródło
for
cesjonariusze deklaracji wartości elementów wVECTOR
celuNAME
, ale nie ich klasa .Sugerowana metoda nie działa z kolumnami współczynników. Chciałbym zasugerować tę poprawę:
Przy okazji: ifelse jest do niczego ... z wielką mocą wiąże się wielka odpowiedzialność, tzn. Konwersja typów macierzy 1x1 i / lub liczb [kiedy należy je na przykład dodać] jest dla mnie w porządku, ale tego typu konwersja w ifelse jest wyraźnie niepożądana. Kilka razy wpadłem na ten sam `` błąd '' ifelse i po prostu kradnie mój czas :-(
FW
źródło
yes
ino
i że najpierw sprawdzisz, czy są to oba czynniki. Prawdopodobnie będziesz musiał przekonwertować na znak, a następnie ponownie połączyć z poziomami „uzwiązkowionymi”.Powodem, dla którego to nie zadziała, jest to, że funkcja ifelse () konwertuje wartości na czynniki. Dobrym obejściem byłoby przekonwertowanie go na znaki przed oceną.
Nie wymagałoby to żadnej biblioteki poza podstawowym R.
źródło
Odpowiedź udzielona przez @ fabian-werner jest świetna, ale obiekty mogą mieć wiele klas, a „czynnik” niekoniecznie musi być pierwszym zwracanym przez
class(yes)
, więc proponuję tę małą modyfikację, aby sprawdzić wszystkie atrybuty klas:Wysłałem również prośbę do zespołu R Development o dodanie udokumentowanej opcji zachowania atrybutów base :: ifelse () na podstawie wyboru przez użytkownika, które atrybuty mają być zachowane. Żądanie jest tutaj: https://bugs.r-project.org/bugzilla/show_bug.cgi?id=16609 - zostało już oflagowane jako „WONTFIX”, ponieważ zawsze było tak, jak jest teraz, ale przedstawiłem kolejny argument wyjaśniający, dlaczego proste dodanie może zaoszczędzić wielu użytkownikom języka R ból głowy. Być może twoje „+1” w tym wątku błędu zachęci zespół R Core do ponownego przyjrzenia się.
EDYCJA: Oto lepsza wersja, która pozwala użytkownikowi określić, które atrybuty mają być zachowane: „cond” (domyślne zachowanie ifelse ()), „tak”, zachowanie zgodnie z powyższym kodem lub „nie” w przypadkach, gdy atrybuty wartości „nie” są lepsze:
źródło
inherits(y, "factor")
może być „bardziej poprawne” niż"factor" %in% class.y
inherits
może być najlepszy.