【问题标题】:How to get the inverse of a linear interpolation in R如何在R中获得线性插值的逆
【发布时间】:2013-09-16 11:14:09
【问题描述】:

我针对这个问题尝试了许多解决方案,但找不到可靠的自动化解决方案。请在下面找到详细的自给自足的描述。

这些是数据: 数据.txt

x y
1 1
2 2
3 3
4 2
5 1

绘制为散点图:

t=read.table("data.txt",header=T)
plot(t$x,t$y,"l")

您会看到一个峰值,我现在的问题是:假设我对线性插值感到满意,那么“曲线”的半最大值宽度是多少?因此,对于 x 的哪些值 x0,我有 f(x0)=max(y)/2,其中 f 是线性插值。我尝试使用 approxfun 和一些内核密度,但我不想平滑我的数据。

非常欢迎任何意见。

【问题讨论】:

  • 在你的 x 数据中有两个 '4' 值是邪恶的。
  • @Bathsheba 我猜 OP 的意思是 5。
  • @nograpes:我希望它不适合“逆”。
  • Ups,你说得对,应该是5
  • 我很想创建一对新的数据:xfine<-seq(1,5,by=.01)yfine,在 xfine 上使用 predict;然后像xfine[which(abs(yfine-mean(y))< .02)] :-)

标签: r


【解决方案1】:

这是一个简单的函数来做你想做的事,假设你的数据是单峰的,这里使用线性插值:

# FUNCTION TO INFER FWHM USING LINEAR INTERPOLATION
fwhm = function(x, y) { 
  halfheight = max(y)/2
  id.maxy = which.max(y)
  y1 = y[1:id.maxy]
  y2 = y[id.maxy:length(y)]
  x1 = x[1:id.maxy]
  x2 = x[id.maxy:length(y)]
  x.start = approx(x=y1,y=x1, xout=halfheight, method="linear")$y # or without interpolation: x[which.min(abs(y1-halfheight))]
  x.stop = approx(x=y2,y=x2, xout=halfheight, method="linear")$y # or without interpolation: x[which.min(abs(y2-halfheight))+id.maxy]
  fwhm = x.stop-x.start
  width = fwhm/(2*sqrt(2*log(2)))
  return(list(fwhm=fwhm, width=width))
  }

# GAUSSIAN PEAK FUNCTION WITH MODE AT u, WIDTH AT INFLECTION POINT w (FWHM=2.355*w) AND PEAK HEIGHT h
gauspeak=function(x, u, w, h=1) h*exp(((x-u)^2)/(-2*(w^2)))

# EXAMPLE
x = seq(0,200,length.out=1000)
y = gauspeak(x=x, u=100, w=10, h=100)
fwhm(x=x, y=y)
# $`fwhm`
# [1] 23.54934
# 
# $width
# [1] 10.00048

您还可以使用spline() 函数代替approx() 进行三次样条插值而不是线性插值。如果您的数据是单峰的但有噪声,您可以先使用smooth.spline() 平滑您的数据(如果您的数据严格为正,则可能在log(y+1E-20) 尺度上,之后您可以反向转换到原始尺度)。

【讨论】:

    【解决方案2】:

    可能有很多更好的方法可以做到这一点,但这里有一个解决方案。如果我们一开始就知道您是如何进行插值的,那就更容易了。

    # Extend your line for testing
    y<-c(1,2,3,2,1,2,3,4,5,4,3)
    
    # Split into linear segments.
    segments<-c(1,diff(diff(y)))!=0
    seg.points<-which(c(segments,TRUE))
    
    # Calculate desired value
    val<-max(y)/2
    
    # Loop through and find value
    res<-c()
    for(i in 1:(length(seg.points)-1)) {
      start<-y[seg.points[i]]
      end<-y[seg.points[i+1]]
      if ((val>=start & val<=end) | (val<=start & val >=end)) {
        slope=(end-start)/(seg.points[i+1] - seg.points[i])
        res<-c(res,seg.points[i] + ((val - start) / slope))
      }
    }
    res
    # [1] 2.5 3.5 6.5
    

    【讨论】:

    • 感谢您的快速答复!首先,我只使用了 type="l" 选项,然后使用了 expressfun()。我会尝试您的解决方案并通知您。
    • 这可以帮助我处理我的数据,这不是单调递增的。非常感谢!
    猜你喜欢
    • 2010-10-22
    • 1970-01-01
    • 2020-07-31
    • 2019-12-06
    • 2021-07-24
    • 1970-01-01
    • 1970-01-01
    • 2014-07-03
    • 2021-03-06
    相关资源
    最近更新 更多