2016-07-18 19 views
2

Ich habe eine Funktion, die den ersten Tag der Woche für ein bestimmtes Datum finden. In diesem speziellen Problem beginnen die Wochen am Donnerstag.Stop Map von der Umwandlung von Daten in Ziffern

Die Funktion funktioniert gut für einzelne Daten.

week_commencing <- function(date) { 
    weekday <- lubridate::wday(date) 
    if (weekday >= 5) { 
    return(date - lubridate::days(weekday) + lubridate::days(5)) 
    } else { 
    return(date - lubridate::days(weekday) - lubridate::days(2)) 
    } 
} 

Nun würde Ich mag es, ein Rohr mit dplyr verwenden. Also habe ich es geändert, um Spalten mit Map zu akzeptieren.

week_commencing <- function(dates) { 
    Map(function(date) { 
    weekday <- lubridate::wday(date) 
    if (weekday >= 5) { 
     return(date - lubridate::days(weekday) + lubridate::days(5)) 
    } else { 
     return(date - lubridate::days(weekday) - lubridate::days(2)) 
    } 
    },dates) 
} 

Ich denke, die Funktion arbeitet, sondern auch einig seltsamen Zwang zu den Terminen anwenden, weil ich mit stellige Daten enden.

> test <- data.frame(datetime=seq.Date(as.Date("2016-06-01"),as.Date("2016-06-10"), by='day')) 
> test 
    datetime 
1 2016-06-01 
2 2016-06-02 
3 2016-06-03 
4 2016-06-04 
5 2016-06-05 
6 2016-06-06 
7 2016-06-07 
8 2016-06-08 
9 2016-06-09 
10 2016-06-10 

> test %>% mutate(datetime=week_commencing(datetime)) 
    datetime 
1  16947 
2  16954 
3  16954 
4  16954 
5  16954 
6  16954 
7  16954 
8  16954 
9  16961 
10 16961 

Irgendwelche Ideen, wie man mit normalem Datumobjekt endet? Wird die Karte immer unter Zwang angewendet?

Antwort

3

Ich weiß nicht, warum das class Attribut hier fallengelassen wird (das gleiche passiert, wenn Sie andere * apply Funktionen verwenden). - Die Frage, tief unten scheint zu sein, dass unlist Klassen fällt:

> unlist(list(structure(1, class = 'foo'))) 
[1] 1 

Aber die Lösung ist einfach genug: die Klasse am Ende gesetzt.

Außerdem würde ich vorschlagen, nicht Map (die eine list zurückgibt), sondern vapply. Dann sind wir nach links mit:

week_commencing <- function(dates) { 
    wc <- function(date) { 
    weekday <- lubridate::wday(date) 
    if (weekday >= 5) { 
     return(date - lubridate::days(weekday) + lubridate::days(5)) 
    } else { 
     return(date - lubridate::days(weekday) - lubridate::days(2)) 
    } 
    } 

    structure(vapply(dates, wc, numeric(1)), class = 'Date') 
} 

Sie auch Vectorize auf die Funktion verwenden können, aber das beseitigt auch die class Attribut.

+0

Vielen Dank! Das funktioniert wie ein Zauber! Ich habe noch nie eine solche Syntax gesehen 'class <-' (16947, 'Date') ... Hat es einen Namen? Vor allem der 'class <-' Teil, damit ich darüber lesen kann? – xav

+2

Als Alternative zu '\' class <- \ '(...)' kann man auch 'structure (vapply (dates, wc, numeric (1)), class =" Date ")' 'verwenden. – nrussell

+0

@xav Es ruft einfach die [Ersatzfunktion] (http://stackoverflow.com/q/11563154/1968) von 'class'. Ich verwende diese Syntax, um zu vermeiden, dass eine ansonsten nutzlose Variable den Wert enthält (die eine Sache, die ich in der Erklärung der verknüpften Antwort ändern möchte, ist, dass Sie keine Zeichenfolgen für Funktionsnamen verwenden sollten, es ist unsinnig; [stattdessen Backtick-Zitat verwenden] (http://stackoverflow.com/a/36229703/1968), wie in meiner Antwort). Ich vergesse jedoch immer, dass ich einfach 'structure' verwenden kann, um das gleiche hier zu tun (obwohl ich es in meiner eigenen Antwort verwendet habe), wie nrussell sagte. –

2

Oder könnten Sie es in der dplyr Familie halten:

week_commencing <- function(date) { 
    weekday <- lubridate::wday(date) 
    dplyr::if_else(weekday >= 5, 
       date - lubridate::days(weekday) + lubridate::days(5), 
       date - lubridate::days(weekday) - lubridate::days(2)) 
} 
+0

Obwohl ich die Flexibilität von Konrads Antwort bevorzuge, muss ich sie im Moment verwenden, da sie in nur wenigen Sekunden auf meinem 900k Zeilen-Datensatz ausgeführt wird, während die andere Lösung nach 1h noch verarbeitet wird. Danke vielmals! – xav