2012-06-02 4 views

ответ

14

что-то вроде

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

будет работать

4

Вы можете использовать align.time функция в пакете XTS, чтобы справиться с округлением, затем format возвращать строку из «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" 
+0

+1 наконечника шляпы к вам – gauden

+5

Это элегантное, но, кажется, только округлить. – Dominic

+0

@ Dominic: вы на 100% правильны. 'align.time' только округляется, и вы хотели округлить до ближайшего четверть часа. Извиняюсь. –

3

Попробуйте, который сочетает в себе запросы и основан на глядя на то, round.POSIXt() и 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 
} 

Это дает:

> 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" 
+0

это, кажется, не хорошо векторизовано, попробуйте 'структура (c (1313331280, 1313334917, 1313334917, 1313340309, 1313340309, 1313340895, 1313340895, 1313341133, 1313341218, 1313341475), class = c ("POSIXct", "POSIXt"), tzone = "UTC") ' – jangorecki

17

Вы можете использовать round. Хитрость заключается в том, чтобы разделить на 900 секунд (15 минут * 60 секунд) до округления и умножить на 900 потом:

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" 

Чтобы получить только час и минуту, просто использовать формат

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

as.character(format(b,"%H:%M")) 
[1] "20:45" 
+2

Я не думаю, что нам нужен двойной, а начало принимает строка, немного упрощенная: 'b <-as.POSIXlt (round (as.numeric (a)/(15 * 60)) * (15 * 60), origin = '1970-01-01')' –

2

Использование 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/

+0

Спасибо за сообщение, но вы можете объяснить, как на самом деле _install_ этот пакет? Это не ясно из документации. – shadowtalker

+0

@ssdecontrol См. Первую команду в блоке кода для установки из опубликованного репо. В противном случае самым надежным способом является получение ветки [iunit] (https://github.com/jangorecki/data.table/tree/iunit), вы можете добавить ее в удаленный и checkout для филиала. Он основан на таблице данных за октябрь 2015 года. – jangorecki

+0

Ах, я пропустил эту линию. Я предположил, что у вас будет отдельный пакет под названием «periodize» или «IPeriod» или что-то в отличие от вилки data.table. Я думаю, что несколько неудачно, что материал 'IDateTime' связан с data.table, а не с отдельным пакетом – shadowtalker

8

Старый вопрос, но хотел бы отметить, что lubridate пакет обрабатывает это легко теперь с floor_date. Чтобы разрезать вектор объектов POSIXct на 15-минутные интервалы, используйте это.

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

EDIT: Отмеченный пользователем @ user3297928 используйте lubridate::round_date(x, "15 minutes") для округления до ближайших 15 минут. На вышеуказанных этажах это.

2

Действительно, старый вопрос с некоторыми полезными ответами до сих пор. Последний, по-видимому, самый гибкий. Однако, IST не floor_date но round_date, который будет делать трюк:

lubridate::round_date(x, "15 minutes") 
+0

Хороший пункт, добавит. – giraffehere

Смежные вопросы