Pytanie w sprawie datetime, r – Czas zaokrąglania do najbliższej ćwierć godziny

24

Mam wektor wartości POSIXct i chciałbym je zaokrąglić do najbliższej ćwierć godziny. Nie obchodzi mnie dzień. Jak przekonwertować wartości na godziny i minuty?

Na przykład chciałbym tę wartość

"2012-05-30 20:41:21 UTC"

być

"20:45"

Twoja odpowiedź

7   odpowiedzi
20

Możesz użyćround. Sztuczka polega na podzieleniu przez 900 sekund (15 minut * 60 sekund) przed zaokrągleniem i pomnożeniem przez 900 później:

a <-as.POSIXlt("2012-05-30 20:41:21 UTC")
b <-as.POSIXlt(round(as.double(a)/(15*60))*(15*60),origin=(as.POSIXlt('1970-01-01')))
b
[1] "2012-05-30 20:45:00 EDT"

Aby uzyskać tylko godzinę i minutę, po prostu użyj formatu

format(b,"%H:%M")
[1] "20:45"

as.character(format(b,"%H:%M"))
[1] "20:45"
Nie sądzę, że potrzebujemy podwójnego, a pochodzenie akceptuje ciąg, więc nieco uproszczony:b <-as.POSIXlt(round(as.numeric(a)/(15*60))*(15*60),origin='1970-01-01') Mark Rajcok
3

Spróbuj tego, co łączy oba żądania i opiera się na sprawdzeniu, coround.POSIXt() itrunc.POSIXt() robić.

myRound <- function (x, convert = TRUE)  {
    x <- as.POSIXlt(x)
    mins <- x$min
    mult <- mins %/% 15
    remain <- mins %% 15
    if(remain > 7L || (remain == 7L && x$sec > 29))
        mult <- mult + 1
    if(mult > 3) {
        x$min <- 0
        x <- x + 3600
    } else {
        x$min <- 15 * mult
    }
    x <- trunc.POSIXt(x, units = "mins")
    if(convert) {
        x <- format(x, format = "%H:%M")
    }
    x
}

To daje:

> tmp <- as.POSIXct("2012-05-30 20:41:21 UTC")
> myRound(tmp)
[1] "20:45"
> myRound(tmp, convert = FALSE)
[1] "2012-05-30 20:45:00 BST"
> tmp2 <- as.POSIXct("2012-05-30 20:55:21 UTC")
> myRound(tmp2)
[1] "21:00"
> myRound(tmp2, convert = FALSE)
[1] "2012-05-30 21:00:00 BST"
wydaje się, że nie jest dobrze wektoryzowany, spróbujstructure(c(1313331280, 1313334917, 1313334917, 1313340309, 1313340309, 1313340895, 1313340895, 1313341133, 1313341218, 1313341475), class = c("POSIXct", "POSIXt"), tzone = "UTC") jangorecki
9

Stare pytanie, ale chciałbym zauważyć, żelubridate pakiet obsługuje to teraz z łatwościąfloor_date. Aby wyciąć wektor obiektów POSIXct do 15-minutowych interwałów, użyj tego.

x <- lubridate::floor_date(x, "15 minutes")

EDYCJA: Zauważony przez użytkownika @ user3297928, użyjlubridate::round_date(x, "15 minutes") zaokrąglanie do najbliższych 15 minut. Powyższe piętra to.

2

Za pomocąIDate iITime klasy oddata.table i aIPeriod klasa (właśnie opracowana) Udało mi się uzyskać bardziej skalowalne rozwiązanie.
Tylkoshhhhimhuntingrabbits iPLapointe odpowiedz na pytanie w zakresienajbliższy. xts rozwiązanie tylko rund za pomocąsufit, mójIPeriod rozwiązanie pozwala określićsufit lubpodłoga.
Aby uzyskać najwyższą wydajność, musisz przechowywać swoje daneIDate iITime klasy. Jak widać w benchmarku, jest tani w produkcjiPOSIXct zIDate/ITime/IPeriod. Poniżej benchmarku o 22M znaczniku czasu:

# install only if you don't have
install.packages(c("microbenchmarkCore","data.table"),
                 repos = c("https://olafmersmann.github.io/drat",
                           "https://jangorecki.github.io/drat/iperiod"))
library(microbenchmarkCore)
library(data.table) # iunit branch
library(xts)
Sys.setenv(TZ="UTC")

## some source data: download and unzip csv
# "http://api.bitcoincharts.com/v1/csv/btceUSD.csv.gz"
# below benchmark on btceUSD.csv.gz 11-Oct-2015 11:35 133664801

system.nanotime(dt <- fread(".btceUSD.csv"))
# Read 21931266 rows and 3 (of 3) columns from 0.878 GB file in 00:00:10
#     user   system  elapsed 
#       NA       NA 9.048991

# take the timestamp only
x = as.POSIXct(dt[[1L]], tz="UTC", origin="1970-01-01")

