【问题标题】:How can I identify the two smallest values (and indexes) rolling over a column in R?如何识别滚动 R 中的列的两个最小值(和索引)?
【发布时间】:2021-07-17 07:07:40
【问题描述】:

我这几天一直在寻找这个问题的答案。我想我已经很接近了,但我不知道该怎么做。

我有一个包含两列的 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,但无济于事。

谢谢你,皮特

【问题讨论】:

  • low2low2Idx 是第二低的值和索引,对吧?为什么它们在第 8 行的值是一样的?
  • Ronak,是的,没错,low2 和 low2Idx 是第二低的值和索引。谢谢大家的帮助!
  • 另外,这最终将针对 1100 万条记录的多个列。我会做一些计时并报告什么是最快的。再次感谢大家的帮助。
  • Rfast 也有 colnth 这就是你想要的。

标签: r data.table vectorization rolling-computation


【解决方案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

【讨论】:

  • 我在我的代码中使用了这个。我理解得更好一些,我不必处理日期的不同时间范围。
【解决方案2】:

data.table 中使用frollapply,您可以这样做:

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。更多信息请参见documentation

    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
    

    【讨论】:

    • Runner 真的是一个很有用的包。你的回答和我的很相似。其实我是你的包裹的粉丝。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-30
    • 2021-10-28
    • 2023-02-01
    • 2017-11-05
    • 1970-01-01
    • 2020-09-19
    相关资源
    最近更新 更多