每15分钟间隔的最接近值

时间:2018-08-20 19:23:43

标签: r dplyr data.table zoo

我希望在每个15分钟间隔(即12:00:00 AM,12:15:00 AM,12:30:00AM)中获取最接近的先前读数,以获取间隔之间的任意数量的读数。 / p>

例如,我希望拥有df

Timestamp   Value (kW)
8/12/2018 23:00:06  51
8/13/2018 0:00:16   52
8/13/2018 0:10:26   53
8/13/2018 0:14:36   54
8/13/2018 0:15:00   55
8/13/2018 0:19:57   56
8/13/2018 0:29:09   57
8/13/2018 0:38:17   58
8/13/2018 0:44:59   59
8/13/2018 0:45:00   60
8/13/2018 0:58:47   61
8/13/2018 1:01:57   62


structure(list(Timestamp = c("8/12/2018 23:00:00", "8/13/2018 0:00:00", 
"8/13/2018 0:10:00", "8/13/2018 0:14:00", "8/13/2018 0:15:00", 
"8/13/2018 0:19:00", "8/13/2018 0:29:00", "8/13/2018 0:38:00", 
"8/13/2018 0:44:00", "8/13/2018 0:45:00", "8/13/2018 0:58:00", 
"8/13/2018 1:01:00"), Value..kW. = 51:62), .Names = c("Timestamp", 
"Value..kW."), class = "data.frame", row.names = c(NA, -12L))

寻找更接近df2的地方:

Interval    Value
8/13/2018 0:00:00   51
8/13/2018 0:15:00   55
8/13/2018 0:30:00   57
8/13/2018 0:45:00   60
8/13/2018 1:00:00   61

也请注意seconds。 我认为nalocfzoodplyr的{​​{1}}函数可以帮助我。打开其他软件包。

3 个答案:

答案 0 :(得分:4)

