简体   繁体   English

R中两条曲线之间的插值

[英]interpolation between two curves in R

I have two curves of same count of points filled using approx function, for both x and y values separately for each curve. 我有两条使用近似函数填充相同点数的曲线,对于每条曲线分别对x和y值。 Both x and y axis values are logarithmic, so I convert back to normal decimal scale when approximating and interpolating. x轴和y轴都是对数的,因此在近似和插值时我会转换回正常的十进制比例。 Black and blue lines are original lines and the red one is interpolated in between. 黑色和蓝色线条是原始线条,红色线条插入其间。 As you can see the red line doesn't mimic the bend on the right side, since interpolation is performed based on assumption that each x and y pair are the closest. 如您所见,红线不会模仿右侧的弯曲,因为插值是基于每个x和y对最接近的假设来执行的。

Is there any way how to perform interpolation between curves in R based on the real closest points in between? 有没有什么方法可以根据两者之间的真实最近点在R中的曲线之间进行插值? Maybe there exists algorithms for that? 也许存在算法? Anything would be useful as I am not sure how it is called in mathematics. 任何东西都会有用,因为我不确定它是如何被称为数学的。

    base="ftp://cdsarc.u-strasbg.fr/pub/cats/J/A+A/508/355/ms/"
    setwd("~/Desktop")
    file1=paste(base,"z001y23_1.60.dat",sep="")
    file2=paste(base,"z001y23_1.70.dat",sep="")

    cols=c("no","age","logL","logTef", "grav","stage")
    ncol <- length(count.fields(file=file1, sep = ","))
    second=read.table(file=file1,fill=T, blank.lines.skip=F, skip=2, header=F, strip.white=T, col.names = paste("V", seq_len(ncol)))
    second$V.6<-second$V.23
    colnames(second) <-cols
    second$logL=as.numeric(second$logL)
    #performing some filtering of data here
    pos1=which(second$stage == "trgb")[1]
    second=second[1:pos1,]

    ncol <- length(count.fields(file=file2, sep = ","))
    first=read.table(file=file2,fill=T, blank.lines.skip=F, skip=2, header=F, strip.white=T, col.names = paste("V", seq_len(ncol)))
    first$V.6<-first$V.23
    colnames(first) <-cols
    #performing some filtering of data here
    pos2=which(first$stage == "trgb")[1]
    first=first[1:pos2,]

    #plotting data
    len=max(c(min(first[[4]]),min(second[[4]])))
    first=first[first[[4]]>len,]
    second=second[second[[4]]>len,]

    plot(second[[4]],second[[3]],t="l",xlim=rev(range(second[[4]])),xlab="x",ylab="y")
    lines(first[[4]],first[[3]],t="l",col="blue")
    n=max(c(length(second[[4]]),length(first[[4]])))
    #approximating missing points
    xf1 <- approx(10^second[[4]],n=n)
    yf1 <- approx(10^second[[3]],n=n)

    xf2 <- approx(10^first[[4]],n=n)
    yf2 <- approx(10^first[[3]],n=n)

    #calculating interpolated line
    ratio=2
    s1<-log10((xf1$y-xf2$y)/ratio+xf2$y)
    s2<-log10((yf1$y-yf2$y)/ratio+yf2$y)
    lines(s1,s2, col ="red")

在此输入图像描述

While not the ultimate answer, 虽然不是最终答案, here is something adapted from what I did a while ago for stream channel migration. 这里有一些改编自我之前为流媒体迁移所做的事情。 Note that those are usually not self crossing so your mileage may vary. 请注意,这些通常不会自行穿越,因此您的里程可能会有所不同 The whole idea is to calculate curvatures and use dynamic time warping to match extrema. 整个想法是计算曲率并使用动态时间扭曲来匹配极值。

Roughly it can be summarize like that: 粗略地说它可以这样总结:

  1. Parametrize both curves so L1 and L2 are vectors representing lengths from curve beginning to the index in question. 对两条曲线进行参数化,使L1和L2为表示从曲线开始到所讨论的索引的长度的向量。
  2. Calculate smooth.spline xsp1, ysp1, xsp2, ysp2 using L1 and L2 for x and y of each curve. 使用L1和L2计算smooth.spline xsp1,ysp1,xsp2,ysp2,用于每条曲线的x和y。 Pay attention to smoothing parameter as your curves look sharp at times. 注意平滑参数,因为曲线有时看起来很清晰。
  3. Explicitly get signed curvature for each smoothed line 为每条平滑线明确地获得带符号的曲率
  4. Use dtw to match peaks in curvatures of each smoothed line 使用dtw匹配每条平滑线的曲率峰值
  5. Use indices returned by dtw to establish mapping between curves 使用dtw返回的索引来建立曲线之间的映射
  6. ... ...
  7. PROFIT!!! 利润!!!

Note that dtw does not do miracles, and some experimentation would be necessary. 请注意,dtw不会创造奇迹,并且需要进行一些实验。

PS To save your time, I tried to use dtw directly on x & y without curvatures, but it didn't turn out nice as we'd want mapping for both coordinates at the same time. PS为了节省你的时间,我尝试在没有曲率的情况下直接在x&y上使用dtw,但它并没有变得很好,因为我们想要同时映射两个坐标。

EDIT 编辑

library(dtw)
df1 <- data.frame(x=first[[4]], y=first[[3]])
df2 <- data.frame(x=second[[4]], y=second[[3]])
measure <- function(df)
  within(df, m <- c(0, cumsum(diff(x)^2 + diff(y)^2)))
df1 <- measure(df1)
df2 <- measure(df2)

curvify <- function(df) {
  xsp <- with(df, smooth.spline(m, x))
  ysp <- with(df, smooth.spline(m, y))
  xx <- predict(xsp, df$m)$y
  yy <- predict(ysp, df$m)$y
  xp <- predict(xsp, df$m, deriv=1)$y
  xpp <- predict(xsp, df$m, deriv=2)$y
  yp <- predict(ysp, df$m, deriv=1)$y
  ypp <- predict(ysp, df$m, deriv=2)$y
  # http://en.wikipedia.org/wiki/Curvature#Signed_curvature
  within(df, c <- (xp*ypp - yp*xpp)/(xp^2 + yp^2)^1.5)
}

df1 <- curvify(df1)
df2 <- curvify(df2)

d <- dtw(df1$c, df2$c, keep=TRUE)
# plot(d, type='three')

xx <- ( df1$x[d$index1] + df2$x[d$index2] ) /2
yy <- ( df1$y[d$index1] + df2$y[d$index2] ) /2

lines(xx, yy, col="green")

在此输入图像描述

在此输入图像描述

EDIT 编辑

To interpolate with weights other than 1/2 使用1/2以外的权重进行插值

fr <- 1/3
xx <- df1$x[d$index1] * fr + df2$x[d$index2] * (1-fr)
yy <- df1$y[d$index1] * fr + df2$y[d$index2] * (1-fr)
lines(xx, yy, col="yellow")

fr <- 2/3
xx <- df1$x[d$index1] * fr + df2$x[d$index2] * (1-fr)
yy <- df1$y[d$index1] * fr + df2$y[d$index2] * (1-fr)
lines(xx, yy, col="brown")

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM