该问题询问如何确定以规则但不同的时间间隔对一个时间序列(“扩展”)滞后于另一个时间序列(“体积”)的数量。
如图所示,在这种情况下,两个系列都表现出合理的连续行为。这意味着(1)可能需要很少或不需要初始平滑,并且(2)重采样可以像线性或二次插值一样简单。由于平滑度,二次方可能会稍好一些。 重新采样后,通过最大化互相关来找到滞后,如线程所示,对于两个偏移采样数据系列,它们之间的偏移的最佳估计是什么?。
为了说明,我们可以使用问题中提供的数据,R
用于伪代码。让我们从基本功能,互相关和重采样开始:
cor.cross <- function(x0, y0, i=0) {
#
# Sample autocorrelation at (integral) lag `i`:
# Positive `i` compares future values of `x` to present values of `y`';
# negative `i` compares past values of `x` to present values of `y`.
#
if (i < 0) {x<-y0; y<-x0; i<- -i}
else {x<-x0; y<-y0}
n <- length(x)
cor(x[(i+1):n], y[1:(n-i)], use="complete.obs")
}
这是一个粗略的算法:基于FFT的计算会更快。但是对于这些数据(涉及约4000个值)来说已经足够了。
resample <- function(x,t) {
#
# Resample time series `x`, assumed to have unit time intervals, at time `t`.
# Uses quadratic interpolation.
#
n <- length(x)
if (n < 3) stop("First argument to resample is too short; need 3 elements.")
i <- median(c(2, floor(t+1/2), n-1)) # Clamp `i` to the range 2..n-1
u <- t-i
x[i-1]*u*(u-1)/2 - x[i]*(u+1)*(u-1) + x[i+1]*u*(u+1)/2
}
我将数据下载为以逗号分隔的CSV文件,并剥离了其标题。(标头给R带来了一些我不希望诊断的问题。)
data <- read.table("f:/temp/a.csv", header=FALSE, sep=",",
col.names=c("Sample","Time32Hz","Expansion","Time100Hz","Volume"))
注意: 此解决方案假定每个系列的数据均按时间顺序排列,且两个之间都没有间隔。 这样,它就可以将值中的索引用作时间的代理,并通过时间采样频率缩放这些索引,以将其转换为时间。
事实证明,这些仪器中的一个或两个都随时间漂移一些。最好在继续操作之前消除这种趋势。另外,由于结尾处的音量信号逐渐变细,因此我们应将其剪切掉。
n.clip <- 350 # Number of terminal volume values to eliminate
n <- length(data$Volume) - n.clip
indexes <- 1:n
v <- residuals(lm(data$Volume[indexes] ~ indexes))
expansion <- residuals(lm(data$Expansion[indexes] ~ indexes)
我对频率较低的序列进行重新采样,以便从结果中获得最高精度。
e.frequency <- 32 # Herz
v.frequency <- 100 # Herz
e <- sapply(1:length(v), function(t) resample(expansion, e.frequency*t/v.frequency))
现在可以计算互相关了-为了提高效率,我们只搜索一个合理的滞后窗口-并且可以确定找到最大值的滞后。
lag.max <- 5 # Seconds
lag.min <- -2 # Seconds (use 0 if expansion must lag volume)
time.range <- (lag.min*v.frequency):(lag.max*v.frequency)
data.cor <- sapply(time.range, function(i) cor.cross(e, v, i))
i <- time.range[which.max(data.cor)]
print(paste("Expansion lags volume by", i / v.frequency, "seconds."))
输出告诉我们,扩展使音量滞后1.85秒。(如果未裁剪最后3.5秒的数据,则输出将为1.84秒。)
最好以几种方式检查所有内容,最好是目视检查。首先,互相关函数:
plot(time.range * (1/v.frequency), data.cor, type="l", lwd=2,
xlab="Lag (seconds)", ylab="Correlation")
points(i * (1/v.frequency), max(data.cor), col="Red", cex=2.5)
接下来,让我们及时记录这两个系列,并将它们绘制在相同的轴上。
normalize <- function(x) {
#
# Normalize vector `x` to the range 0..1.
#
x.max <- max(x); x.min <- min(x); dx <- x.max - x.min
if (dx==0) dx <- 1
(x-x.min) / dx
}
times <- (1:(n-i))* (1/v.frequency)
plot(times, normalize(e)[(i+1):n], type="l", lwd=2,
xlab="Time of volume measurement, seconds", ylab="Normalized values (volume is red)")
lines(times, normalize(v)[1:(n-i)], col="Red", lwd=2)
看起来不错! 不过,我们可以通过散点图更好地了解注册质量。我会根据时间改变颜色以显示进度。
colors <- hsv(1:(n-i)/(n-i+1), .8, .8)
plot(e[(i+1):n], v[1:(n-i)], col=colors, cex = 0.7,
xlab="Expansion (lagged)", ylab="Volume")
我们正在寻找沿着一条线来回追踪的点:变化的点反映了体积扩展的时间滞后响应中的非线性。尽管有一些变化,但它们很小。然而,这些变化如何随时间变化可能具有某些生理意义。关于统计的奇妙之处,尤其是其探索性和可视性方面,在于它如何趋向于产生好的问题和想法以及有用的答案。