【问题标题】:Efficient coding to make time increments 'finer' from minutes to seconds有效的编码使时间增量从几分钟到几秒钟“更精细”
【发布时间】:2019-05-23 18:32:40
【问题描述】:

我有一个以 1 分钟为增量的时间序列数据。我已经编写了一个代码,但是由于我拥有大量数据(超过 100 万行),循环遍历每一行所花费的时间太长了。数据如下所示:

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

我想通过在每分钟之前添加 11 行(55 秒)将这些数据转换为 5 秒的增量,该值从最新值继承。所以它会是这样的:

> 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

我希望找到一些方法来做到这一点,而无需使用循环并利用我不太熟悉的 和/或 中的有效代码。

我尝试使用基础 R 中的 ave 函数,但速度不够快。

【问题讨论】:

  • 除了如何实现这一点的问题:效率如何?你说,循环遍历每一行需要太长时间,因为你已经有超过 1M 行。现在每行添加 11 行会产生 12M 行。因此,让代码在实际使用时“使用”这些数据来“伪造”额外的 11 行或完全改变该代码,难道不是更明智的做法吗?我的意思是 - 通过添加 11 行,您不会创建任何数据。你只是膨胀它。

标签: xts data.table r loops data.table xts


【解决方案1】:

既然你用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谢谢你这太强大了
【解决方案2】:

这是在基础 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 除了列名、排序和分配本地时区外,这与另一个结果相同。它还解决了您在另一个 cmets 中提到的问题。
【解决方案3】:

padr 的组合将助您一臂之力。我使用lubridate 来格式化日期,所以它与padr 配合得很好。 padr 将缺失的日期时间值添加到数据框中。最后使用 tidyr 的 fill 函数来填充空值。请注意,默认情况下padr 有 100 万行的中断以保护内存,但您可以将此值设置得更高。

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 分钟。它失踪是有原因的。有没有办法解决这个问题?
  • 所以不是从第一个时间点开始使用 pad 函数生成所有 5 秒的间隔,而是在我拥有的每个数据点上方生成 11 个 5 秒的间隔?
  • @jay2020,在这种情况下,来自 jdobres 的合并或来自 eddi 的解决方案应该可以工作,因为它们不会加入不存在的数据。 padr 填充所有缺失的数据。现在您可以删除所有丢失的值。但这可能会破坏试图加快速度的目的。考虑到速度,我会说 eddi 的答案是最好的。
【解决方案4】:

基本方式:

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取反了。

【讨论】:

    【解决方案5】:

    这是一个通用的 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
    

    【讨论】:

      猜你喜欢
      • 2021-06-26
      • 1970-01-01
      • 2011-02-18
      • 2019-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-18
      相关资源
      最近更新 更多