#r #time-series
#r #временные ряды
Вопрос:
Это кажется простым, но после долгих поисков и попыток я этого не понял:
У меня есть список временных рядов, краткий пример для воспроизведения:
a <- seq(as.Date("1970-01-01"), as.Date("1970-01-05"), "days")
b <- seq(as.Date("1985-10-01"), as.Date("1985-10-05"), "days")
c <- seq(as.Date("2014-03-01"), as.Date("2014-03-05"), "days")
d <- c(a, b, c)
df1 <- data.frame(d)
colnames(df1) <- c("date")
e <- seq(as.Date("1975-01-01"), as.Date("1975-01-05"), "days")
f <- seq(as.Date("1990-10-01"), as.Date("1990-10-05"), "days")
g <- c(e, f)
df2 <- data.frame(g)
colnames(df2) <- c("date")
ll <- list(df1, df2)
Теперь я хочу подмножество перечисленных данных.кадры для:
> llsubset
[[1]]
date
1 1970-01-01
2 1970-01-05
3 1985-10-01
4 1985-10-05
5 2014-03-01
6 2014-03-05
[[2]]
date
1 1975-01-01
2 1975-01-05
3 1990-10-01
4 1990-10-05
Я пробовал это с помощью rollapply
, но это не работает, и это не стоит смотреть. Может быть, вы можете мне помочь? Спасибо!
Ответ №1:
Определите, какие точки отличаются от предыдущих более чем на 1 день, и из этого постройте логическое с ИСТИНОЙ в концах каждой последовательности и ЛОЖЬЮ в другом месте. Подмножество по нему. Пакеты не используются.
lapply(ll, subset, { dif <- diff(date) > 1; c(TRUE, dif) | c(dif, TRUE) } )
предоставление:
[[1]]
date
1 1970-01-01
5 1970-01-05
6 1985-10-01
10 1985-10-05
11 2014-03-01
15 2014-03-05
[[2]]
date
1 1975-01-01
5 1975-01-05
6 1990-10-01
10 1990-10-05
Комментарии:
1. Мне нравится использование
|
.
Ответ №2:
Может быть, что-то вроде этого? Используйте cumsum
и diff
для создания групповой переменной, а затем подмножьте свою дату (при условии, что вы пытаетесь узнать минимальную и максимальную дату в течение каждого последовательного периода времени и date
сортируется в порядке возрастания перед рукой):
library(dplyr)
lapply(ll, function(df) {
df %>%
group_by(cumsum(c(TRUE, diff(date) != 1))) %>%
slice(c(1, n())) %>%
ungroup() %>%
select(date) }
)
#[[1]]
# A tibble: 6 × 1
# date
# <date>
#1 1970-01-01
#2 1970-01-05
#3 1985-10-01
#4 1985-10-05
#5 2014-03-01
#6 2014-03-05
#[[2]]
# A tibble: 4 × 1
# date
# <date>
#1 1975-01-01
#2 1975-01-05
#3 1990-10-01
#4 1990-10-05
Ответ №3:
Вероятно, есть пакет, который делает именно это, но я пока не знаю его названия.
Использование diff()
для дат может выделить, какие даты имеют только один день между ними, вот так:
diff(df1$date)
Time differences in days
[1] 1 1 1 1 5748 1 1 1 1 10374 1
[12] 1 1 1
Мы можем использовать это.
end_finder <- function(x) {
# find the gap between dates.
# mark dates where the diff > 1,
# also mark the entry prior to that one;
# this will be the end of the previous date.
# also include the first and last element.
diff_dates <- c(100,diff(x$dates))
diff_idx <- which(diff_dates > 1)
diff_idx <- c((diff_idx -1 ), diff_idx)
# remove any elements < 1
diff_idx <- diff_idx[diff_idx >= 1 ]
# include the first element
diff_idx <- c(1, diff_idx)
# include the last element
diff_idx <- c(diff_idx, length(x$date))
# remove duplicates and sort for easier reading
diff_idx <- sort(unique(diff_idx))
x$dates[diff_idx]
}
Теперь запустите это.
> lapply(ll, end_finder)
[[1]]
[1] "1970-01-01" "1970-01-05" "1985-10-01" "1985-10-05" "2014-03-01"
[6] "2014-03-05"
[[2]]
[1] "1975-01-01" "1975-01-05" "1990-10-01" "1990-10-05"
Ответ №4:
Другое решение с использованием dplyr
: сначала мы вычисляем год для каждой даты и для каждого года находим минимальную и максимальную дату, используя year
и melt
функции из пакетов lubridate и reshape2 соответственно
library(dplyr)
library(lubridate)
library(reshape2)
ll <- list(df1, df2)
fn_endPoint_Years = function(DF) {
newDF = DF %>%
mutate(Year=year(date)) %>%
group_by(Year) %>%
do(.,data.frame(minDate=min(.$date),maxDate=max(.$date) )) %>%
melt(id="Year",value.name = "date") %>%
arrange(date) %>%
select(date)
}
lapply(ll,fn_endPoint_Years)
# [[1]]
# date
# 1 1970-01-01
# 2 1970-01-05
# 3 1985-10-01
# 4 1985-10-05
# 5 2014-03-01
# 6 2014-03-05
# [[2]]
# date
# 1 1975-01-01
# 2 1975-01-05
# 3 1990-10-01
# 4 1990-10-05