Использование IDate
и ITime
классы от data.table
и класс IPeriod
(только что разработанный) Я смог получить более масштабируемое решение.
только shhhhimhuntingrabbits и PLapointe ответить на вопрос с точки зрения ближайшего. xts
раствор только раундов с использованием потолок, мой IPeriod
раствор позволяет указать потолок или этаж.
Чтобы получить максимальную производительность, вам необходимо сохранить свои данные в классах IDate
и ITime
. Как видно из сравнения, дешево производить POSIXct
от IDate/ITime/IPeriod
. Ниже эталон некоторых 22Й метки времени:
# 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
и ITime
успешно масштабируются не только в этой конкретной задаче. Оба типа, такие как IPeriod
, основаны на целых числах. Я бы предположил, что они также будут масштабироваться красиво при объединении или группировке на datetime полей.
Интернет Руководство: https://jangorecki.github.io/drat/iperiod/
+1 наконечника шляпы к вам – gauden
Это элегантное, но, кажется, только округлить. – Dominic
@ Dominic: вы на 100% правильны. 'align.time' только округляется, и вы хотели округлить до ближайшего четверть часа. Извиняюсь. –