4

I am trying to generate functions combining n gaussians, and using values retrieved from a nls run. I use gsub to replace the original coefficients with the nls ones using backreferences. However, it seems that [ on the datafame evaluates before the \\1.

Here is a MWE :

nls <- data.frame(Estimate = seq(1,3))
row.names(nls) <- c("a","b","c")
gsub("(a|b|c)",paste0(" ",nls["\\1","Estimate"]," "),"a + b*x + c*x^2")

As you can see, the replacements are NAs, while the call to the nls dataframe appear to be valid :

gsub("(a|b|c)",paste0(" ","\\1","Estimate"," "),"a + b*x + c*x^2")

Any ideas to delay the evaluation of [ ?

Thanks !

EDIT : for the sake of clarity, here is the full function now working great (it takes number of peaks, formula of one peak, parameters in the formula, variable, constant boolean, and nls results as arguments, and returns the formula for use in ggplot's stat_function() :

Generate_func <- function(peakNb,peakForm,peakParams, peakVar, constBool,nls){
  res <- as.data.frame(summary(nls)$coefficients, optional = T)
  rhs <- strsplit(peakForm, "~")[[1]][[2]]
  regex <- paste0("([*+-/\\^\\(\\)[:space:]]|^)(",paste0(peakParams, collapse = "|"),")([*+-/\\^\\(\\)[:space:]]|$)")
  exp_names <- paste0(sapply(seq(1,peakNb),function(i){
    paste0(sapply(peakParams, function(j){
      paste0(j,i)
    }))
  }))
  if(constBool){exp_names <- c("C", exp_names)}
  func_text <- paste0(sapply(seq(1,peakNb),function(n){gsubfn(regex, x + y + z ~ paste0(x,res[paste0(y,n),"Estimate"],z), rhs )}), collapse = " + ")
  func_text <- paste0(ifelse(constBool,paste0(res["C","Estimate"]," + "),""), func_text)

  func <- function(x){
    eval(parse(text = func_text))
  }
  names(formals(func)) <- c(peakVar)

  print(func_text)

  func
}

And here is an usage example (nls data not included for length sake):

> testfunc <- Generate_func(3, "intensity_cnt ~ a * exp((-(energy_eV-b)^2)/(2*c^2))", c("a","b","c"), "energy_eV", constBool = T, testnls)
[1] "1000 +  32327.6598743022 * exp((-(energy_eV-1.44676439236578)^2)/(2*0.0349194350021539^2)) +  10000 * exp((-(energy_eV-1.49449385009962)^2)/(2*0.0102269096492807^2)) +  54941.8293572164 * exp((-(energy_eV-1.5321664735001)^2)/(2*0.01763494864617^2))"

Thank you for your help !

4

2 に答える 2

5

1) gsubパターンを定数に置き換えますが、探しているのは、一致した文字列に関数を適用した結果に置き換えることです。 gsubfn パッケージgusbfnでそれを行います。以下の 2 番目の引数の式は、引数が左辺で本体が右辺である関数の gsubfn の短縮形です。別の方法として、2 番目の引数を通常の関数表記 ( ) で表すこともできますが、少し冗長になります。function(x) nls[x,]

> library(gsubfn)
> gsubfn("a|b|c", x ~ nls[x, ], "a + b*x + c*x^2")
[1] "1 + 2*x + 3*x^2"

冗長な指定を避けるために、使用"a|b|c"から派生する可能性があることに注意してください。nlspaste(rownames(nls), collapse = "|")

2)これを大幅に簡素化しますが、使用gsubfnせずに行うには:gsubfnsubstitute

> L <- as.list(setNames(nls[[1]], rownames(nls)))  # L <- list(a = 1L, b = 2L, c = 3L)
> e <- parse(text = "a + b * x + c * x ^ 2")[[1]]  # e is the text as a "call" object
> s <- do.call(substitute, list(e, L))             # perform the substitution
> format(s)                                        # convert to character
[1] "1L + 2L * x + 3L * x^2"

Ls は、質問で定義されているように整数が含まれているためですnls。気に入らない場合は、上記を実行する前に数値に変換してください。

nls[[1]] <- as.numeric(nls[[1]])

3) 別の可能性は、置換する文字列をループすることです。

> s <- "a + b*x + c*x^2"
> for(nm in rownames(nls)) s <- gsub(nm, nls[nm, ], s)
> s
[1] "1 + 2*x + 3*x^2"

置換するそれぞれの出現が 1 つしかないことがわかっている場合は、ここsubの代わりに使用できgsubます。

更新: 2 番目の解決策を修正しました。

更新 2: 3 番目のソリューションを追加しました。

于 2013-10-06T21:55:56.447 に答える
1

ここにそれを行う別の方法があります

gsub(paste0(row.names(nls), "(.*)", collapse=""),  paste0(t(nls),  paste0("\\", 1:nrow(nls)), collapse=""), "a + b*x + c*x^2"  )
[1] "1 + 2*x + 3*x^2"
于 2013-10-06T22:09:10.757 に答える