R:如何找到数据点重叠且没有缺失数据的最长周期?



我有一个非常大的变电站电力负荷时间序列数据集,该数据集已被清理为具有 15 分钟的一致时间间隔,但仍有大量数据丢失。变电站分为单独的馈线,因此形式如下:

Feeder <- c("F1","F1","F1","F1","F1", "F2","F2","F2","F2","F2", "F3","F3","F3","F3","F3")
Load <- c(3.1, NA, 4.0, 3.8, 3.6, 2.1, NA, 2.6, 2.9, 3.0, 2.4, NA, 2.3, 2.2, 2.5)
start <- as.POSIXct("2016-01-12 23:15:00")
end <- as.POSIXct("2016-01-13 00:15:00")
DateTimeseq <- seq(start, end, by = "15 min")
DateTime <- c(DateTimeseq, DateTimeseq, DateTimeseq)
dt <- data.frame(Feeder, Load, DateTime)

我的实际数据跨越了多年,但我已将其压缩下来,因此易于复制。如您所见,存在缺失值。我的实际数据集有大量缺失数据。为了进行有效的分析,我需要找到所有馈线没有丢失负载数据点的周期(即最长重叠周期(。如果可能的话,我想生成一个没有任何 NA 值的最长重叠周期列表,最小值约为 24 小时(我知道这在我给出的例子中是不可能的,但如果你能告诉我那会很棒!在此示例中,您可以使用至少 15 分钟或其他时间。

从简单数据中可以看出,在 2016-01-12 23:45:00和 2016-01-13 00:15:00 之间,最长的时间段为 30 分钟。但是,在此示例中,第二长的时间段为 15 分钟,但在最长时间段内。如果可能的话,我想运行它,这样它就不会复制值。如果是这样,在这种情况下,第二长的时间段将是重叠点 2016-01-12 23:15:00。

随意使用它并添加更多值,如果它更容易。为不同的进料器创建单独的列可能是有益的。我通常使用dplyr的管道,但这不是必需的。如果您需要更多信息,请随时询问。

谢谢!

基本 R 解决方案:

# Strategy 1 contiguous period classification:
data.frame(do.call("rbind", lapply(split(dt, dt$Feeder), function(x){
y <- with(x, x[order(DateTime),])
y$category <- paste0(y$Feeder, ":", cumsum(is.na(y$Load)) + 1)
tmp <- y[!(is.na(y$Load)),]
cat_diff <- do.call("rbind", lapply(split(tmp, tmp$category), 
function(z){
data.frame(category = unique(z$category), 
max_diff = difftime(max(z$DateTime),
min(z$DateTime), 
units = "hours"))}))
y$max_diff <- cat_diff$max_diff[match(y$category, cat_diff$category)] 
return(y)
}
)
), row.names = NULL
)

也许,这会给你一个开始。对于每个Feeder,您可以在NA值之间创建组,计算它们的第一个和最后一个值,并在它们之间创建一个 15 分钟的序列。然后,您可以count数据中出现最多的间隔。

library(dplyr)
dt %>%
group_by(Feeder) %>%
group_by(grp = cumsum(is.na(Load)), .add = TRUE) %>%
#Use add = TRUE in old dplyr
#group_by(grp = cumsum(is.na(Load)), add = TRUE) %>%
summarise(start = first(DateTime), 
end = last(DateTime)) %>%
ungroup %>%
mutate(datetime = purrr::map2(start, end, seq, by = '15 mins')) %>%
tidyr::unnest(datetime) %>%
select(-start, -end) %>%
count(datetime, sort = TRUE)

这是另一个选项,用于强制转换为宽表并检查没有任何 NA 的连续行:

library(data.table)
wDT <- dcast(setDT(dt)[, na := +is.na(Load)], DateTime ~ Feeder, value.var="na")
wDT[, c("ri", "rr") := {
ri <- rleid(rowSums(.SD)==0L)
.(ri, rowid(ri))
}, .SDcols=names(wDT)[-1L]]
range(wDT[ri %in% ri[rr==max(rr)]]$DateTime)
#[1] "2016-01-12 23:45:00 +08" "2016-01-13 00:15:00 +08"

我可能会为您提供一个不错的 3 行代码解决方案:

  1. 首先将数据转换为宽格式,即每个馈线都是一列
  2. 逐行检查(现在是时间戳(,所有馈送器都是非 NA。这给出了类似于 12:15 TRUE、12:30 TRUE、12:45 FALSE 之类的内容,...在此上下文中为 FALSE 表示所有馈线都可用于此时间戳
  3. 对生成的真、真、假、假进行运行长度编码,...系列 - 这使您可以找到您所谓的连续重叠周期

法典:

library("tidyr")
library("dplyr")
# Into wide format
dt_wide <- dt %>% pivot_wider(names_from = Feeder, values_from = Load)
# Check if complete row is available
dt_anyna <- apply(y,1, anyNA)

# Now we need to find the longest FALSE runs
rle(dt_anyna)

这为您提供了一个运行长度编码,如下所示

Run Length Encoding
lengths: int [1:3] 1 1 3
values : logi [1:3] FALSE TRUE FALSE

意思是一开始你连续有 1 个 False,连续有 1 个 TRUE,连续有接下来的 3 个 FALSE。

现在,您可以轻松处理此结果。您可能希望筛选出 TRUE 运行,因为您只查找所有数据都可用的最长运行(这些是 FALSE 运行(。 然后你可以寻找max((运行,你也可以寻找例如运行>4(对于你的15分钟数据,这将是1h(。

埃利斯问题的其他代码

rle <- rle(dt_anyna)
x <- data.frame(  value = rle$values, duration = rle$lengths)
x$start <- dt_wide$DateTime[(cumsum(x$duration)- x$duration)+1]
x$end <-  dt_wide$DateTime[cumsum(x$duration)]
x$duration_s <-  x$end - x$start
ordered <- x[order(x$duration, decreasing = TRUE),]  
filtered <- filter(ordered, value == FALSE)
filtered

因此,只需恢复我们之前结束的地方 - 您可以使用此代码添加自己的开始/结束时间/持续时间/排序和过滤。(您现在还必须在开始时调用库("dplyr"(

结果如下所示:

value  duration   start                end                 duration_s
FALSE        3    2016-01-12 23:45:00 2016-01-13 00:15:00  1800 secs
FALSE        1    2016-01-12 23:15:00 2016-01-12 23:15:00     0 secs

这将为您提供一个 data.frame,按连续非 NA 段的持续时间以及开始和结束时间排序。

最新更新