我为这个问题找了很多解决方案,但找不到可靠的自动解决方案。请在下面找到详细的自我描述。
这些是数据: data.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 I的值x0具有f(x0)= max(y)/ 2,其中f是线性插值。我尝试使用近似和一些内核密度,但我不想平滑我的数据。
非常欢迎任何意见。
答案 0 :(得分:1)
这可能有很多更好的方法,但这是一个解决方案。如果我们首先知道你如何进行插值会更容易。
# 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
答案 1 :(得分: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)
尺度上进行平滑,然后再转换回原始尺度)。>