#r #data.table #vectorization #rolling-computation
Вопрос:
Я уже несколько дней ищу ответ на этот вопрос. Я думаю, что я очень близок, но я не могу понять, как это сделать.
У меня есть таблица data.table с двумя такими столбцами:
df = data.table(a = c(8,3,6,12,15,21,4,5,1,32,13), b = c(12,3,1,66,4,7,32,6,76,2,11))
Я хотел бы получить наименьшие два значения и их индексы в скользящем четырехдневном окне. Rfast::nth, кажется, дает мне все, что мне нужно, за исключением того, что я не могу его векторизовать. Очевидно, я делаю что-то не так.
Мне нужно, чтобы результат выглядел следующим образом:
a b low lowIdx low2 low2Idx
1: 8 12 NA NA NA NA
2: 3 3 NA NA NA NA
3: 6 1 NA NA NA NA
4: 12 66 3 2 6 3
5: 15 4 3 1 6 2
6: 21 7 6 1 12 2
7: 4 32 4 4 12 1
8: 5 6 4 3 4 3
9: 1 76 1 4 4 2
10: 32 2 1 3 4 1
11: 13 11 1 2 5 1
Я попытался сделать это с помощью следующих различных форм:
n <- nrow(df)
df$low[4:n] <- Rfast::nth(df[(n-3):n]$a, 1)
df$lowIdx[4:n] <- Rfast::nth(df$a, 1, index.return = TRUE)
df$low2[4:n] <- Rfast::nth(df[(n-3):n]$a, 2)
df$low2Idx[4:n] <- Rfast::nth(df$a, 2, index.return = TRUE)
Я также пытался работать с frollapply, но безрезультатно.
Спасибо тебе, Пит
Комментарии:
1.
low2
иlow2Idx
являются вторым по величине значением и индексом, верно? Почему их значение в строке 8 одинаковое?2. Ронак, да, это верно, low2 и low2Idx являются вторым по величине значением и индексом. Спасибо всем вам за помощь!
3. Кроме того, в конечном итоге это будет против нескольких колов для 11 миллионов записей. Я сделаю несколько таймингов и сообщу, какой из них самый быстрый. Еще раз спасибо всем за помощь.
4.
Rfast
также естьcolnth
то, что вам нужно.
Ответ №1:
Библиотека runner
также помогает.
library(dplyr)
library(runner)
df %>% mutate(low = runner(x=a, k=4, f = function(x) ifelse(length(x) ==4, min(x), NA)),
lowIdx = runner(x = a, k =4, function(x) ifelse(length(x) ==4, which.min(x), NA)),
Low2 = runner(x=a, k=4, f = function(x) ifelse(length(x) ==4, sort(x)[2], NA)),
Low2Idx =runner(x=a, k=4, f = function(x) ifelse(length(x) ==4, order(x)[2], NA))
)
a b low lowIdx Low2 Low2Idx
1: 8 12 NA NA NA NA
2: 3 3 NA NA NA NA
3: 6 1 NA NA NA NA
4: 12 66 3 2 6 3
5: 15 4 3 1 6 2
6: 21 7 6 1 12 2
7: 4 32 4 4 12 1
8: 5 6 4 3 5 4
9: 1 76 1 4 4 2
10: 32 2 1 3 4 1
11: 13 11 1 2 5 1
Комментарии:
1. Я использовал это в своем коде. Я понимаю это немного лучше, и мне не приходилось иметь дело с разными временными рамками для дат.
Ответ №2:
С frollapply
помощью in data.table
вы можете сделать :
library(data.table)
cols <- c('low', 'lowIdx', 'low2', 'low2Idx')
n <- 4
df[, (cols) := .(frollapply(a, n, min),
frollapply(a, n, which.min),
frollapply(a, n, function(x) sort(x)[2]),
frollapply(a, n, function(x) order(x)[2]))]
df
# a b low lowIdx low2 low2Idx
# 1: 8 12 NA NA NA NA
# 2: 3 3 NA NA NA NA
# 3: 6 1 NA NA NA NA
# 4: 12 66 3 2 6 3
# 5: 15 4 3 1 6 2
# 6: 21 7 6 1 12 2
# 7: 4 32 4 4 12 1
# 8: 5 6 4 3 5 4
# 9: 1 76 1 4 4 2
#10: 32 2 1 3 4 1
#11: 13 11 1 2 5 1
Ответ №3:
Для простого примера, подобного вашему, я предлагаю использовать frollapply
. Для лучшего контроля над окном, особенно если у вас есть пробелы в столбце дат, я рекомендую runner. Дополнительную информацию смотрите в документации
df[, c('low', 'lowIdx', 'low2', 'low2Idx') := .(
min_run(a, k = 4, na_pad = TRUE),
runner(a, k = 4, function(x) ifelse(length(x) > 0, which.min(x), NA), na_pad = TRUE),
runner(a, k = 4, function(x) sort(x)[2], na_pad = TRUE),
runner(a, k = 4, function(x) order(x)[2], na_pad = TRUE)
)]
df
# a b low lowIdx low2 low2Idx
# 1: 8 12 NA NA NA NA
# 2: 3 3 NA NA NA NA
# 3: 6 1 NA NA NA NA
# 4: 12 66 3 2 6 3
# 5: 15 4 3 1 6 2
# 6: 21 7 6 1 12 2
# 7: 4 32 4 4 12 1
# 8: 5 6 4 3 5 4
# 9: 1 76 1 4 4 2
# 10: 32 2 1 3 4 1
# 11: 13 11 1 2 5 1
Комментарии:
1. Бегун — действительно полезный пакет. Ваш ответ очень похож на мой. На самом деле я фанат вашего пакета. 🙂