# functions
shhhhi <- function(your.time){
    strptime("1970-01-01", "%Y-%m-%d", tz="UTC") + round(as.numeric(your.time)/900)*900
}

PLapointe <- function(a){
    as.POSIXlt(round(as.double(a)/(15*60))*(15*60),origin=(as.POSIXlt('1970-01-01')))
}

# myRound - not vectorized

# compare results
all.equal(
    format(shhhhi(x),"%H:%M"),
    format(PLapointe(x),"%H:%M")
)
# [1] TRUE
all.equal(
    format(align.time(x, n = 60*15),"%H:%M"),
    format(periodize(x, "mins", 15),"%H:%M")
)
# [1] TRUE

# IPeriod native input are IDate and ITime - will be tested too
idt <- IDateTime(x)
idate <- idt$idate
itime <- idt$itime
microbenchmark(times = 10L,
               shhhhi(x),
               PLapointe(x),
               xts = align.time(x, 15*60),
               posix_ip_posix = as.POSIXct(periodize(x, "mins", 15), tz="UTC"),
               posix_ip = periodize(x, "mins", 15),
               ip_posix = as.POSIXct(periodize(idate, itime, "mins", 15), tz="UTC"),
               ip = periodize(idate, itime, "mins", 15))
# Unit: microseconds
#            expr         min          lq         mean       median          uq         max neval
#       shhhhi(x)  960819.810  984970.363 1127272.6812 1167512.2765 1201770.895 1243706.235    10
#    PLapointe(x) 2322929.313 2440263.122 2617210.4264 2597772.9825 2792936.774 2981499.356    10
#             xts  453409.222  525738.163  581139.6768  546300.9395  677077.650  767609.155    10
#  posix_ip_posix 3314609.993 3499220.920 3641219.0876 3586822.9150 3654548.885 4457614.174    10
#        posix_ip 3010316.462 3066736.299 3157777.2361 3133693.0655 3234307.549 3401388.800    10
#        ip_posix     335.741     380.696     513.7420     543.3425     630.020     663.385    10
#              ip      98.031     151.471     207.7404     231.8200     262.037     278.789    10

IDate iITime z powodzeniem skaluje się nie tylko w tym konkretnym zadaniu. Oba typy, takie same jakIPeriod, są oparte na liczbach całkowitych. Zakładam, że będą się skalować również przy łączeniu lub grupowaniu wedługdatetime pola.
Instrukcja online:https://jangorecki.github.io/drat/iperiod/

Abstrakcja jest cennym imo shadowtalker
@ssdecontrol Zobacz pierwsze polecenie w bloku kodu, które chcesz zainstalować z opublikowanego repo. W przeciwnym razie najbardziej niezawodnym sposobem jest zdobycieiunit oddział, możesz dodać go do zdalnego i do kasy do oddziału. Opiera się na danych z października 2015 r. Tabela. jangorecki
@ssdecontrol zgadza się, ale wyodrębnienie tylko tego do osobnego pakietu nie jest już konieczne, ponieważ data.table jest już lekką zależnością. Można importować tylko dla IDateTime bez kłopotów. Należy pamiętać, że planowane są rozszerzenia do klas data.table klas IDateTimedata.table # 1451, byłoby miło dla rękojeści IP nanosekund. jangorecki
Dziękuję za wiadomość, ale czy możesz wyjaśnić, jak to zrobićzainstalować ten pakiet? Nigdzie nie jest jasne z dokumentacji. shadowtalker
14

coś jak

format(strptime("1970-01-01", "%Y-%m-%d", tz="UTC") + round(as.numeric(your.time)/900)*900,"%H:%M")

pracowałbym

12

Rzeczywiście, stare pytanie z pewnymi pomocnymi odpowiedziami. Ten ostatni autorstwa giraffhere wydaje się najbardziej elegancki. jednak nie jest to data_podstawy, ale data_okrągła, która wykona sztuczkę:

lubridate::round_date(x, "15 minutes") 
Niezły punkt dodam. giraffehere
4

Możesz użyćalign.time funkcja w pakiecie xts do obsługi zaokrąglaniaformat aby zwrócić ciąg „HH: MM”:

R> library(xts)
R> p <- as.POSIXct("2012-05-30 20:41:21", tz="UTC")
R> a <- align.time(p, n=60*15)  # n is in seconds
R> format(a, "%H:%M")
[1] "20:45"
zaokrąglić w dół:align.time(p - lubridate::minutes(15), n=60*15) Nicholas Hamilton
+1 wskazówka dla ciebie gauden
To eleganckie, ale wydaje się tylko zaokrąglać. Dominic
@Dominic: masz 100% poprawności.align.time tylko zaokrągla w górę i chciałeś zaokrąglić do najbliższej ćwierć godziny. Przeprosiny. Joshua Ulrich

Powiązane pytania