"Spread" na.locf数据为不规则时间数据
"Spread" na.locf data for irregular time data
我有如下数据:
data <- tibble(time = c(ymd_hms("2019-11-01 09:33:00"),
ymd_hms("2019-11-01 09:35:00"),
ymd_hms("2019-11-01 09:40:00"),
ymd_hms("2019-11-01 09:52:00")),
data = c(1250, 900, 4000, 9000))
data
## A tibble: 4 x 2
# time data
# <dttm> <dbl>
# 1 2019-11-01 09:33:00 1250
# 2 2019-11-01 09:35:00 900
# 3 2019-11-01 09:40:00 4000
# 4 2019-11-01 09:52:00 9000
我希望在第一次和最后一次观察之间的每一分钟对 data
列进行重新采样,并且我希望 data
的值成为下一个非 NAN 值除以 1 +从先前的非 nan 值到下一个非 nan 值的 nan 值的数量(即 data
的值是 "spread" 从其给定样本点到先前给定样本点的分钟数。
例如,在这种情况下,我希望得到以下结果
> result
# A tibble: 20 x 2
time data
<dttm> <dbl>
1 2019-11-01 09:33:00 1250
2 2019-11-01 09:34:00 450
3 2019-11-01 09:35:00 450
4 2019-11-01 09:36:00 800
5 2019-11-01 09:37:00 800
6 2019-11-01 09:38:00 800
7 2019-11-01 09:39:00 800
8 2019-11-01 09:40:00 800
9 2019-11-01 09:41:00 750
10 2019-11-01 09:42:00 750
11 2019-11-01 09:43:00 750
12 2019-11-01 09:44:00 750
13 2019-11-01 09:45:00 750
14 2019-11-01 09:46:00 750
15 2019-11-01 09:47:00 750
16 2019-11-01 09:48:00 750
17 2019-11-01 09:49:00 750
18 2019-11-01 09:50:00 750
19 2019-11-01 09:51:00 750
20 2019-11-01 09:52:00 750
我该怎么做?
我在 Zoo 中看到如何使用 na.locf
来做 几乎 我想要的,但我不知道如何将这个 "spreading"数据而不是仅仅填充最后一个值或进行线性插值。
我也尝试过使用 xts
并使用一些自定义逻辑合并两个系列(其中一个是不规则日期),但这对我来说很有挑战性。
我们可以使用 dplyr
和 join
具有所有时间步长的数据帧。
然后我们可以使用 tidyr
到 fill
向上,最后除以每组中的记录数(即缺少的时间步数 + 1)
library(dplyr)
library(lubridate)
library(tidyr)
data <- tibble(time = c(ymd_hms("2019-11-01 09:33:00"),
ymd_hms("2019-11-01 09:35:00"),
ymd_hms("2019-11-01 09:40:00"),
ymd_hms("2019-11-01 09:52:00")),
data = c(1250, 900, 4000, 9000))
tibble(time = seq.POSIXt(from = min(data$time),
to = max(data$time), by="min")) %>%
left_join(., data, by="time") %>%
group_by(id = cumsum(is.na(data) & !is.na(lag(data)))) %>%
fill(data, .direction = "up") %>%
mutate(data = data/ n())
#> # A tibble: 20 x 3
#> # Groups: id [4]
#> time data id
#> <dttm> <dbl> <int>
#> 1 2019-11-01 09:33:00 1250 0
#> 2 2019-11-01 09:34:00 450 1
#> 3 2019-11-01 09:35:00 450 1
#> 4 2019-11-01 09:36:00 800 2
#> 5 2019-11-01 09:37:00 800 2
#> 6 2019-11-01 09:38:00 800 2
#> 7 2019-11-01 09:39:00 800 2
#> 8 2019-11-01 09:40:00 800 2
#> 9 2019-11-01 09:41:00 750 3
#> 10 2019-11-01 09:42:00 750 3
#> 11 2019-11-01 09:43:00 750 3
#> 12 2019-11-01 09:44:00 750 3
#> 13 2019-11-01 09:45:00 750 3
#> 14 2019-11-01 09:46:00 750 3
#> 15 2019-11-01 09:47:00 750 3
#> 16 2019-11-01 09:48:00 750 3
#> 17 2019-11-01 09:49:00 750 3
#> 18 2019-11-01 09:50:00 750 3
#> 19 2019-11-01 09:51:00 750 3
#> 20 2019-11-01 09:52:00 750 3
1) zoo 转换为 zoo 对象 z
,使用 merge
插入 NA,然后将组 g
定义为连续位置除了组中的最后一个之外,它们都是 NA。然后计算所需的比率并使用 fortify.zoo
转换为数据框。如果动物园系列结果没问题,最后一行可以省略。
library(zoo)
z <- read.zoo(data)
m <- merge(z, zoo(, seq(start(z), end(z), 60)))
g <- head(c(0, cumsum(!is.na(m))), -1)
data2 <- na.locf0(m, fromLast = TRUE) / ave(m, g, FUN = length)
fortify.zoo(data2)
给予:
Index data2
1 2019-11-01 09:33:00 1250
2 2019-11-01 09:34:00 450
3 2019-11-01 09:35:00 450
4 2019-11-01 09:36:00 800
5 2019-11-01 09:37:00 800
6 2019-11-01 09:38:00 800
7 2019-11-01 09:39:00 800
8 2019-11-01 09:40:00 800
9 2019-11-01 09:41:00 750
10 2019-11-01 09:42:00 750
11 2019-11-01 09:43:00 750
12 2019-11-01 09:44:00 750
13 2019-11-01 09:45:00 750
14 2019-11-01 09:46:00 750
15 2019-11-01 09:47:00 750
16 2019-11-01 09:48:00 750
17 2019-11-01 09:49:00 750
18 2019-11-01 09:50:00 750
19 2019-11-01 09:51:00 750
20 2019-11-01 09:52:00 750
2) base 这是一个更短的基本解决方案。我们定义了一个函数 ratiofun
,它为一组给定其长度(以分钟为单位)和右端点的值生成数据。然后展开时间,应用函数。
ratiofun <- function(minutes, data) rep(data/minutes, minutes)
with(data, data.frame(time = seq(min(time), max(time), 60),
data = unlist(mapply(ratiofun, c(1, diff(time)), data))))
给予:
time data
1 2019-11-01 09:33:00 1250
2 2019-11-01 09:34:00 450
3 2019-11-01 09:35:00 450
4 2019-11-01 09:36:00 800
5 2019-11-01 09:37:00 800
6 2019-11-01 09:38:00 800
7 2019-11-01 09:39:00 800
8 2019-11-01 09:40:00 800
9 2019-11-01 09:41:00 750
10 2019-11-01 09:42:00 750
11 2019-11-01 09:43:00 750
12 2019-11-01 09:44:00 750
13 2019-11-01 09:45:00 750
14 2019-11-01 09:46:00 750
15 2019-11-01 09:47:00 750
16 2019-11-01 09:48:00 750
17 2019-11-01 09:49:00 750
18 2019-11-01 09:50:00 750
19 2019-11-01 09:51:00 750
20 2019-11-01 09:52:00 750
我有如下数据:
data <- tibble(time = c(ymd_hms("2019-11-01 09:33:00"),
ymd_hms("2019-11-01 09:35:00"),
ymd_hms("2019-11-01 09:40:00"),
ymd_hms("2019-11-01 09:52:00")),
data = c(1250, 900, 4000, 9000))
data
## A tibble: 4 x 2
# time data
# <dttm> <dbl>
# 1 2019-11-01 09:33:00 1250
# 2 2019-11-01 09:35:00 900
# 3 2019-11-01 09:40:00 4000
# 4 2019-11-01 09:52:00 9000
我希望在第一次和最后一次观察之间的每一分钟对 data
列进行重新采样,并且我希望 data
的值成为下一个非 NAN 值除以 1 +从先前的非 nan 值到下一个非 nan 值的 nan 值的数量(即 data
的值是 "spread" 从其给定样本点到先前给定样本点的分钟数。
例如,在这种情况下,我希望得到以下结果
> result
# A tibble: 20 x 2
time data
<dttm> <dbl>
1 2019-11-01 09:33:00 1250
2 2019-11-01 09:34:00 450
3 2019-11-01 09:35:00 450
4 2019-11-01 09:36:00 800
5 2019-11-01 09:37:00 800
6 2019-11-01 09:38:00 800
7 2019-11-01 09:39:00 800
8 2019-11-01 09:40:00 800
9 2019-11-01 09:41:00 750
10 2019-11-01 09:42:00 750
11 2019-11-01 09:43:00 750
12 2019-11-01 09:44:00 750
13 2019-11-01 09:45:00 750
14 2019-11-01 09:46:00 750
15 2019-11-01 09:47:00 750
16 2019-11-01 09:48:00 750
17 2019-11-01 09:49:00 750
18 2019-11-01 09:50:00 750
19 2019-11-01 09:51:00 750
20 2019-11-01 09:52:00 750
我该怎么做?
我在 Zoo 中看到如何使用 na.locf
来做 几乎 我想要的,但我不知道如何将这个 "spreading"数据而不是仅仅填充最后一个值或进行线性插值。
我也尝试过使用 xts
并使用一些自定义逻辑合并两个系列(其中一个是不规则日期),但这对我来说很有挑战性。
我们可以使用 dplyr
和 join
具有所有时间步长的数据帧。
然后我们可以使用 tidyr
到 fill
向上,最后除以每组中的记录数(即缺少的时间步数 + 1)
library(dplyr)
library(lubridate)
library(tidyr)
data <- tibble(time = c(ymd_hms("2019-11-01 09:33:00"),
ymd_hms("2019-11-01 09:35:00"),
ymd_hms("2019-11-01 09:40:00"),
ymd_hms("2019-11-01 09:52:00")),
data = c(1250, 900, 4000, 9000))
tibble(time = seq.POSIXt(from = min(data$time),
to = max(data$time), by="min")) %>%
left_join(., data, by="time") %>%
group_by(id = cumsum(is.na(data) & !is.na(lag(data)))) %>%
fill(data, .direction = "up") %>%
mutate(data = data/ n())
#> # A tibble: 20 x 3
#> # Groups: id [4]
#> time data id
#> <dttm> <dbl> <int>
#> 1 2019-11-01 09:33:00 1250 0
#> 2 2019-11-01 09:34:00 450 1
#> 3 2019-11-01 09:35:00 450 1
#> 4 2019-11-01 09:36:00 800 2
#> 5 2019-11-01 09:37:00 800 2
#> 6 2019-11-01 09:38:00 800 2
#> 7 2019-11-01 09:39:00 800 2
#> 8 2019-11-01 09:40:00 800 2
#> 9 2019-11-01 09:41:00 750 3
#> 10 2019-11-01 09:42:00 750 3
#> 11 2019-11-01 09:43:00 750 3
#> 12 2019-11-01 09:44:00 750 3
#> 13 2019-11-01 09:45:00 750 3
#> 14 2019-11-01 09:46:00 750 3
#> 15 2019-11-01 09:47:00 750 3
#> 16 2019-11-01 09:48:00 750 3
#> 17 2019-11-01 09:49:00 750 3
#> 18 2019-11-01 09:50:00 750 3
#> 19 2019-11-01 09:51:00 750 3
#> 20 2019-11-01 09:52:00 750 3
1) zoo 转换为 zoo 对象 z
,使用 merge
插入 NA,然后将组 g
定义为连续位置除了组中的最后一个之外,它们都是 NA。然后计算所需的比率并使用 fortify.zoo
转换为数据框。如果动物园系列结果没问题,最后一行可以省略。
library(zoo)
z <- read.zoo(data)
m <- merge(z, zoo(, seq(start(z), end(z), 60)))
g <- head(c(0, cumsum(!is.na(m))), -1)
data2 <- na.locf0(m, fromLast = TRUE) / ave(m, g, FUN = length)
fortify.zoo(data2)
给予:
Index data2
1 2019-11-01 09:33:00 1250
2 2019-11-01 09:34:00 450
3 2019-11-01 09:35:00 450
4 2019-11-01 09:36:00 800
5 2019-11-01 09:37:00 800
6 2019-11-01 09:38:00 800
7 2019-11-01 09:39:00 800
8 2019-11-01 09:40:00 800
9 2019-11-01 09:41:00 750
10 2019-11-01 09:42:00 750
11 2019-11-01 09:43:00 750
12 2019-11-01 09:44:00 750
13 2019-11-01 09:45:00 750
14 2019-11-01 09:46:00 750
15 2019-11-01 09:47:00 750
16 2019-11-01 09:48:00 750
17 2019-11-01 09:49:00 750
18 2019-11-01 09:50:00 750
19 2019-11-01 09:51:00 750
20 2019-11-01 09:52:00 750
2) base 这是一个更短的基本解决方案。我们定义了一个函数 ratiofun
,它为一组给定其长度(以分钟为单位)和右端点的值生成数据。然后展开时间,应用函数。
ratiofun <- function(minutes, data) rep(data/minutes, minutes)
with(data, data.frame(time = seq(min(time), max(time), 60),
data = unlist(mapply(ratiofun, c(1, diff(time)), data))))
给予:
time data
1 2019-11-01 09:33:00 1250
2 2019-11-01 09:34:00 450
3 2019-11-01 09:35:00 450
4 2019-11-01 09:36:00 800
5 2019-11-01 09:37:00 800
6 2019-11-01 09:38:00 800
7 2019-11-01 09:39:00 800
8 2019-11-01 09:40:00 800
9 2019-11-01 09:41:00 750
10 2019-11-01 09:42:00 750
11 2019-11-01 09:43:00 750
12 2019-11-01 09:44:00 750
13 2019-11-01 09:45:00 750
14 2019-11-01 09:46:00 750
15 2019-11-01 09:47:00 750
16 2019-11-01 09:48:00 750
17 2019-11-01 09:49:00 750
18 2019-11-01 09:50:00 750
19 2019-11-01 09:51:00 750
20 2019-11-01 09:52:00 750