对于使用{nearest“选项的data.table滚动连接来说,这可能是一个很好的应用。

第一步是将数据放入具有正确格式的data.table时间戳记的POSIXct类型的对象中。

library(data.table)

DT <- structure(list(Timestamp = c("8/12/2018 23:00:00", "8/13/2018 0:00:00", 
                             "8/13/2018 0:10:00", "8/13/2018 0:14:00", "8/13/2018 0:15:00", 
                             "8/13/2018 0:19:00", "8/13/2018 0:29:00", "8/13/2018 0:38:00", 
                             "8/13/2018 0:44:00", "8/13/2018 0:45:00", "8/13/2018 0:58:00", 
                             "8/13/2018 1:01:00"), Value..kW. = 51:62), .Names = c("Timestamp", 
                                                                                   "Value..kW."), class = "data.frame", row.names = c(NA, -12L))
## Convert from data.frame to data.table
setDT(DT)

## Convert to POSIXct
DT[,Timestamp := as.POSIXct(Timestamp, format = "%m/%d/%Y %H:%M:%S", tz = "UTC")]

一旦有了,就可以以15分钟的间隔序列生成另一个表。

## Get Start and Ends
Start <- min(as.POSIXct(cut.POSIXt(DT[,Timestamp],breaks = c("15 min")), tz = "UTC"))
End <- max(as.POSIXct(cut.POSIXt(DT[,Timestamp],breaks = c("15 min")), tz = "UTC"))
## Generate data.table with a sequence
SummaryDT <- data.table(TimeStamp15 = seq.POSIXt(from = Start, to = End, by = "15 min"))

print(SummaryDT)
#            TimeStamp15
# 1: 2018-08-12 23:00:00
# 2: 2018-08-12 23:15:00
# 3: 2018-08-12 23:30:00
# 4: 2018-08-12 23:45:00
# 5: 2018-08-13 00:00:00
# 6: 2018-08-13 00:15:00
# 7: 2018-08-13 00:30:00
# 8: 2018-08-13 00:45:00
# 9: 2018-08-13 01:00:00

然后,您可以设置键并使用滚动连接更新获得每15分钟一次的最接近值。

## Set keys
setkey(SummaryDT,TimeStamp15)
setkey(DT,Timestamp)

## Create a new column in SummaryDT with the closest measurement
SummaryDT[DT, Closest_Value_kW := `i.Value..kW.` , roll = "nearest"]
print(SummaryDT)
#            TimeStamp15 Closest_Value_kW
# 1: 2018-08-12 23:00:00               51
# 2: 2018-08-12 23:15:00               NA
# 3: 2018-08-12 23:30:00               NA
# 4: 2018-08-12 23:45:00               NA
# 5: 2018-08-13 00:00:00               52
# 6: 2018-08-13 00:15:00               56
# 7: 2018-08-13 00:30:00               57
# 8: 2018-08-13 00:45:00               60
# 9: 2018-08-13 01:00:00               62

如果您是data.table的新手,那么您可能需要了解很多内容,此示例位于频谱的高端-data.table网站上的Getting Started页面如果您以前从未使用过data.table,则可能是一个不错的起点。

执行help("data.table")可以使您的文章简洁明了,但是有一个很好的例子,说明了Ben Gorman在他的博客上写的一些功能– Gorman Analysis: R – Data.Table Rolling Joins,而Rober Norberg在他的博客bRogramming: Understanding data.table Rolling Joins可能有助于更好地理解。

  

更新:您似乎可能只希望进行结转观察,而不一定要执行“最近”值-在这种情况下,选项如下:

(使用相同的DT作为起点)

## Get Start and Ends
Start <- min(as.POSIXct(cut.POSIXt(DT[,Timestamp],breaks = c("15 min")), tz = "UTC"))
End <- max(as.POSIXct(cut.POSIXt(DT[,Timestamp],breaks = c("15 min"),), tz = "UTC"))
## Generate data.table with a sequence
SummaryDT <-data.table(TimeStamp15 = seq.POSIXt(from = Start, to = End, by = "15 min"))

## Set keys
setkey(SummaryDT,TimeStamp15)
setkey(DT,Timestamp)
## Do a rolling join
FinalDT <- DT[SummaryDT, roll = +Inf]

print(FinalDT)
#              Timestamp Value..kW.
# 1: 2018-08-12 23:00:00         51
# 2: 2018-08-12 23:15:00         51
# 3: 2018-08-12 23:30:00         51
# 4: 2018-08-12 23:45:00         51
# 5: 2018-08-13 00:00:00         52
# 6: 2018-08-13 00:15:00         55
# 7: 2018-08-13 00:30:00         57
# 8: 2018-08-13 00:45:00         60
# 9: 2018-08-13 01:00:00         61

答案 1 :(得分:1)

这可能与示例结果有所不同。我不确定您的示例输出是否100%正确。例如12/8中的数据呢?

润滑剂润滑脂具有许多有用的日期时间功能。这会将字符转换为日期,并四舍五入到最接近的句点。 (还有floor_dateceiling_date函数,分别向下或向上取整)。

library(dplyr) 
library(lubridate)
df %>% 
  # ensure timestamp is a date type and round to the nearest fifteen minutes
  mutate(ts = mdy_hm(Timestamp),
         period = round_date(ts, unit = "15 minutes")) %>%
  # group into periods 
  group_by(period) %>%
  # grab the first row in each period, orderd by the timestamp (use -1 for last)
  top_n(-1, ts) %>%
  # order the reuslt
  arrange(period)

#   Timestamp       Value..kW. ts                  period             
#   <chr>                <int> <dttm>              <dttm>             
# 1 8/12/2018 23:00         51 2018-08-12 23:00:00 2018-08-12 23:00:00
# 2 8/13/2018 0:00          52 2018-08-13 00:00:00 2018-08-13 00:00:00
# 3 8/13/2018 0:10          53 2018-08-13 00:10:00 2018-08-13 00:15:00
# 4 8/13/2018 0:29          57 2018-08-13 00:29:00 2018-08-13 00:30:00
# 5 8/13/2018 0:38          58 2018-08-13 00:38:00 2018-08-13 00:45:00

答案 2 :(得分:1)

根据输入数据的结构和预期的约束,OP有多种选择。

从问题和样本数据集中,如果输入数据包含空白(即间隔超过15分钟且未记录任何数据),则尚不清楚完全预期的结果。 OP如何希望输入数据中的差距反映在结果中?

编辑: 。OP提供了两个略有不同的数据集。两者都在下面用来说明输入数据对结果的影响。

下面的变体将使用lubridatedata.table。假定df已被Timesstamp排序。

准备

所有变体都需要它:

library(lubridate)
library(data.table)
setDT(df)[, Timestamp := mdy_hms(Timestamp)]

总计到下一个15分钟的间隔(结果存在差距)

最简单的解决方案是加入下一个15分钟间隔:

df[, .SD[.N], by = .(Interval = ceiling_date(Timestamp, "15 min"))]
              Interval Value..kW.
1: 2018-08-12 23:00:00         51
2: 2018-08-13 00:00:00         52
3: 2018-08-13 00:15:00         55
4: 2018-08-13 00:30:00         57
5: 2018-08-13 00:45:00         60
6: 2018-08-13 01:00:00         61
7: 2018-08-13 01:15:00         62

请注意,第1行和第2行之间存在1小时的间隔,其中缺少3个间隔。

为了完整起见,这是一个变体,它也适用于无序数据。

df[, .SD[which.max(Timestamp)], keyby = .(Interval = ceiling_date(Timestamp, "15 min"))]

编辑: 对于其他数据集(无截短的秒数),我们得到

df0[, .SD[.N], by = .(Interval = ceiling_date(Timestamp, "15 min"))]
1: 2018-08-12 23:15:00         51
2: 2018-08-13 00:15:00         55
3: 2018-08-13 00:30:00         57
4: 2018-08-13 00:45:00         60
5: 2018-08-13 01:00:00         61
6: 2018-08-13 01:15:00         62

请注意,这些值将在不缩短秒数的情况下移动到下一个间隔。

汇总到下一个15分钟间隔,结果无差异

step <- "15 min"
df[, .SD[.N], by = .(Interval = ceiling_date(Timestamp, step))][
  .(seq(min(Interval), max(Interval), step)), on = .(Interval = V1)]

在这里,我们加入一系列时间戳以完成缺少的间隔:

               Interval Value..kW.
 1: 2018-08-12 23:00:00         51
 2: 2018-08-12 23:15:00         NA
 3: 2018-08-12 23:30:00         NA
 4: 2018-08-12 23:45:00         NA
 5: 2018-08-13 00:00:00         52
 6: 2018-08-13 00:15:00         55
 7: 2018-08-13 00:30:00         57
 8: 2018-08-13 00:45:00         60
 9: 2018-08-13 01:00:00         61
10: 2018-08-13 01:15:00         62

现在,通过NA值,差距在结果中变得可见。

编辑: 对于其他数据集(无截短的秒数),我们得到

df0[, .SD[.N], by = .(Interval = ceiling_date(Timestamp, step))][
  .(seq(min(Interval), max(Interval), step)), on = .(Interval = V1)]
              Interval Value..kW.
1: 2018-08-12 23:15:00         51
2: 2018-08-12 23:30:00         NA
3: 2018-08-12 23:45:00         NA
4: 2018-08-13 00:00:00         NA
5: 2018-08-13 00:15:00         55
6: 2018-08-13 00:30:00         57
7: 2018-08-13 00:45:00         60
8: 2018-08-13 01:00:00         61
9: 2018-08-13 01:15:00         62

滚动联接(间隙填充了结果中的数据)

这是Matt's approach的精简版本

step = "15 min"
df[.(seq(floor_date(min(Timestamp), step), ceiling_date(max(Timestamp), step),by = step)), 
   on = .(Timestamp = V1), roll = TRUE]
              Timestamp Value..kW.
 1: 2018-08-12 23:00:00         51
 2: 2018-08-12 23:15:00         51
 3: 2018-08-12 23:30:00         51
 4: 2018-08-12 23:45:00         51
 5: 2018-08-13 00:00:00         52
 6: 2018-08-13 00:15:00         55
 7: 2018-08-13 00:30:00         57
 8: 2018-08-13 00:45:00         60
 9: 2018-08-13 01:00:00         61
10: 2018-08-13 01:15:00         62

在此处,间隙填充有从最新可用值复制的数据。从结果看,不再可见输入数据中存在间隙。

编辑: 对于其他数据集(无截短的秒数),我们得到

df0[.(seq(floor_date(min(Timestamp), step), ceiling_date(max(Timestamp), step),by = step)), 
   on = .(Timestamp = V1), roll = TRUE]
              Timestamp Value..kW.
 1: 2018-08-12 23:00:00         NA
 2: 2018-08-12 23:15:00         51
 3: 2018-08-12 23:30:00         51
 4: 2018-08-12 23:45:00         51
 5: 2018-08-13 00:00:00         51
 6: 2018-08-13 00:15:00         55
 7: 2018-08-13 00:30:00         57
 8: 2018-08-13 00:45:00         60
 9: 2018-08-13 01:00:00         61
10: 2018-08-13 01:15:00         62

在这里,第一行有一个未填补的空白。这是由间隔序列的构造方式引起的。可以避免稍加修改

df0[.(seq(ceiling_date(min(Timestamp), step), ceiling_date(max(Timestamp), step),by = step)), 
    on = .(Timestamp = V1), roll = TRUE]

             Timestamp Value..kW.
1: 2018-08-12 23:15:00         51
2: 2018-08-12 23:30:00         51
3: 2018-08-12 23:45:00         51
4: 2018-08-13 00:00:00         51
5: 2018-08-13 00:15:00         55
6: 2018-08-13 00:30:00         57
7: 2018-08-13 00:45:00         60
8: 2018-08-13 01:00:00         61
9: 2018-08-13 01:15:00         62

数据

该OP提供的数据为dput()

df <-
structure(list(Timestamp = c("8/12/2018 23:00:00", "8/13/2018 0:00:00", 
"8/13/2018 0:10:00", "8/13/2018 0:14:00", "8/13/2018 0:15:00", 
"8/13/2018 0:19:00", "8/13/2018 0:29:00", "8/13/2018 0:38:00", 
"8/13/2018 0:44:00", "8/13/2018 0:45:00", "8/13/2018 0:58:00", 
"8/13/2018 1:01:00"), Value..kW. = 51:62), .Names = c("Timestamp", 
"Value..kW."), class = "data.frame", row.names = c(NA, -12L))

编辑: :OP提供了两个略有不同的数据集:

  1. dput(),其中秒被截断(此答案中的df
  2. 在问题被截断的秒中df中打印df0(此答案中的df0 <- data.frame( readr::read_table(" Timestamp Value.(kW) 8/12/2018 23:00:06 51 8/13/2018 0:00:16 52 8/13/2018 0:10:26 53 8/13/2018 0:14:36 54 8/13/2018 0:15:00 55 8/13/2018 0:19:57 56 8/13/2018 0:29:09 57 8/13/2018 0:38:17 58 8/13/2018 0:44:59 59 8/13/2018 0:45:00 60 8/13/2018 0:58:47 61 8/13/2018 1:01:57 62 ")) # prepare library(lubridate) library(data.table) setDT(df0)[, Timestamp := mdy_hms(Timestamp)]

这种细微的差异会影响结果。因此,这是打印出来的数据集:

./gradlew :nameOfModule:action