给定y轴上的缩放和x轴上的平移(t)的参数,当目的是最大化曲线叠加(不是最小化距离)时,如何缩放和对齐两条不重合的曲线?< / p>
正如@DWin所指出的,这可以改名为“如何与R完美地玩俄罗斯方块”,尽管它的应用程度远远超过了赢得俄罗斯方块游戏。
此问题的变体可能涉及任意数量的刚体变换(旋转,平移和缩放)。
给出曲线1
curve1<-data.frame(x=c(1,1,2,2,3),
y=c(9,6,6,3,3))
with(curve1, plot(x=x, y=y, type="l", xlim=c(0,10), ylim=c(0,10)))
和曲线2
curve2<-data.frame(x=c(4,5,5,6,6,7),
y=c(2,2,1,1,2,3))
with(curve2, plot(x=x, y=y, type="l", xlim=c(0,10), ylim=c(0,10)))
我希望找到最大化两条曲线之间叠加的s和t。
理想情况下,该方法将在R中使用optim。
在这个组成的例子中,t = 3且s = 1/3,所以
t=3
s=1/3
with(curve2, plot(x=x, y=y, type="l", xlim=c(0,10), ylim=c(0,10)))
with(curve1, lines(x=x+t, y=y*s, col="red"))
注意,为了获得这样的拟合,可以具有共识的区域必须具有比不能叠加的区域更高的参数化权重,并且共识区域越大,权重越高。
我一直在探索的路径:
使用最大似然的方法的加分点(假设错误的正态分布)。
答案 0 :(得分:5)
当曲线1在y轴上缩放一个因子“tfac”并在x轴上移动量“s”时,这将返回各点之间的距离:
as.matrix( dist( rbind(as.matrix(curve2),
( matrix(c(rep(s, 5), rep(1,5)), ncol=2) + # x-shift matrix
as.matrix(curve1) ) %*%
matrix(c( 1, 0, 0, tfac),ncol=2) ) ) # the y-scaling matrix
)[
# better not to use 't' as a variable name
-(1:5), -(6:11)] # easier to return the relevant distances when in matrix
将它放在一个最小化的函数中应该是一件简单的事情:
dfunc <- function(C1, C2, s, tfac) { sum( .... ) }
我并不完全确定这会返回您期望的结果,因为您所暗示的目标函数可能不是距离的总和。您可能需要转向整数编程方法。优化CRAN任务视图是在R中查找这些方法的好地方。我认为如果出现此问题可能会将“s”值四舍五入并仅缩放到最接近的2的幂。
dfunc <- function(param, D1=curve1, D2=curve2) {
sum( as.matrix(dist(
rbind(as.matrix(D2),
( matrix(c(rep(param[1], 5), rep(1,5)), ncol=2) +
as.matrix(D1) ) %*%
matrix(c(1,0,0,param[2]),ncol=2) ) ) )[-(1:5), -(6:11)])}
optim(c(1,1), dfunc)
#$par
$[1] 3.3733977 0.2243866
# trimmed output
使用这些值可获得以下叠加:
因此,我可能会尝试s = 3,tfac = 0.25。 (我看到回头看,我把t和s的角色从你要求的转换开来。抱歉。)
答案 1 :(得分:4)
好的,这是尝试解决方案。
基本诀窍是:我们 rasterise 两条曲线,然后我们可以逐个瓦片进行曲线比较。这似乎是比较曲线叠加的一种相当合理的方法,至少。为了鼓励优化者接近曲线,我们还引入了一种损失,使得曲线对另一条曲线的距离太大。
不保证这适用于更复杂的曲线和变换,但这至少是一个想法。
curve2<-data.frame(x=c(4,5,5,6,6,7),
y=c(2,2,1,1,2,3))
fillin <- function(ax, ay, bx, by, scaling= 10, steps= 100) floor(cbind(seq(from = ax, to = bx, len = steps), seq(from = ay, to = by, len = steps)) * scaling)
Bmat <- matrix(0, 100, 100)
for (i in 2:nrow(curve2)){
Bmat[fillin (curve2[i-1,1], curve2[i-1,2], curve2[i,1], curve2[i,2])] =1
}
Bmat.orig = Bmat
Bmat = Bmat.orig
#construct utility function based on
#manhattan distances to closest point?
shift = function(mat, offset){
mat0 = array(0, dim = dim(mat)+2)
mat0[1:nrow(mat) +1+ offset[1] , 1:ncol(mat) + 1+offset[2]] = mat
return(mat0[1:nrow(mat) + 1, 1:ncol(mat) + 1])
}
for (i in 1:100){
Bm = (Bmat != 0)
Btmp1 = shift(Bm, c(1,0))
Btmp2 = shift(Bm, c(-1,0))
Btmp3 = shift(Bm, c(0,1))
Btmp4 = shift(Bm, c(0,-1))
Bmat = Bmat + pmax(Bm ,Btmp1, Btmp2, Btmp3, Btmp4)/i
}
Bmat2 = replace(Bmat, Bmat == max(Bmat), max(Bmat) + 10)
#construct and compare rasterised versions
getcurve = function(trans = c(0,1), curve=data.frame(x=c(1,1,2,2,3) ,
y=c(9,6,6,3,3) ), Bmat = Bmat2){
Amat = array(0, dim = dim(Bmat))
curve[,1] = curve[,1] + trans[1]
curve[,2] = curve[,2] * trans[2]
for (i in 2:nrow(curve)){
fillin (curve[i-1,1], curve[i-1,2], curve[i,1], curve[i,2]) -> ind
if (min(ind) < 1 || max(ind) > nrow(Bmat)) return( array(-1, dim= dim(Bmat)))
Amat[ind] =1
}
Amat = (Amat - mean(Amat))/sd(as.vector(Amat))
Amat
}
compcurve = function(trans = c(0,1), curve=data.frame(x=c(1,1,2,2,3) ,
y=c(9,6,6,3,3) ) , Bmat = Bmat2){
Amat = getcurve(trans, curve, Bmat)
-sum(Amat * Bmat)
}
#SANN seems to work for this, but is slow. Beware of finite differencing
# - criterion is non-smooth!
optim(c(0,1), compcurve, method = "SANN", Bmat = Bmat2) -> output
image(Bmat)
contour(getcurve(output$par), add = T)
结果:
也许不是太破旧了?
你可能不得不捏造光栅化的细节来解决其他问题。你可能想调整优化的方式。
一个“更聪明”的选择是要注意,对于最佳解决方案,可能的情况是至少有一对顶点是一致的。这可以为您提供更好的搜索策略。与曲线区域相比,光栅化方案的优势在于它可能对不同的变换和非图形更灵活(特别是,第一条曲线中的垂直线是一个问题。)您可以通过以下方式避免光栅化。适当的计算,但考虑到它让我头疼。
由于我们正在最大化一个标准,因此这是一种最大似然法。奇怪的是,我认为实际上不可能将这个问题用作使用正常错误的最大似然问题,因为正常错误意味着基于L2的标准,这将着名的不给你准确叠加。