简体   繁体   English

如何在R中获得线性插值的逆

[英]How to get the inverse of a linear interpolation in R

I went through many solutions for that problem, but could not find a reliable automated one. 我针对该问题经历了许多解决方案,但找不到可靠的自动化解决方案。 Please find below a detailed self-suficient description. 请在下面找到详细的自给自足的说明。

These are the data: data.txt 这些是数据:data.txt

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

Plotting as a scatter plot: 绘制为散点图:

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

You will see a peak, my question is now: assuming I am happy with the linear interpolation, what is the width at half maximum of that "curve"? 您将看到一个峰值,现在我的问题是:假设我对线性插值感到满意,那么该“曲线”的一半最大宽度是多少? So for which values x0 of x I have f(x0)=max(y)/2, where f is the linear interpolation. 因此,对于x的x0值,我有f(x0)= max(y)/ 2,其中f是线性插值。 I tried with approxfun and some kernel density, but I do not want to smooth my data. 我尝试使用roxfun和一些内核密度,但是我不想使数据平滑。

Any input is very welcome. 任何输入都非常欢迎。

There are probably a lot of better ways of doing this, but here is one solution. 可能有很多更好的方法可以做到这一点,但这是一种解决方案。 It would be easier if we knew how you did the interpolation in the first place. 如果我们一开始就知道您是如何进行插值的,那会更容易。

# 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

Here is a simple function to do what you want, assuming your data are unimodal, here using linear interpolation: 假设您的数据是单峰的,以下是使用线性插值的简单函数:

# 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

You could also use the spline() function instead of approx() to do cubic spline interpolation instead of linear interpolation. 您也可以使用spline()函数代替approx()进行三次样条插值,而不是线性插值。 And if your data were unimodal but noisy you could smooth your data first using smooth.spline() (maybe on a log(y+1E-20) scale if your data are strictly positive, after which you can backtransform to the original scale). 而且,如果您的数据是单峰的但嘈杂的,则可以先使用smooth.spline()平滑数据smooth.spline()如果数据严格为正数,则可以对log(y+1E-20)缩放,然后可以反向转换为原始缩放) 。

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

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