如何在 R 中设置平滑的滞后?
How can I fit a smooth hysteresis in R?
我有一个应该适合滞后的测量值。出于可视化目的,我想绘制一条近似于滞后的线来帮助解释这种模式。
我使用下面的代码在下图中创建了一个示例。
我想要一个类似于绿色曲线的输出 - 但是我没有直接可用的数据,我不在乎它是否尖锐。
然而,大多数平滑函数(例如我用蓝色绘制的 smooth.spline
)不允许循环。我能找到的最接近的是来自 bezier
库 - 以红色绘制。在这里不太明显,但它会产生一个循环,但它不太适合(并给出一些警告并需要相当长的时间)。
你能推荐一个方法吗?
set.seed(12345)
up <- seq(0,1,length.out=100)^3
down <- sqrt(seq(1,0,length.out=100))
x <- c(seq(0,1,length.out=length(up)),
seq(1,0, length.out=length(down)))
data <- data.frame(x=x, y=c(up,down),
measuredx=x + rnorm(length(x))*0.01,
measuredy=c(up,down) + rnorm(length(up)+length(down))*0.03)
with(data,plot(measuredx,measuredy, type = "p"))
with(data,lines(x,y, col='green'))
sp <- with(data,smooth.spline(measuredx, measuredy))
with(sp, lines(x,y, col="blue"))
library(bezier)
bf <- bezierCurveFit(as.matrix(data[,c(1,3)]))
lines(bezier(t=seq(0, 1, length=500), p=bf$p), col="red", cex=0.25)
更新
事实证明我的实际问题略有不同我问另一个问题来反映我在问题中的实际问题:
set.seed(12345)
up <- seq(0,1,length.out=100)^3
down <- sqrt(seq(1,0,length.out=100))
x <- c(seq(0,1,length.out=length(up)),
seq(1,0, length.out=length(down)))
data <- data.frame(x=x, y=c(up,down),
measuredx=x + rnorm(length(x))*0.01,
measuredy=c(up,down) + rnorm(length(up)+length(down))*0.03)
不是直接在 data$measuredx
上平滑 data$measuredy
,而是通过针对时间戳变量对每个进行平滑来进行两次单独的平滑。然后结合来自两个平滑的拟合值。这是平滑闭合曲线或环路的一般方法。 (另见问答:Smoothing Continuous 2D Points)
t <- seq_len(nrow(data) + 1)
xs <- smooth.spline(t, c(data$measuredx, data$measuredx[1]))$y
ys <- smooth.spline(t, c(data$measuredy, data$measuredy[1]))$y
with(data, plot(measuredx, measuredy))
lines(xs, ys)
c(data$measuredx, data$measuredx[1])
例如只是为了保证vector中的最后一个值和第一个一致,这样就完成了一个循环。
左下角的曲线并不是真正闭合的,因为smooth.spline
做的是平滑而不是插值,所以即使我们保证数据向量完成一个循环,拟合的也可能不是闭合的一。一个实用的解决方法是使用加权回归,在此点上施加较大的权重以使其关闭。
t <- seq_len(nrow(data) + 1)
w <- rep(1, length(t)) ## initially identical weight everywhere
w[c(1, length(w))] <- 100000 ## give heavy weight
xs <- smooth.spline(t, c(data$measuredx, data$measuredx[1]), w)$y
ys <- smooth.spline(t, c(data$measuredy, data$measuredy[1]), w)$y
with(data, plot(measuredx, measuredy), col = 8)
lines(xs, ys, lwd = 2)
我有一个应该适合滞后的测量值。出于可视化目的,我想绘制一条近似于滞后的线来帮助解释这种模式。
我使用下面的代码在下图中创建了一个示例。
我想要一个类似于绿色曲线的输出 - 但是我没有直接可用的数据,我不在乎它是否尖锐。
然而,大多数平滑函数(例如我用蓝色绘制的 smooth.spline
)不允许循环。我能找到的最接近的是来自 bezier
库 - 以红色绘制。在这里不太明显,但它会产生一个循环,但它不太适合(并给出一些警告并需要相当长的时间)。
你能推荐一个方法吗?
set.seed(12345)
up <- seq(0,1,length.out=100)^3
down <- sqrt(seq(1,0,length.out=100))
x <- c(seq(0,1,length.out=length(up)),
seq(1,0, length.out=length(down)))
data <- data.frame(x=x, y=c(up,down),
measuredx=x + rnorm(length(x))*0.01,
measuredy=c(up,down) + rnorm(length(up)+length(down))*0.03)
with(data,plot(measuredx,measuredy, type = "p"))
with(data,lines(x,y, col='green'))
sp <- with(data,smooth.spline(measuredx, measuredy))
with(sp, lines(x,y, col="blue"))
library(bezier)
bf <- bezierCurveFit(as.matrix(data[,c(1,3)]))
lines(bezier(t=seq(0, 1, length=500), p=bf$p), col="red", cex=0.25)
更新
事实证明我的实际问题略有不同我问另一个问题来反映我在问题中的实际问题:
set.seed(12345)
up <- seq(0,1,length.out=100)^3
down <- sqrt(seq(1,0,length.out=100))
x <- c(seq(0,1,length.out=length(up)),
seq(1,0, length.out=length(down)))
data <- data.frame(x=x, y=c(up,down),
measuredx=x + rnorm(length(x))*0.01,
measuredy=c(up,down) + rnorm(length(up)+length(down))*0.03)
不是直接在 data$measuredx
上平滑 data$measuredy
,而是通过针对时间戳变量对每个进行平滑来进行两次单独的平滑。然后结合来自两个平滑的拟合值。这是平滑闭合曲线或环路的一般方法。 (另见问答:Smoothing Continuous 2D Points)
t <- seq_len(nrow(data) + 1)
xs <- smooth.spline(t, c(data$measuredx, data$measuredx[1]))$y
ys <- smooth.spline(t, c(data$measuredy, data$measuredy[1]))$y
with(data, plot(measuredx, measuredy))
lines(xs, ys)
c(data$measuredx, data$measuredx[1])
例如只是为了保证vector中的最后一个值和第一个一致,这样就完成了一个循环。
左下角的曲线并不是真正闭合的,因为smooth.spline
做的是平滑而不是插值,所以即使我们保证数据向量完成一个循环,拟合的也可能不是闭合的一。一个实用的解决方法是使用加权回归,在此点上施加较大的权重以使其关闭。
t <- seq_len(nrow(data) + 1)
w <- rep(1, length(t)) ## initially identical weight everywhere
w[c(1, length(w))] <- 100000 ## give heavy weight
xs <- smooth.spline(t, c(data$measuredx, data$measuredx[1]), w)$y
ys <- smooth.spline(t, c(data$measuredy, data$measuredy[1]), w)$y
with(data, plot(measuredx, measuredy), col = 8)
lines(xs, ys, lwd = 2)