我需要一些关于dplyr的帮助。
我有两个数据框 - 一个大的,里面有几个时间序列A,B, ...(LargeDF),还有一个第二个(Categories),包含左右边界的时间间隔。
我想向LargeDF添加另一列,标记为leftBoundary,其中包含适当的边界值,如下所示:
因此,如果我将所有内容转移到更大的值(例如,在下面的示例中
我想向LargeDF添加另一列,标记为leftBoundary,其中包含适当的边界值,如下所示:
LargeDF
ts timestamp signal # left_boundary
1 A 0.3209338 10.43279 # 0
2 A 1.4791524 10.34295 # 1
3 A 2.6007494 10.71601 # 2
并且
Categories
ts left right
1 A 0 1
2 A 1 2
3 A 2 3
我想分享的代码是:
LargeDF %>%
group_by(ts) %>%
do(myFUN(., Categories))
# calls this ...
myFUN <- function(Large, Categ) {
CategTS <- Categ %>%
filter(ts == Large[1, "ts"][[1]])
Large %>%
group_by(timestamp) %>% # this is bothering me...
mutate(left_boundary = CategTS$left[CategTS$left < timestamp
& timestamp < CategTS$right])
}
但是对于大型时间序列来说,它非常慢。我真的想去掉 group_by(timestamp)
,因为它们在每个 ts
中都是唯一的。
有人看到更好的解决方案吗?这将不胜感激。
# Code for making the example data frames ...
library("dplyr")
n <- 10; series <- c("A", "B", "C")
LargeDF <- data.frame(
ts = rep(series, each = n)
, timestamp = runif(n*length(series), max = 4)
, signal = runif(n*length(series), min = 10, max = 11)
) %>% group_by(ts) %>% arrange(timestamp)
m <- 7
Categories <- data.frame(
ts = rep(series, each = m)
, left = rep(seq(1 : m) - 1, length(series))
, right = rep(seq(1 : m), length(series))
)
更新(data.table和我稍作修改的模拟)
所以,我首先尝试了@DavidArenburg的建议,在一个快速/脏模拟示例上,但遇到了一个问题,即一些时间戳被分成了两个区间。
> foverlaps(d, c, type="any", by.x = c("timestamp", "timestamp2"))
left right value timestamp timestamp2
1: 0.9 1.9 0.1885459 1 1
2: 0.9 1.9 0.0542375 2 2 # binned here
3: 1.9 2.9 0.0542375 2 2 # and here as well
13: 19.9 25.9 0.4579986 20 20
我后来了解到 minoverlap = 1L
是默认设置,并且意识到正常时间戳是 >> 1
。
> as.numeric(Sys.time())
[1] 1429022267
因此,如果我将所有内容转移到更大的值(例如,在下面的示例中
n <- 10
),一切都很好。 left right value timestamp timestamp2
1: 9 19 0.64971126 10 10
2: 19 29 0.75994751 20 20
3: 29 99 0.98276462 30 30
9: 199 259 0.89816165 200 200
使用我的真实数据,一切顺利进行,再次感谢。
## Code for my data.table example -----
n <- 1
d <- data.table( value = runif(9),
timestamp = c(1, 2, 3, 5, 7, 10, 15, 18, 20)*n,
timestamp2 = c(1, 2, 3, 5, 7, 10, 15, 18, 20)*n)
c <- data.table(left = c(0.9, 1.9, 2.9, 9.9, 19.9, 25.9)*n,
right = c(1.9, 2.9, 9.9, 19.9, 25.9, 33.9)*n)
setkey(c, left, right)
foverlaps(d, c, type="any", by.x = c("timestamp", "timestamp2"))
更新2(使用dplyr中的JOIN,然后FILTER)
我测试了@aosmith建议使用dplyr函数left_join()
创建一个(非常)大的数据框,然后再次使用filter()
进行过滤。很快,我就遇到了内存问题:
Error: std::bad_alloc
也许对于小型表格来说,这种方法是一个不错的选择 - 因为语法非常简洁易懂(但这再次取决于个人喜好)。在这种情况下,我会选择 data.table
解决方案。再次感谢所有的建议。
floor(timestamp)
吗? - talatleft_join(LargeDF, Categories) %>% filter(timestamp > left, timestamp < right)
。 - aosmith