我有一些频谱数据看起来像绘制时的多重数据之一: http://journals.prous.com/journals/dof/19982303/html/df230301/images/keiferf3.gif
如何在图像中看到所有的峰值彼此之间非常接近,所以我想使用nls函数进行一些反卷积,就像之前发布的那样(R: Fitting Gaussian peaks to density plot data using nls),但是使用Lorentzian功能改为:
y <- 1/(pi*a*(1+((x-x0)/a)^2))
在我的例子中,x0是峰值最大值(长度(x0)是峰值数),所以我只需要优化'a'。
但是,我的问题与执行该问题无关,而是编写一个可以对任何频谱进行去卷积的强大脚本,将峰值数量作为输入信息。
我的第一个想法是编写洛伦兹函数并将'a'留作矢量(此后应用所有洛伦兹曲线的总和),但R不识别这种结构:
for (i in 1:length(x0)) {
f[i]<-function(a) { y <- 1/(pi*a[i]*(1+((x-x0[i])/a[i])^2)) }
}
fit <- nls(sum(f[1:length(x0)]), start=list(a=rep(1, times=length(x0))))
更新
这是我的样本,格式为.csv(https://drive.google.com/file/d/0B66EHLI5AufhbjlWcW9rYXl1UFk/edit?usp=sharing)。数据填充为2行。第一个具有频率(以ppm为单位),第二个具有强度。对于这个数据,我会选择5个峰值,所以我会在公式= f [1] + f [2] + f [3] + f [4] + f [5]上做'nls',我会得到5个参数(a [1:5])进行评估。
答案 0 :(得分:0)
我找到了'as.formula'命令,它允许将任何字符串转换为公式。因此,我设法创建一个for循环,创建洛伦兹曲线的总和。在我的例子中,参数a [1:5]现在定义为a-e,但是使用sprintf我也可以使用矢量命名法。
cac<-"abcdefghijklmnopqrstuvwxyz"
for (i in 1:length(x0)) {
letter<-substr(cac, i,i)
formulae[i]<-sprintf("1/(pi*%s*(1+((spectra[1,]-%f)/%s)^2))", letter,x0[i],letter)
coeff[i]<-sprintf("%s=1", letter)
}
formula2<-paste(formulae, collapse="+")
formulo<-paste("spectra[2,] ~", formula2, sep="")
coeffs<-paste(coeff, collapse=",")
fit<-as.formula(paste("nls(",formulo,",start=list(",coeffs,"))", sep=""))
所以,所有这些代码都为我发布的示例带来了以下公式:
"nls(spectra[2,] ~1/(pi*a*(1+((spectra[1,]-2.156460)/a)^2))+1/(pi*b*(1+((spectra[1,]-2.170150)/b)^2))+1/(pi*c*(1+((spectra[1,]-2.184820)/c)^2))+1/(pi*d*(1+((spectra[1,]-2.163550)/d)^2))+1/(pi*e*(1+((spectra[1,]-2.142040)/e)^2)), start=list(a=1,b=1,c=1,d=1,e=1))
然而,似乎公式不起作用,但这不是这个帖子的目的,所以我现在可以说它已经关闭了(我开了一个新的试图解决它)。