R:根据一天中的时间有效地对数据框进行子集化
Posted
技术标签:
【中文标题】R:根据一天中的时间有效地对数据框进行子集化【英文标题】:R: Efficiently subsetting dataframe based on time of day 【发布时间】:2012-01-23 03:52:47 【问题描述】:我有一个大型 (150,000x7) 数据框,打算用于对金融市场进行回溯测试和实时分析。这些数据以 5 分钟的间隔代表投资工具的状况(尽管确实存在漏洞)。它看起来像这样(但更长):
pTime Time Price M1 M2 M3 M4
1 1212108300 20:45:00 1.5518 12.21849 -0.37125 4.50549 -31.00559
2 1212108900 20:55:00 1.5516 11.75350 -0.81792 -1.53846 -32.12291
3 1212109200 21:00:00 1.5512 10.75070 -1.47438 -8.24176 -34.35754
4 1212109500 21:05:00 1.5514 10.23529 -1.06044 -8.46154 -33.24022
5 1212109800 21:10:00 1.5514 9.74790 -1.02759 -10.21978 -33.24022
6 1212110100 21:15:00 1.5513 9.31092 -1.17076 -11.97802 -33.79888
7 1212110400 21:20:00 1.5512 8.84034 -1.28428 -13.62637 -34.35754
8 1212110700 21:25:00 1.5509 8.07843 -1.63715 -18.24176 -36.03352
9 1212111000 21:30:00 1.5509 7.39496 -1.49198 -20.65934 -36.03352
10 1212111300 21:35:00 1.5512 7.65266 -1.03717 -18.57143 -34.35754
数据已预加载到 R 中,但在我的回测期间,我需要按两个标准对其进行子集化:
第一个标准是滑动窗口,以避免窥视未来。窗口必须是这样的,回测中每个新的 5 分钟间隔将整个窗口移动到未来 5 分钟。这部分我可以这样做:
require(zoo)
zooser <- zoo(x=tser$Close, order.by=as.POSIXct(tser$pTime, origin="1970-01-01"))
window(zooser, start=A, end=B)
第二个条件是另一个滑动窗口,但它会在任何一天在time of day
中滑动,并且只包含在输入时间N
分钟内的那些条目。
示例:如果窗口大小为2 hours
,输入时间为12:00PM
,则窗口必须包含10:00AM
和2:00PM
之间的所有Time
行
这是我无法弄清楚的部分。
编辑:我的数据中有漏洞,连续两行可能相隔 5 分钟以上。数据看起来像这样(非常放大)
随着窗口在这些间隙中移动,窗口内的点数应有所不同。
以下是我的 mysql 代码,它可以在 R 中做我想做的事情(相同的表结构):
SET @qTime = Time(FROM_UNIXTIME(SAMP_endTime));
SET @inc = -1;
INSERT INTO MetIndListBuys (pTime,ArrayPos,M1,M2,M3,M4)
SELECT pTime,@inc:=@inc+1,M1,M2,M3,M4
FROM mergebuys USE INDEX (`y`) WHERE pTime BETWEEN SAMP_startTime AND SAMP_endTime
AND TIME_TO_SEC(TIMEDIFF(Time,@qTime))/3600 BETWEEN 0-HourSpan AND HourSpan
;
【问题讨论】:
那些索引值远不及下午 12:00,至少在我的时区。 是的,你是对的......我只是随机选择了12:00PM
我猜这是个坏例子。
【参考方案1】:
假设您的目标时间 t0 与 pTime:自纪元以来的秒数相同。然后 t0 - pTime =(两者之间的纪元以来的天数差异)+(剩余秒数的差异)。取 t0 - pTime %% (每天的秒数)会给我们留下时钟算术中的秒数差异(如果差异为负数,则环绕)。这暗示了以下功能:
SecondsPerDay <- 24 * 60 * 60
within <- function(d, t0Sec, wMin)
diff <- (d$pTime - t0Sec) %% SecondsPerDay
wSec <- 60 * wMin
return(d[diff < wSec | diff > (SecondsPerDay - wSec), ])
【讨论】:
我正在尝试理解这个解决方案,但我是 R 新手 - 你能解释一下return
声明中发生了什么吗?
对于布尔值 x 的向量,d[x, ] 返回一个新的 data.frame,其中只有 x 为 TRUE 的 d 行。 “|”是向量“OR”运算符,如果至少一个参数的第 i 个条目为 TRUE,则其结果中的第 i 个条目为 TRUE。例如,如果“diff[i] (SecondsPerDay - wSec)”,则“diff (SecondsPerDay - wSec)”中的第 i 个条目将为 TRUE。 (由于 wSec 的长度小于 diff 的长度,因此在执行“
特别是,diff > (SecondsPerDay - wSec) 处理差异实际上是“负”但被时钟算法包围的情况。
知道了!快速、简单、直观。非常感谢!【参考方案2】:
1) 如果DF
是问题中显示的数据框,则按照您所做的那样从中创建一个动物园对象,并将其拆分为几天,给出zs
。然后lapply
你的函数f
到每个组件中的每个连续的w
点集(即每天)。例如,如果您想一次将函数应用于 2 小时的数据,并且您的数据是定期间隔 5 分钟的数据,则 w = 24(因为两小时中有 24 个五分钟周期)。在这种情况下,f
每次调用时都会以矩阵形式传递 24 行数据。此外,align
已设置为下面的"right"
,但也可以设置为align="center"
,并且提供ix
的条件可以更改为双面等。有关rollapply
的更多信息,请参阅:?rollapply
library(zoo)
z <- zoo(DF[-2], as.POSIXct(DF[,1], origin = "1970-01-01"))
w <- 3 # replace this with 24 to handle two hours at a time with five min data
f <- function(x)
tt <- x[, 1]
ix <- tt[w] - tt <= w * 5 * 60 # RHS converts w to seconds
x <- x[ix, -1]
sum(x) # replace sum with your function
out <- rollapply(z, w, f, by.column = FALSE, align = "right")
使用问题中的数据框我们得到:
> out
$`2008-05-30`
2008-05-30 02:00:00 2008-05-30 02:05:00 2008-05-30 02:10:00 2008-05-30 02:15:00
-66.04703 -83.92148 -95.93558 -100.24924
2008-05-30 02:20:00 2008-05-30 02:25:00 2008-05-30 02:30:00 2008-05-30 02:35:00
-108.15038 -121.24519 -134.39873 -140.28436
对了,请务必阅读this post。
2) 这可以交替执行如下,其中w
和f
如上所述:
n <- nrow(DF)
m <- as.matrix(DF[-2])
sapply(w:n, function(i) m <- m[seq(length = w, to = i), ]; f(m) )
如果需要,将 sapply
替换为 lapply
。此外,这可能看起来比第一个解决方案更短,但是一旦您添加代码来定义 f
和 w
(出现在第一个而不是第二个),它并没有太大的不同。
如果白天没有空洞,而只有几天之间的空洞,那么这些解决方案可以简化。
【讨论】:
感谢您的回答(和链接!)问题是我的数据没有定期间隔 - 其中可能(并且应该有)孔。我很抱歉最初没有说清楚。我编辑了我的帖子来代表这一点。 这些漏洞只是几天之间的时间还是几天之间也有漏洞?从图中看来,漏洞似乎只在几天之间,如果是这种情况,那么上面的代码应该可以工作。 我还修改了解决方案,即使白天有漏洞也能正常工作。 现在也有漏洞。非常感谢您的回答,我是 R 新手,所以明天我将不得不仔细考虑。 我做了一些简化。由于漏洞可以在任何地方,因此将其分成数天是没有意义的,因为f
中的额外代码也处理了这个问题,因此拆分已被删除。 f
中的 tail
也被简化了。以上是关于R:根据一天中的时间有效地对数据框进行子集化的主要内容,如果未能解决你的问题,请参考以下文章