У меня есть данные временного ряда с шагом в 1 минуту. Я написал код, но с большим объемом данных, которые у меня есть (более 1 миллиона строк), цикл по каждой строке занимает слишком много времени. Данные выглядят примерно так:
t0 = as.POSIXlt("2018-12-23 00:01:00")
t0 = t0+seq(60,60*10,60)
p1 = seq(5,5*10,5)
p2 = seq(7,7*10,7)
m0 = cbind(p1,p2)
rownames(m0) = as.character(t0)
Где это выглядит примерно так:
> head(m0)
p1 p2
2018-12-23 00:02:00 5 7
2018-12-23 00:03:00 10 14
2018-12-23 00:04:00 15 21
2018-12-23 00:05:00 20 28
2018-12-23 00:06:00 25 35
2018-12-23 00:07:00 30 42
Я хочу преобразовать эти данные с шагом 5 секунд, добавляя 11 строк (55 секунд) перед каждой минутой со значением, перенесенным из последнего значения. Итак, это было бы примерно так:
> new0
p1 p2
2018-12-23 00:01:05 5 7
2018-12-23 00:01:10 5 7
2018-12-23 00:01:15 5 7
2018-12-23 00:01:20 5 7
2018-12-23 00:01:25 5 7
2018-12-23 00:01:30 5 7
2018-12-23 00:01:35 5 7
2018-12-23 00:01:40 5 7
2018-12-23 00:01:45 5 7
2018-12-23 00:01:50 5 7
2018-12-23 00:01:55 5 7
2018-12-23 00:02:00 5 7
2018-12-23 00:02:05 10 14
2018-12-23 00:02:10 10 14
2018-12-23 00:02:15 10 14
2018-12-23 00:02:20 10 14
2018-12-23 00:02:25 10 14
2018-12-23 00:02:30 10 14
2018-12-23 00:02:35 10 14
2018-12-23 00:02:40 10 14
2018-12-23 00:02:45 10 14
2018-12-23 00:02:50 10 14
2018-12-23 00:02:55 10 14
2018-12-23 00:03:00 10 14
Я надеюсь найти способ сделать это без использования цикла и с использованием эффективных кодов в xts и / или Таблица данных, с которыми я не слишком знаком.
Я пробовал использовать функцию ave
из базы R, но она не работает достаточно быстро.
Вот один из способов сделать это в базе R. Сначала преобразуйте данные во фрейм данных с явным столбцом для меток времени:
m0 <- as.data.frame(m0)
m0$t <- t0
p1 p2 t
1 5 7 2018-12-23 00:02:00
2 10 14 2018-12-23 00:03:00
3 15 21 2018-12-23 00:04:00
4 20 28 2018-12-23 00:05:00
5 25 35 2018-12-23 00:06:00
6 30 42 2018-12-23 00:07:00
7 35 49 2018-12-23 00:08:00
8 40 56 2018-12-23 00:09:00
9 45 63 2018-12-23 00:10:00
10 50 70 2018-12-23 00:11:00
Затем merge
этот фрейм данных с фреймом данных с 1 столбцом разницы во времени (от 0 до 55):
m1 <- merge(m0, data.frame(diff = seq(0, 55, 5)))
И, наконец, вычтите столбец разницы из столбца отметки времени, чтобы создать новые значения:
m1$t2 <- with(m1, t - diff)
> m1[c(1, 20, 40), ]
p1 p2 t diff t2
1 5 7 2018-12-23 00:02:00 0 2018-12-23 00:02:00
20 50 70 2018-12-23 00:11:00 5 2018-12-23 00:10:55
40 50 70 2018-12-23 00:11:00 15 2018-12-23 00:10:45
Извините, но это не дает желаемых результатов. Тем не менее, спасибо за ваш вклад.
@ jay2020 Это тот же результат, что и другой, за исключением имен столбцов, порядка и назначения местного часового пояса. Это также устраняет проблему, о которой вы упоминаете в своих комментариях к другому.
Сочетание смазывать, padr
и тидир доставит вас туда. Я использую lubridate
для форматирования даты, чтобы она хорошо воспроизводилась с padr
. padr
добавляет отсутствующие значения даты и времени во фрейм данных. Наконец, используя функцию tidyr fill
, чтобы заполнить пустые значения. Обратите внимание, что по умолчанию padr
имеет разрыв на 1 миллион строк для защиты памяти, но вы можете установить это значение выше.
library(lubridate)
library(padr)
library(tidyr)
df1 <- data.frame(ymd_hms(t0), p1, p2)
df1 <- pad(df1, interval = "5 secs", start_val = lubridate::ymd_hms("2018-12-23 00:01:05"))
df1 <- fill(df1, p1, p2, .direction = "up")
head(df1, 15)
t0 p1 p2
1 2018-12-23 00:01:05 5 7
2 2018-12-23 00:01:10 5 7
3 2018-12-23 00:01:15 5 7
4 2018-12-23 00:01:20 5 7
5 2018-12-23 00:01:25 5 7
6 2018-12-23 00:01:30 5 7
7 2018-12-23 00:01:35 5 7
8 2018-12-23 00:01:40 5 7
9 2018-12-23 00:01:45 5 7
10 2018-12-23 00:01:50 5 7
11 2018-12-23 00:01:55 5 7
12 2018-12-23 00:02:00 5 7
13 2018-12-23 00:02:05 10 14
14 2018-12-23 00:02:10 10 14
15 2018-12-23 00:02:15 10 14
Большое спасибо. Это то, что я искал. Однако в исходных данных отсутствуют отметки времени, которые я не хочу заполнять. Например, вы можете думать об этом как о после 2018-12-23 00:02:00, 2018-12-23 00:03 : 00, 2018-12-23 00:05:00, где 00:04 мин. Его нет по какой-то причине. Есть ли способ обойти эту проблему?
Итак, вместо того, чтобы генерировать все 5-секундные интервалы с использованием функции pad из первой временной точки, делать 11 5-секундных интервалов над каждой точкой данных, которую я имею?
@ jay2020, в этом случае слияния из jdobres или решения от eddi должны работать, поскольку они не объединяются с данными, которых нет. padr заполняет все недостающие данные. Теперь вы можете удалить все отсутствующие значения. Но это может свести на нет цель попытки ускорить процесс. Учитывая скорость, я бы сказал, что ответ Эдди будет лучшим.
Поскольку вы отметили это data.table
:
library(data.table)
dt = as.data.table(m0, keep = T)[, rn := as.POSIXct(rn)]
dt[.(rep(rn, each = 12) - seq(0, 55, 5)), on = 'rn', roll = -Inf][order(rn)]
# rn p1 p2
# 1: 2018-12-23 00:01:05 5 7
# 2: 2018-12-23 00:01:10 5 7
# 3: 2018-12-23 00:01:15 5 7
# 4: 2018-12-23 00:01:20 5 7
# 5: 2018-12-23 00:01:25 5 7
# ---
#116: 2018-12-23 00:10:40 50 70
#117: 2018-12-23 00:10:45 50 70
#118: 2018-12-23 00:10:50 50 70
#119: 2018-12-23 00:10:55 50 70
#120: 2018-12-23 00:11:00 50 70
Мне действительно нужно изучить и использовать data.table, спасибо, это так мощно
Базовый способ:
m0 <- as.data.frame(m0)
time <- lapply(as.POSIXct(rownames(m0)), seq, by = "-5 sec", len = 12)
m1 <- cbind(TIME = Reduce(c, time), m0[rep(seq_len(nrow(m0)), each = 12), ])
row.names(m1) <- NULL
head(m1)
# TIME p1 p2
# 1 2018-12-23 00:02:00 5 7
# 2 2018-12-23 00:01:55 5 7
# 3 2018-12-23 00:01:50 5 7
# 4 2018-12-23 00:01:45 5 7
# 5 2018-12-23 00:01:40 5 7
# 6 2018-12-23 00:01:35 5 7
Примечание: Переменная TIME
на выходе инвертирована.
Вот общее решение xts, которое должно работать для параметров, отличных от тех, которые вы указали в своем вопросе.
# convert m0 to xts
x0 <- as.xts(m0)
# create empty xts object with observations at all time points you want
nobs <- 11
nsec <- 5
y0 <- xts(, index(x0) - rep(seq_len(nobs) * nsec, each = nrow(x0)))
# merge data with desired index observations
new0 <- merge(x0, y0)
# carry the current value backward
new0 <- na.locf(new0, fromLast = TRUE)
head(new0, 20)
# p1 p2
# 2018-12-23 00:01:05 5 7
# 2018-12-23 00:01:10 5 7
# 2018-12-23 00:01:15 5 7
# 2018-12-23 00:01:20 5 7
# 2018-12-23 00:01:25 5 7
# 2018-12-23 00:01:30 5 7
# 2018-12-23 00:01:35 5 7
# 2018-12-23 00:01:40 5 7
# 2018-12-23 00:01:45 5 7
# 2018-12-23 00:01:50 5 7
# 2018-12-23 00:01:55 5 7
# 2018-12-23 00:02:00 5 7
# 2018-12-23 00:02:05 10 14
# 2018-12-23 00:02:10 10 14
# 2018-12-23 00:02:15 10 14
# 2018-12-23 00:02:20 10 14
# 2018-12-23 00:02:25 10 14
# 2018-12-23 00:02:30 10 14
# 2018-12-23 00:02:35 10 14
# 2018-12-23 00:02:40 10 14
Помимо вопроса, как этого добиться: а как насчет эффективности? Вы говорите, что перебор каждой строки занимает слишком много времени, поскольку у вас уже есть более 1 миллиона строк. Теперь добавление 11 строк на строку дает примерно 12 миллионов строк. Следовательно, не было бы более разумным иметь код, «использующий» эти данные для «подделки» дополнительных 11 строк при их фактическом использовании, или полностью изменить этот код? Я имею в виду - добавляя 11 строк, вы не Создайте никаких данных. Вы просто его раздуваете.