2016-08-05 72 views
4

我正在R与xts时间系列工作。R xts - 重新采样不等时间步xts到等距时间序列

我有什么: 时间序列数据集具有不等间隔时间步骤。

我想获得: 用其值对应于重叠的时间步骤中的原始值的比例相等间隔的时间步骤的时间序列(见下例)。

例子:采用原始系列这样的:

sample_xts <- as.xts(read.zoo(text=' 
2016-07-01 00:00:20, 0.0 
2016-07-01 00:01:20, 60.0 
2016-07-01 00:01:50, 30.0 
2016-07-01 00:02:30, 40.0 
2016-07-01 00:04:20, 110.0 
2016-07-01 00:05:30, 140.0 
2016-07-01 00:06:00, 97.0 
2016-07-01 00:07:12, 144.0 
2016-07-01 00:08:09, 0.0 
', sep=',', index=1, tz='', format="%Y-%m-%d %H:%M:%S")) 
names(sample_xts) <- c('x') 

我想获得一个等距时间序列,看起来像这样:

      x 
2016-07-01 00:00:00, 0.0 
2016-07-01 00:01:00, 40.0 
2016-07-01 00:02:00, 60.0 
2016-07-01 00:03:00, 60.0 
2016-07-01 00:04:00, 60.0 
2016-07-01 00:05:00, 100.0 
2016-07-01 00:06:00, 157.0 
2016-07-01 00:07:00, 120.0 
2016-07-01 00:08:00, 24.0 
2016-07-01 00:09:00, 0.0 

注:

  • 某些原始时间步长小于新时间步长,而 其他人更大。
  • x的colSums保持不变(即621)。

这里是我用来创建上面的例子中(可能有助于说明我想要做什么)的草图: illustration of resampling

我想这不限于创建方法一个1分钟的时间步长系列,但通常是任何固定的时间步长。

我看了很多q/a在stackoverflow上,并尝试了很多不同的东西,但没有成功。

任何帮助将不胜感激!谢谢。

回答

1

下面是我用zoo写的一些代码 - 我还没有使用xts,所以我不知道是否可以应用相同的函数。希望有所帮助!

功能

下面的函数来计算,对于原始数据中的每个间隔,即以给定的时间间隔(注重叠分数:在下面所有的代码,变量名ta1ta2指一个给定的时间间隔的开始和结束(例如在每次需要作为输出相等的间隔),而tb1tb2指原始数据的(不相等)的间隔)的开始和结束:

frac.overlap <- function(ta1,ta2,tb1,tb2){ 
if(tb1 <= ta1 & tb2 >= ta2) { # Interval 2 starts earlier and ends later than interval 1 
    frac <- as.numeric(difftime(ta2,ta1,units="secs"))/as.numeric(difftime(tb2,tb1,units="secs")) 
} else if(tb1 >= ta1 & tb2 <= ta2) { # Interval 2 is fully contained within interval 1 
    frac <- 1 
} else if(tb1 <= ta1 & tb2 >= ta1) { # Interval 2 partly overlaps with interval 1 (starts earlier, ends earlier) 
    frac <- as.numeric(difftime(tb2,ta1,units="secs"))/as.numeric(difftime(tb2,tb1,units="secs")) 
} else if (tb1 <= ta2 & tb2 >= ta2){ # Interval 2 partly overlaps with interval 1 (starts later, ends later) 
    frac <- as.numeric(difftime(ta2,tb1,units="secs"))/as.numeric(difftime(tb2,tb1,units="secs")) 
     } else {        # No overlap 
      frac <- 0 
    } 

    return(frac) 
} 

下一个函数来确定与当前考虑的间隔ta1原始数据集重叠的记录 - ta2

check.overlap <- function(ta1,ta2,tb1,tb2){ 
ov <- vector("logical",4) 
ov[1] <- (tb1 <= ta1 & tb2 >= ta2) # Interval 2 starts earlier and ends later than interval 1 
ov[2] <- (tb1 >= ta1 & tb2 <= ta2) # Interval 2 is fully contained within interval 1 
ov[3] <- (tb1 <= ta1 & tb2 >= ta1) # Interval 2 partly overlaps with interval 1 (starts earlier, ends earlier) 
ov[4] <- (tb1 <= ta2 & tb2 >= ta2) # Interval 2 partly overlaps with interval 1 (starts later, ends later) 
return(as.logical(sum(ov))) # Gives TRUE if at least one element of ov is TRUE, otherwise FALSE 
} 

(注:这工作得很好,您所提供的样本数据,但在更大的数据集,我发现它过于缓慢。由于我编写的这段代码是用一个固定的时间步重新采样时间序列,所以我通常使用一个固定的时间间隔来完成这个步骤,这个过程要快得多。可能很容易修改代码(查看下一个函数的代码),以便根据原始数据的间隔加快此步骤。)

下一个函数使用前两个函数来计算间隔的重采样值ta1 - ta2

fracres <- function(tstart,interval,input){ 
# tstart: POSIX object 
# interval: length of interval in seconds 
# input: zoo object 

ta1 <- tstart 
ta2 <- tstart + interval 

# First, determine which records of the original data (input) overlap with the current 
# interval, to avoid going through the whole object at every iteration 
ind <- index(input) 
ind1 <- index(lag(input,-1)) 
recs <- which(sapply(1:length(ind),function(x) check.overlap(ta1,ta2,ind[x],ind1[x]))) 
#recs <- which(abs(as.numeric(difftime(ind,ta1,units="secs"))) < 601) 


# For each record overlapping with the current interval, return the fraction of the input data interval contained in the current interval 
if(length(recs) > 0){ 
    fracs <- sapply(1:length(recs), function(x) frac.overlap(ta1,ta2,ind[recs[x]],ind1[recs[x]])) 
    return(sum(coredata(input)[recs]*fracs)) 

} else { 
    return(0) 
} 
} 

(被注释掉的行显示如何获取相关记录,如果原来的和新的时间步长之间的最大时间差是已知的)

应用

首先,让我们在您的样本数据读取为zoo对象:

sample_zoo <- read.zoo(text=' 
2016-07-01 00:00:20, 0.0 
2016-07-01 00:01:20, 60.0 
2016-07-01 00:01:50, 30.0 
2016-07-01 00:02:30, 40.0 
2016-07-01 00:04:20, 110.0 
2016-07-01 00:05:30, 140.0 
2016-07-01 00:06:00, 97.0 
2016-07-01 00:07:12, 144.0 
2016-07-01 00:08:09, 0.0 
', sep=',', index=1, tz='', format="%Y-%m-%d %H:%M:%S") 

它看起来像你的数据集包含瞬时值(“在01:20x值60”)。由于我为汇总值编写了此代码,因此时间戳的含义不同(“起始于01:20的记录的值为60”)。为了纠正这一点,记录需要转移:

sample_zoo <- lag(sample_zoo,1) 

然后,我们定义对应所需的分辨率POSIXct对象序列:

time.out <- seq.POSIXt(from=as.POSIXct("2016-07-01"),to=(as.POSIXct("2016-07-01")+(60*9)),by="1 min") 

然后,我们可以应用功能fracres,描述以上:

data.out <- sapply(1:length(time.out), function(x) fracres(tstart=time.out[x],interval=60,input=sample_zoo)) 

索引和数据被组合到一个zoo对象:

zoo.out <- read.zoo(data.frame(time.out,data.out)) 

最后,时间序列又一步像以前那样移动,向相反的方向:

zoo.out <- lag(zoo.out,-1) 

2016-07-01 00:01:00 2016-07-01 00:02:00 2016-07-01 00:03:00 2016-07-01 00:04:00 2016-07-01 00:05:00 2016-07-01 00:06:00 2016-07-01 00:07:00 2016-07-01 00:08:00 2016-07-01 00:09:00 
      40     60     60     60     100     157     120     24     0 
+0

Thanks @ m.chips!最后在我的实时系列中尝试了这一点。完美的作品,但是,是的,正如你所指出的那样,即使是很短的系列,它也会变得“过于缓慢”。看起来,执行时间与系列的长度不成比例地增长 - 按指数或2^N。我的系列有30万到1万。观察灵感来自你的算法,我决定尝试别的。在下面的帖子中回答问题。 –

0

我终于决定去了“而循环路”这个和有下面创建了解决方案。它运行良好 - 速度不是很快,但执行时间似乎与时间序列的长度成正比。我用我在问题中发布的一个小例子对它进行了测试,其源代码时间序列具有330 000个观察值,目标序列的时间步长约为110 000个。

源系列和目标系列都可能具有不规则的时间步长。 结果序列的总和与源的总和相同。

性能:虽然速度不错,但我相信速度会更快。我想这是RCpp版本的一个明显候选者,对于长篇系列文章来说,这应该会更快。现在,这将为我做,如果/当我开始创建一个RCpp版本,我会在这里发布。

如果您有改进性能的建议,请发布!

谢谢!

sameEndTime <- function(i,j,src_index,dest_index){ 
    if(src_index[i] == dest_index[j]){ 
    TRUE 
    } else { 
    FALSE 
    } 
} 

wholeSourceStepIsWithinDestStep <- function(i,j,src_index,dest_index){ 
    if(dest_index[j-1] <= src_index[i-1] & src_index[i] <= dest_index[j]){ 
    TRUE 
    } else { 
    FALSE 
    } 
} 

wholeDestStepIsWithinSourceStep <- function(i,j,src_index,dest_index){ 
    if(src_index[i-1] <= dest_index[j-1] & dest_index[j] <= src_index[i]){ 
    TRUE 
    } else { 
    FALSE 
    } 
} 

onlyEndOfSourceStepIsWithinDestStep <- function(i,j,src_index,dest_index){ 
    if(src_index[i-1] < dest_index[j-1] & src_index[i] < dest_index[j] & src_index[i] > dest_index[j-1]){ 
    TRUE 
    } else { 
    FALSE 
    } 
} 

onlyStartOfSourceStepIsWithinDestStep <- function(i,j,src_index,dest_index){ 
    if(src_index[i-1] < dest_index[j] & src_index[i-1] > dest_index[j-1] & src_index[i] > dest_index[j]){ 
    TRUE 
    } else { 
    FALSE 
    } 
} 

resampleToDestTimeSteps <- function(src, dest){ 
    # src and dest are both xts with only one time series each 
    # src is the original series and 
    # dest holds the time steps of the final series 
    # 
    # NB: there is an issue with the very first time step 
    # (gets ignored in this version) 
    # 
    original_names <- names(src) 
    names(src) <- c("value") 
    names(dest) <- c("value") 
    dest$value <- dest$value*0.0 
    dest$value[is.na(dest$value)] <- 0.0 

    dest[1]$value = 0.0 

    for(k in 2:length(src)){ 
    src[k]$value <- src[k]$value/as.numeric(difftime(index(src[k]),index(src[k-1]),units="secs")) 
    } 
    # First value is NA due to lag at this point (we don't want that) 
    src$value[1] = 0.0 

    i = 2 # source timestep counter 
    j = 2 # destination timestep counter 

    src_index = index(src) 
    dest_index = index(dest) 

    src_length = length(src) 
    dest_length = length(dest) 

    # Make sure we start with an overlap 
    if(src_index[2] < dest_index[1]){ 
    while(src_index[i] < dest_index[1]){ 
     i = i + 1 
    } 
    } else if(dest_index[2] < src_index[1]){ 
    while(dest_index[j] < src_index[1]){ 
     j = j + 1 
    } 
    } 

    while(i <= src_length & j <= dest_length){ 
    if(wholeSourceStepIsWithinDestStep(i,j,src_index,dest_index)){ 
     dest[j]$value = dest[j]$value + as.numeric(src[i]$value)*as.numeric(difftime(src_index[i],src_index[i-1],units="secs")) 
     if(sameEndTime(i,j,src_index,dest_index)){ 
     j = j+1 
     } 
     i = i+1 
    } else if(wholeDestStepIsWithinSourceStep(i,j,src_index,dest_index)){ 
     dest[j]$value = dest[j]$value + as.numeric(src[i]$value)*as.numeric(difftime(dest_index[j],dest_index[j-1],units="secs")) 
     if(sameEndTime(i,j,src_index,dest_index)){ 
     i = i+1 
     } 
     j = j+1 
    } else if(onlyEndOfSourceStepIsWithinDestStep(i,j,src_index,dest_index)){ 
     dest[j]$value = dest[j]$value + as.numeric(src[i]$value)*as.numeric(difftime(src_index[i],dest_index[j-1],units="secs")) 
     i = i+1 
    } else if(onlyStartOfSourceStepIsWithinDestStep(i,j,src_index,dest_index)){ 
     diff_time = difftime(dest_index[j],src_index[i-1],units="secs") 
     dest[j]$value = dest[j]$value + as.numeric(src[i]$value)*as.numeric(diff_time) 
     j = j+1 
    } else { 
     print("======================================================") 
     print(paste0("i=",i,", j=",j)) 
     print(paste0("src_index[i] =",src_index[i])) 
     print(paste0("dest_index[j] =",dest_index[j])) 
     print(" ") 
     print(paste0("src_index[i-1] =",src_index[i-1])) 
     print(paste0("dest_index[j-1]=",dest_index[j-1])) 
     print("======================================================") 
     stop("This should never happen.") 
    } 
    } 
    names(dest) <- original_names 
    return(dest) 
} 
相关问题