nls当数据是一个复杂的光谱(可变数量的变量)

时间:2014-01-27 12:34:48

标签: r spectrum nls

我有一些频谱数据看起来像绘制时的多重数据之一: 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])进行评估。

1 个答案:

答案 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))

然而,似乎公式不起作用,但这不是这个帖子的目的,所以我现在可以说它已经关闭了(我开了一个新的试图解决它)。