libro - fahrenheit 451 ray bradbury
Tiempo de redondeo al cuarto de hora más cercano (7)
De hecho, una vieja pregunta con algunas respuestas útiles hasta ahora. El último por jirafa parece ser el más elegante. sin embargo, no es floor_date sino round_date que hará el truco:
lubridate::round_date(x, "15 minutes")
Tengo un vector de valores POSIXct y me gustaría redondearlos al cuarto de hora más cercano. No me importa el día. ¿Cómo convierto los valores a horas y minutos?
Por ejemplo, me gustaría el valor.
"2012-05-30 20:41:21 UTC"
ser
"20:45"
Intente esto, que combina ambas solicitudes y se basa en lo que hacen round.POSIXt()
y trunc.POSIXt()
.
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
}
Esto da:
> 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"
Pregunta antigua, pero me gustaría señalar que el paquete lubridate
maneja esto fácilmente ahora con floor_date
. Para cortar un vector de objetos POSIXct a intervalos de 15 minutos, úselo así.
x <- lubridate::floor_date(x, "15 minutes")
EDITAR: anotado por el usuario @ user3297928, use lubridate::round_date(x, "15 minutes")
para redondear a los 15 minutos más cercanos. Los pisos anteriores lo.
Puede usar la función align.time
en el paquete xts para manejar el redondeo, luego format
para devolver una cadena de "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"
Se puede usar round
. El truco es dividir por 900 segundos (15 minutos * 60 segundos) antes de redondear y multiplicar por 900 luego:
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"
Para obtener solo hora y minuto, solo usa el formato
format(b,"%H:%M")
[1] "20:45"
as.character(format(b,"%H:%M"))
[1] "20:45"
Usando las clases IDate
y ITime
de data.table
y una clase de IPeriod
(recién desarrollada) pude obtener una solución más escalable.
Solo shhhhimhuntingrabbits y PLapointe responden la pregunta en términos de lo más cercano . xts
solución xts
solo redondea utilizando el techo , mi solución IPeriod
permite especificar el techo o el piso .
Para obtener el mejor rendimiento, debería mantener sus datos en clases de IDate
y ITime
. Como se ve en el punto de referencia, es barato producir POSIXct
desde IDate/ITime/IPeriod
. Por debajo del punto de referencia de unos 22M de marca de tiempo:
# 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
y ITime
éxito no solo en esta tarea en particular. Ambos tipos, igual que IPeriod
, están basados en enteros. Supongo que también se ajustarán bien en la combinación o agrupación por campos de fecha y hora .
Manual en línea: https://jangorecki.github.io/drat/iperiod/
algo como
format(strptime("1970-01-01", "%Y-%m-%d", tz="UTC") + round(as.numeric(your.time)/900)*900,"%H:%M")
trabajaría