问题描述
我正在寻找一种有效的方法来查找与大数据集(a)相比最接近小数据集(x)的时间。结果必须是(a)长度的索引。我已经创建了一个功能很好的函数,但是,它对于大数据绝对是无用的,因为要花费几天的时间进行处理。
Here is my function: function(x,a,which = TRUE,na.rm=FALSE){
if("POSIXt" %in% class(x)) x <- as.numeric(x)
if("POSIXt" %in% class(a)) a <- as.numeric(a)
sapply(a,function(y) DescTools::Closest(x,y,na.rm=FALSE)[1])
}
x和a数据集都经过过滤,因此没有一致的时间间隔,但在相同的条件下进行了过滤。
向量a包含20 Hz的数据,长度为16020209,而x包含30 sec的数据,长度为26908。
任何建议都非常感谢!谢谢:)
解决方法
一个人可以使用data.table
中的滚动联接:
library(data.table)
set.seed(1) # reproduciblity on Stackoverflow
DF_A <- data.table(x = seq(-500,by = 0.5,length.out = 26908),idx = seq_len(26908))
DF_HZ <- data.table(x = round(runif(16020209,first(DF_A$x),last(DF_A$x)),3),idx_hz = seq_len(16020209))
DF_HZ[,x_hz := x + 0] # so we can check
DF_A[,x_a := x + 0] # so we can check
setkey(DF_A,x)
setkey(DF_HZ,x)
# The order(idx_hz) returns the result in the same order as
# DF_HZ but it is not necessary to match joins.
DF_A[DF_HZ,roll = "nearest"][order(idx_hz)]
#> x idx x_a idx_hz x_hz
#> 1: 3072.021 7145 3072.0 1 3072.021
#> 2: 4506.369 10014 4506.5 2 4506.369
#> 3: 7206.883 15415 7207.0 3 7206.883
#> 4: 11718.574 24438 11718.5 4 11718.574
#> 5: 2213.328 5428 2213.5 5 2213.328
#> ---
#> 16020205: 10517.477 22036 10517.5 16020205 10517.477
#> 16020206: 11407.776 23817 11408.0 16020206 11407.776
#> 16020207: 12051.919 25105 12052.0 16020207 12051.919
#> 16020208: 3482.463 7966 3482.5 16020208 3482.463
#> 16020209: 817.366 2636 817.5 16020209 817.366
由reprex package(v0.3.0)于2020-11-11创建
在我的计算机上,上述操作(不包括虚拟数据的创建)大约需要3 s。
,由于第二个df很小,因此我将使用类似SQL完全连接的方式执行此任务-尽管这取决于您的数据大小和内存。这是一个包含测试数据的简单示例:
library(dplyr)
# demo tibbles
tab1 <- tibble::tribble(
~time_1,~VALUE_1,"2020-11-01",268L,"2020-11-02",479L,"2020-11-03",345L,"2020-11-04",567L,"2020-11-05",567L) %>%
dplyr::mutate(time_1 = as.Date(time_1))
tab2 <- tibble::tribble(
~time_2,~VALUE_2,479L) %>%
dplyr::mutate(time_2 = as.Date(time_2))
# calculations
tab1 %>%
dplyr::mutate(ID = dplyr::row_number()) %>% # Build ID from row number
dplyr::full_join(tab2,by = character()) %>%
dplyr::mutate(DIF = abs(time_1 - time_2)) %>%
dplyr::group_by(ID) %>%
dplyr::slice_min(order_by = DIF,n = 1)
time_1 VALUE_1 ID time_2 VALUE_2 DIF
<date> <int> <int> <date> <int> <drtn>
1 2020-11-01 268 1 2020-11-01 268 0 days
2 2020-11-02 479 2 2020-11-02 479 0 days
3 2020-11-03 345 3 2020-11-02 479 1 days
4 2020-11-04 567 4 2020-11-02 479 2 days
5 2020-11-05 567 5 2020-11-02 479 3 days
如果发现大小有问题,则将大data.frame拆分为较小的一次,然后循环运行。在这种情况下,并行处理将是一个不错的选择,因为通过拆分大型DF计算可以独立运行。