Эффективное кодирование для более точного приращения времени от минут до секунд

У меня есть данные временного ряда с шагом в 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

Я надеюсь найти способ сделать это без использования цикла и с использованием эффективных кодов в и / или , с которыми я не слишком знаком.

Я пробовал использовать функцию ave из базы R, но она не работает достаточно быстро.

Помимо вопроса, как этого добиться: а как насчет эффективности? Вы говорите, что перебор каждой строки занимает слишком много времени, поскольку у вас уже есть более 1 миллиона строк. Теперь добавление 11 строк на строку дает примерно 12 миллионов строк. Следовательно, не было бы более разумным иметь код, «использующий» эти данные для «подделки» дополнительных 11 строк при их фактическом использовании, или полностью изменить этот код? Я имею в виду - добавляя 11 строк, вы не Создайте никаких данных. Вы просто его раздуваете.

Xenonite 22.01.2019 11:47
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
1
133
5

Ответы 5

Вот один из способов сделать это в базе 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 24.12.2018 18:44

@ jay2020 Это тот же результат, что и другой, за исключением имен столбцов, порядка и назначения местного часового пояса. Это также устраняет проблему, о которой вы упоминаете в своих комментариях к другому.

IceCreamToucan 24.12.2018 19:03

Сочетание , 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 мин. Его нет по какой-то причине. Есть ли способ обойти эту проблему?

jay2020 24.12.2018 18:51

Итак, вместо того, чтобы генерировать все 5-секундные интервалы с использованием функции pad из первой временной точки, делать 11 5-секундных интервалов над каждой точкой данных, которую я имею?

jay2020 24.12.2018 18:52

@ jay2020, в этом случае слияния из jdobres или решения от eddi должны работать, поскольку они не объединяются с данными, которых нет. padr заполняет все недостающие данные. Теперь вы можете удалить все отсутствующие значения. Но это может свести на нет цель попытки ускорить процесс. Учитывая скорость, я бы сказал, что ответ Эдди будет лучшим.

phiver 24.12.2018 19:31

Поскольку вы отметили это 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, спасибо, это так мощно

jay2020 24.12.2018 20:53

Базовый способ:

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

Другие вопросы по теме