Git Product home page Git Product logo

nls.multstart's Introduction

nls.multstart

Robust and reproducible non-linear regression in R

Authors and maintainers

Daniel Padfield: [email protected]

Granville Matheson: [email protected]

Issues and suggestions

Please report any issues/suggestions for improvement in the issues link for the repository. Or please email [email protected] or [email protected].

R-CMD-check CRAN version Downloads from Rstudio mirror

Licensing

This package is licensed under GPL-3.

Overview

nls.multstart is an R package that allows more robust and reproducible non-linear regression compared to nls() or nlsLM(). These functions allow only a single starting value, meaning that it can be hard to get the best estimated model. This is especially true if the same model is fitted over the levels of a factor, which may have the same shape of curve, but be much different in terms of parameter estimates.

nls_multstart() is the main (currently only) function of nls.multstart. Similar to the R package nls2, it allows multiple starting values for each parameter and then iterates through multiple starting values, attempting a fit with each set of start parameters. The best model is then picked on AIC score. This results in a more reproducible and reliable method of fitting non-linear least squares regression in R.

This package is designed to work with the tidyverse, harnessing the functions within broom, tidyr, dplyr and purrr to extract estimates and plot things easily with ggplot2. A slightly less tidy-friendly implementation is nlsLoop.

Installation and examples

1. Installation

nls.multstart can be installed from CRAN using install.packages() or GitHub can be installed using devtools.

# install package
install.packages('nls.multstart') # from CRAN
devtools::install_github("padpadpadpad/nls.multstart") # from GitHub

2. Run nls_multstart()

nls_multstart() can be used to do non-linear regression on a single curve.

# load in nlsLoop and other packages
library(nls.multstart)
library(ggplot2)
library(broom)
library(purrr)
library(dplyr)
library(tidyr)
library(nlstools)

# load in example data set
data("Chlorella_TRC")

# define the Sharpe-Schoolfield equation
schoolfield_high <- function(lnc, E, Eh, Th, temp, Tc) {
  Tc <- 273.15 + Tc
  k <- 8.62e-5
  boltzmann.term <- lnc + log(exp(E/k*(1/Tc - 1/temp)))
  inactivation.term <- log(1/(1 + exp(Eh/k*(1/Th - 1/temp))))
  return(boltzmann.term + inactivation.term)
  }
# subset dataset
d_1 <- subset(Chlorella_TRC, curve_id == 1)

# run nls_multstart with shotgun approach
fit <- nls_multstart(ln.rate ~ schoolfield_high(lnc, E, Eh, Th, temp = K, Tc = 20),
                     data = d_1,
                     iter = 250,
                     start_lower = c(lnc=-10, E=0.1, Eh=0.5, Th=285),
                     start_upper = c(lnc=10, E=2, Eh=5, Th=330),
                     supp_errors = 'Y',
                     convergence_count = 100,
                     na.action = na.omit,
                     lower = c(lnc = -10, E = 0, Eh = 0, Th = 0))

fit
#> Nonlinear regression model
#>   model: ln.rate ~ schoolfield_high(lnc, E, Eh, Th, temp = K, Tc = 20)
#>    data: data
#>      lnc        E       Eh       Th 
#>  -1.3462   0.9877   4.3326 312.1887 
#>  residual sum-of-squares: 7.257
#> 
#> Number of iterations to convergence: 19 
#> Achieved convergence tolerance: 1.49e-08

This method uses a random-search/shotgun approach to fit multiple curves. Random start parameter values are picked from a uniform distribution between start_lower() and start_upper() for each parameter. If the best model is not improved upon (in terms of AIC score) for 100 new start parameter combinations, the function will return that model fit. This is controlled by convergence_count, if this is set to FALSE, nls_multstart() will try and fit all iterations.

Another method of model fitting available in nls_multstart() is a gridstart approach. This method creates a combination of start parameters, equally spaced across each of the starting parameter bounds. This can be specified with a vector of the same length as the number of parameters, c(5, 5, 5) for 3 estimated parameters will yield 125 iterations.

# run nls_multstart with gridstart approach
fit <- nls_multstart(ln.rate ~ schoolfield_high(lnc, E, Eh, Th, temp = K, Tc = 20),
                     data = d_1,
                     iter = c(5, 5, 5, 5),
                     start_lower = c(lnc=-10, E=0.1, Eh=0.5, Th=285),
                     start_upper = c(lnc=10, E=2, Eh=5, Th=330),
                     supp_errors = 'Y',
                     na.action = na.omit,
                     lower = c(lnc = -10, E = 0, Eh = 0, Th = 0))

fit
#> Nonlinear regression model
#>   model: ln.rate ~ schoolfield_high(lnc, E, Eh, Th, temp = K, Tc = 20)
#>    data: data
#>      lnc        E       Eh       Th 
#>  -1.3462   0.9877   4.3326 312.1887 
#>  residual sum-of-squares: 7.257
#> 
#> Number of iterations to convergence: 17 
#> Achieved convergence tolerance: 1.49e-08

Reassuringly both methods give identical model fits!

3. Clean up fit

This fit can then be tidied up in various ways using the R package broom. Each different function in broom returns a different set of information. tidy() returns the estimated parameters, augment() returns the predictions and glance() returns information about the model such as AIC score. Confidence intervals of non-linear regression can also be estimated using nlstools::confint2()

# get info
info <- glance(fit)
info
#> # A tibble: 1 × 9
#>   sigma isConv       finTol logLik   AIC   BIC deviance df.residual  nobs
#>   <dbl> <lgl>         <dbl>  <dbl> <dbl> <dbl>    <dbl>       <int> <int>
#> 1 0.952 TRUE   0.0000000149  -14.0  38.0  40.4     7.26           8    12

# get params
params <- tidy(fit)

# get confidence intervals using nlstools
CI <- confint2(fit) %>%
  data.frame() %>%
  rename(., conf.low = X2.5.., conf.high = X97.5..)

# bind params and confidence intervals
params <- bind_cols(params, CI)
select(params, -c(statistic, p.value))
#> # A tibble: 4 × 5
#>   term  estimate std.error conf.low conf.high
#>   <chr>    <dbl>     <dbl>    <dbl>     <dbl>
#> 1 lnc     -1.35      0.466  -2.42      -0.272
#> 2 E        0.988     0.452  -0.0549     2.03 
#> 3 Eh       4.33      1.49    0.902      7.76 
#> 4 Th     312.        3.88  303.       321.

# get predictions
preds <- augment(fit)
preds
#> # A tibble: 12 × 5
#>    ln.rate     K `(weights)` .fitted  .resid
#>      <dbl> <dbl>       <dbl>   <dbl>   <dbl>
#>  1 -2.06    289.           1 -1.89   -0.176 
#>  2 -1.32    292.           1 -1.48    0.156 
#>  3 -0.954   295.           1 -1.08    0.127 
#>  4 -0.794   298.           1 -0.691  -0.103 
#>  5 -0.182   301.           1 -0.311   0.129 
#>  6  0.174   304.           1  0.0534  0.121 
#>  7 -0.0446  307.           1  0.367  -0.411 
#>  8  0.481   310.           1  0.498  -0.0179
#>  9  0.388   313.           1  0.180   0.208 
#> 10  0.394   316.           1 -0.645   1.04  
#> 11 -3.86    319.           1 -1.70   -2.16  
#> 12 -1.72    322.           1 -2.81    1.09

4. Plot fit

The predictions can then easily be plotted alongside the actual data.

ggplot() +
  geom_point(aes(K, ln.rate), d_1) +
  geom_line(aes(K, .fitted), preds)

5. Fitting over levels of a factor with nls_multstart

nls_multstart() is unlikely to speed you up very much if only one curve is fitted. However, if you have 10, 60 or 100s of curves to fit, it makes sense that at least some of them may not fit with the same starting parameters, no matter how many iterations it is run for.

This is where nls_multstart() can help. Multiple models can be fitted using purrr, dplyr and tidyr. These fits can then be tidied using broom, an approach Hadley Wickham has previously written about.

# fit over each set of groupings
fits <- Chlorella_TRC %>%
  group_by(., flux, growth.temp, process, curve_id) %>%
  nest() %>%
  mutate(fit = purrr::map(data, ~ nls_multstart(ln.rate ~ schoolfield_high(lnc, E, Eh, Th, temp = K, Tc = 20),
                                   data = .x,
                                   iter = 1000,
                                   start_lower = c(lnc=-1000, E=0.1, Eh=0.5, Th=285),
                                   start_upper = c(lnc=1000, E=2, Eh=10, Th=330),
                                   supp_errors = 'Y',
                                   na.action = na.omit,
                                   lower = c(lnc = -10, E = 0, Eh = 0, Th = 0))))

A single fit can check to make sure it looks ok. Looking at fits demonstrates that there is now a fit list column containing each of the non-linear fits for each combination of our grouping variables.

# look at output object
select(fits, curve_id, data, fit)
#> Adding missing grouping variables: `flux`, `growth.temp`, `process`
#> # A tibble: 60 × 6
#> # Groups:   flux, growth.temp, process, curve_id [60]
#>    flux        growth.temp process     curve_id data              fit   
#>    <chr>             <dbl> <chr>          <dbl> <list>            <list>
#>  1 respiration          20 acclimation        1 <tibble [12 × 3]> <nls> 
#>  2 respiration          20 acclimation        2 <tibble [12 × 3]> <nls> 
#>  3 respiration          23 acclimation        3 <tibble [12 × 3]> <nls> 
#>  4 respiration          27 acclimation        4 <tibble [9 × 3]>  <nls> 
#>  5 respiration          27 acclimation        5 <tibble [12 × 3]> <nls> 
#>  6 respiration          30 acclimation        6 <tibble [12 × 3]> <nls> 
#>  7 respiration          30 acclimation        7 <tibble [12 × 3]> <nls> 
#>  8 respiration          33 acclimation        8 <tibble [10 × 3]> <nls> 
#>  9 respiration          33 acclimation        9 <tibble [8 × 3]>  <nls> 
#> 10 respiration          20 acclimation       10 <tibble [10 × 3]> <nls> 
#> # ℹ 50 more rows

# look at a single fit
summary(fits$fit[[1]])
#> 
#> Formula: ln.rate ~ schoolfield_high(lnc, E, Eh, Th, temp = K, Tc = 20)
#> 
#> Parameters:
#>     Estimate Std. Error t value Pr(>|t|)    
#> lnc  -1.3462     0.4656  -2.891   0.0202 *  
#> E     0.9877     0.4521   2.185   0.0604 .  
#> Eh    4.3326     1.4878   2.912   0.0195 *  
#> Th  312.1887     3.8782  80.499 6.32e-13 ***
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> Residual standard error: 0.9524 on 8 degrees of freedom
#> 
#> Number of iterations to convergence: 23 
#> Achieved convergence tolerance: 1.49e-08

6. Clean up multiple fits

These fits can be cleaned up in a similar way to the single fit, but this time purrr::map() iterates the broom function over the grouping variables.

# get summary
info <- fits %>%
  mutate(summary = map(fit, glance)) %>%
  unnest(summary)

# get params
params <- fits %>%
  mutate(., p = map(fit, tidy)) %>%
  unnest(p)

# get confidence intervals
CI <- fits %>%
  mutate(., cis = map(fit, confint2),
         cis = map(cis, data.frame)) %>%
  unnest(cis) %>%
  rename(., conf.low = X2.5.., conf.high = X97.5..) %>%
  group_by(., curve_id) %>%
  mutate(., term = c('lnc', 'E', 'Eh', 'Th')) %>%
  ungroup() %>%
  select(., -data, -fit)

# merge parameters and CI estimates
params <- merge(params, CI, by = intersect(names(params), names(CI)))

# get predictions
preds <- fits %>%
  mutate(., p = map(fit, augment)) %>%
  unnest(p)

Looking at info allows us to see if all the models converged.

select(info, curve_id, logLik, AIC, BIC, deviance, df.residual)
#> Adding missing grouping variables: `flux`, `growth.temp`, `process`
#> # A tibble: 60 × 9
#> # Groups:   flux, growth.temp, process, curve_id [60]
#>    flux    growth.temp process curve_id  logLik   AIC   BIC deviance df.residual
#>    <chr>         <dbl> <chr>      <dbl>   <dbl> <dbl> <dbl>    <dbl>       <int>
#>  1 respir…          20 acclim…        1 -14.0   38.0  40.4     7.26            8
#>  2 respir…          20 acclim…        2  -1.20  12.4  14.8     0.858           8
#>  3 respir…          23 acclim…        3  -7.39  24.8  27.2     2.41            8
#>  4 respir…          27 acclim…        4  -0.523 11.0  12.0     0.592           5
#>  5 respir…          27 acclim…        5 -10.8   31.7  34.1     4.29            8
#>  6 respir…          30 acclim…        6  -8.52  27.0  29.5     2.91            8
#>  7 respir…          30 acclim…        7  -1.29  12.6  15.0     0.871           8
#>  8 respir…          33 acclim…        8 -13.4   36.7  38.2     8.48            6
#>  9 respir…          33 acclim…        9   1.82   6.36  6.76    0.297           4
#> 10 respir…          20 acclim…       10  -1.27  12.5  14.1     0.755           6
#> # ℹ 50 more rows

7. Plotting predictions

When plotting non-linear fits, it often looks better to have a smooth curve, even if there are not many points underlying the fit. This can be achieved by including newdata in the augment() function and creating a higher resolution set of predictor values.

However, when predicting for many different fits, it is not certain that each curve has the same range of predictor variables. Consequently, we need to filter each new prediction by the min() and max() of the predictor variables.

# new data frame of predictions
new_preds <- Chlorella_TRC %>%
  do(., data.frame(K = seq(min(.$K), max(.$K), length.out = 150), stringsAsFactors = FALSE))

# max and min for each curve
max_min <- group_by(Chlorella_TRC, curve_id) %>%
  summarise(., min_K = min(K), max_K = max(K)) %>%
  ungroup()

# create new predictions
preds2 <- fits %>%
  mutate(., p = map(fit, augment, newdata = new_preds)) %>%
  unnest(p) %>%
  merge(., max_min, by = 'curve_id') %>%
  group_by(., curve_id) %>%
  filter(., K > unique(min_K) & K < unique(max_K)) %>%
  rename(., ln.rate = .fitted) %>%
  ungroup()

These can then be plotted using ggplot2.

# plot
ggplot() +
  geom_point(aes(K - 273.15, ln.rate, col = flux), size = 2, Chlorella_TRC) +
  geom_line(aes(K - 273.15, ln.rate, col = flux, group = curve_id), alpha = 0.5, preds2) +
  facet_wrap(~ growth.temp + process, labeller = labeller(.multi_line = FALSE)) +
  scale_colour_manual(values = c('green4', 'black')) +
  theme_bw(base_size = 12) +
  ylab('log Metabolic rate') +
  xlab('Assay temperature (ºC)') +
  theme(legend.position = c(0.9, 0.15))

8. Plotting confidence intervals

The confidence intervals of each parameter for each curve fit can also be easily visualised.

# plot
ggplot(params, aes(col = flux)) +
  geom_point(aes(curve_id, estimate)) +
  facet_wrap(~ term, scale = 'free_x', ncol = 4) +
  geom_linerange(aes(curve_id, ymin = conf.low, ymax = conf.high)) +
  coord_flip() +
  scale_color_manual(values = c('green4', 'black')) +
  theme_bw(base_size = 12) +
  theme(legend.position = 'top') +
  xlab('curve') +
  ylab('parameter estimate')

nls.multstart's People

Contributors

mathesong avatar padpadpadpad avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

nls.multstart's Issues

write vignette

Write vignette comparing fitting potential of nls and nlsLM with nls_multstart for multiple models.

Data input, parameter bounds and runif

I spotted your package when it popped up on my Twitter feed, and it looks really great, and it solves a problem which I've been looking to get to for my pharmacokinetic modelling package (https://github.com/mathesong/kinfitr). As such, I would very much like to make use of your package in mine. There are just a few changes/enhancements which I would like to make: I'd be happy to submit them as a pull request. Just wanted to check if they were ok for you first.

(by the way, I've never made a PR before, so please tell me if I should be doing anything differently here)

Data input argument

I would like to be able to include the data as vectors rather than as columns of a vector in some cases. I see that the minpack.lm package has achieved this by using parent.frame() as the default input argument. This allows that the data can be flexibly entered either in vector form in the formula, or in the data frame.

Parameter bounds

You implemented the parameter bounds input as a vector of lower1, upper1, lower2, upper2. This differs from the underlying minpack.lm input, and makes it a little bit harder to directly use the parameter bounds inputs which might have gone directly into minpack.lm as these inputs. Is there a special reason for putting them together? If not, would it be ok for me to separate the upper and lower input arguments for consistency with minpack.lm below?

runif shotgun

You implemented a shotgun approach selecting from a uniform distribution for choosing values for input arguments. Another possibility for scanning across the parameter space would be to divide each parameter's upper and lower starting parameter limit into x equally spaced units, and then fitting the model using each of these starting points. This would ensure that the model was fitted using starting parameters which covered the whole bounding space. I would like to include this option for having fewer iterations, but still covering the full space.

Again, the package looks great, and I'm really excited to try to implement it in my functions.

All the best,
Granville

Error in nls_multstart(speed ~ sharpeschoolhigh_1981(temp = temperature, : There must be as many parameter starting bounds as there are parameters

Hey everyone, (first post here 😃 )

I have been running the same script once or twice already but this time, for some reason it does not work.
I have a very simple dataset with the speed of individuals at different temperature and I want to draw and fit a thermal response curve following the sharpe-Schoolfield model

`start_vals <- get_start_vals(speed$temp, speed$medianSpeed, model_name = 'sharpeschoolhigh_1981')

low_lims <- get_lower_lims(speed$temp, speed$medianSpeed, model_name = 'sharpeschoolhigh_1981')

upper_lims <- get_upper_lims(speed$temp, speed$medianSpeed, model_name = 'sharpeschoolhigh_1981')`

So this step works fine, but then I do:
fit <- nls_multstart(speed~sharpeschoolhigh_1981(temp = temperature, r_tref,e,eh,th, tref = 15), data = speed, iter = 500, start_lower = start_vals - 10, start_upper = start_vals + 10, lower = low_lims, upper = upper_lims, supp_errors = 'Y')

As simple as that. However, I still have the issue

Error in nls_multstart(speed ~ sharpeschoolhigh_1981(temp = temperature, : There must be as many parameter starting bounds as there are parameters

I tried to look at my start_vals vector and I got NA for 'eh'. I don't know if there is any issue related to that.

Any help would be more than welcome,

Thanks
Alann

Get ready for CRAN

After the implementation of the updates suggested by @mathesong, I think the package should get submitted to CRAN. Just a single function it does a valuable job for the R community.

If only so that the package can start earning citation when me and my lab use it in the methods of our manuscripts! Free references are not to be missed. And it will also help publicise the package so people actually know about it!

Links for preparing a package for CRAN are from Karl Broman, Hadley Wickham and CRAN

Error: There must be as many parameter starting bounds as there are parameters

Hello,
First I would like to thank you for this great work .
I am trying to use nls.multstart to fit sine like curve, but I getting error that "There must be as many parameter starting bounds as there are parameters". I double checked all parameters and they are same as the bounds parameters. Below is my function and code I used:

As you can see below, I am trying to fit OPT vs. Volts. The fitting parameters are six: p1, beta1, beta2, eta, ntot , sig
The actual data has multiple sets/sites of similar data shown below, that is why I want to use your function which supports multiple starting values.
Is it too many parameters to fit and that is why it fails? Is it possible to make this fitting happen ? Could you please help me to make this working ?

Thank you
Abdo

function to fit

mzmfunc <- function(p1, beta1, beta2, eta, ntot , sig , Volt1, Volt2,lamb) {

l<-0.63e-2
co_mod<- 1
capperl<-0.26e-9
cap <- capperl*l*co_mod
vbi_va <- 0.4
m_va <- 0.3
mgrad <- (1.0/m_va) - 2.0
qo <- -1*((mgrad+2)/(mgrad+1))*exp(log(vbi_va)/(mgrad+2))*cap
qt <- qo*exp(((mgrad+1)/(mgrad+2))*log(vbi_va))
ntotperl <- 2.34e-9
ntoti <- ntotperl*l*co_mod*co_mod
qcap1<- qt*exp(((mgrad+1)/(mgrad+2))*log(1- Volt1/vbi_va))
phi1<- (-2*pi/lamb)*eta*qcap1
qcap2<- qt*exp(((mgrad+1)/(mgrad+2))*log(1- Volt2/vbi_va))
phi2<- (-2*pi/lamb)*eta*qcap2

A1<- sqrt(abs(p1*( 1-sig*(ntot+qcap1))))
A2<- sqrt(abs(p1*( 1-sig*(ntot+qcap2))))
Eo1<- -1i*0.5*( A1*exp(-1i*(phi1+beta1)) + A2*exp(-1i*(phi2+beta2)) )
Eo2<- 0.5*( A1*exp(-1i*(phi1+beta1)) - A2*exp(-1i*(phi2+beta2)) )
pow1<- abs(Eo1*Conj(Eo1))
pow2<- abs(Eo2*Conj(Eo2))
return(pow1)

}

using nls_multstart

result1 <- nls_multstart(OPT ~ mzmfunc(p1, beta1, eta, ntot , sig , Volt1=0, Volt2=Volt, lamb=1.262e-6),
data = sitedata,
iter = 250,
start_lower = c(p1= 0.01, beta1 = 0 , beta2 = 0, eta=1.4e5 , ntot= 1.4742e-11, sig= 1e10 ),
start_upper = c(p1= 0.04, beta1 = 4 , beta2 = 4, eta=10.4e5 , ntot= 10.4742e-11, sig= 10e10 ),
supp_errors = 'Y',
convergence_count = 200,
na.action = na.omit,
lower = c( p1=0.01, beta1 = 0, beta2 = 0, eta=2.4e5, ntot= 1.4742e-11, sig= 1e10))

sitedata
Volt
-4.0 -3.8 -3.6 -3.4 -3.2 -3.0 -2.8 -2.6 -2.4 -2.2 -2.0 -1.8 -1.6 -1.4 -1.2 -1.0 -0.8 -0.6 -0.4 -0.2 0.0
OPT
0.005701643 0.006880183 0.008212966 0.009582967 0.011132687 0.012385114 0.013740420 0.014845677 0.016180800 0.017108030 0.017901936 0.018365383 0.018365383 0.018395009 0.017926686 0.016900517 0.015848932 0.014197112 0.012705741 0.010514775 0.008077928

Different results for the fitting parameters on the same exact data

Hi Daniel & Granville
@mathesong
@padpadpadpad

I have these issues:

  • Every time I call nls_multstart, I get different results for the fitting parameters on the same exact data. How can I get this fixed and get all time similar results for the fitting parameters ( eta , ntotperl , sig ).

  • As you see from the image below, I am fitting two data (blueData, redData) in for loop and get the fitting parameters for each separately. Expecting I get similar fitting parameters for (eta , ntotperl , sig) for both data. As you see in the image, those two curves very similar except they are pi phase shifted from one another.

  • I noticed the fitting sometimes takes the value I assigned in 'lower' in nls_multstart function as shown in the image below , ntotperl=0.00e+00
    If I don't specify values in "lower", I get negative valuse for ( eta , ntotperl , sig) which are not realistic.
    For both data (blueData, redData), the expected positive values for (eta , ntotperl , sig) are eta =~ 2.40e5, ntotperl =~ 2.34e-9, sig = ~8.0e10 and they could be different but they need to be consistent every time I run nls_multstart
    For beta1 and beta2 they are random phase or angels in radiance and they can take any values. p1 is the max-min for each data ~ 0.002 -0.004

Here are the data, function , and nls_multstart input parametrs
your help is really appreciated

Thank you
Abdo

sitedata

OPT_blueData:
0.0029621019 0.0031441264 0.0033358000 0.0034986460 0.0036702868 0.0038132915 0.0039111097 0.0040373835 0.0040803743 0.0040709897 0.0040105137 0.0038815037 0.0036576319 0.0034387452 0.0031434025 0.0028047877 0.0023944182 0.0019696996 0.0015332042 0.0011084089 0.0007231027 0.0003991168 0.0001695899 0.0000978363
OPT_redData:
1.298375e-03 1.122535e-03 9.253372e-04 7.426770e-04 5.618236e-04 3.994846e-04 2.674853e-04 1.632676e-04 1.043999e-04 9.799412e-05 1.429881e-04 2.435567e-04 4.067242e-04 6.214411e-04 8.943345e-04 1.213109e-03 1.571810e-03 1.957492e-03 2.328627e-03 2.716439e-03 3.082478e-03 3.345800e-03 3.505097e-03 3.535086e-03
Volt:
-4.6 -4.4 -4.2 -4.0 -3.8 -3.6 -3.4 -3.2 -3.0 -2.8 -2.6 -2.4 -2.2 -2.0 -1.8 -1.6 -1.4 -1.2 -1.0 -0.8 -0.6 -0.4 -0.2 0.0
lam:
1264

custom function

`
mzmfunc <- function(p1, beta1, beta2, eta, ntotperl , sig , Volt1, Volt2,lamb) {

lamb<- lamb*1e-9

l<-0.63e-2

co_mod<- 1

capperl<-0.26e-9

cap <- capperllco_mod

vbi_va <- 0.4

m_va <- 0.3

mgrad <- (1.0/m_va) - 2.0

qo <- -1*((mgrad+2)/(mgrad+1))*exp(log(vbi_va)/(mgrad+2))*cap

qt <- qo*exp(((mgrad+1)/(mgrad+2))*log(vbi_va))

ntot <- ntotperllco_mod*co_mod

qcap1<- qt*exp(((mgrad+1)/(mgrad+2))*log(1- Volt1/vbi_va))

phi1<- (-2*pi/lamb)etaqcap1

qcap2<- qt*exp(((mgrad+1)/(mgrad+2))*log(1- Volt2/vbi_va))

phi2<- (-2*pi/lamb)etaqcap2

A1<- sqrt(abs(p1*( 1-sig*(ntot+qcap1))))

A2<- sqrt(abs(p1*( 1-sig*(ntot+qcap2))))

Eo1<- -1i * 0.5 ( A1exp(-1i * (phi1+beta1)) + A2*exp(-1i * (phi2+beta2)) )

Eo2<- 0.5*( A1*exp(-1i (phi1+beta1)) - A2exp(-1i * (phi2+beta2)) )

pow1<- abs(Eo1*Conj(Eo1))

pow2<- abs(Eo2*Conj(Eo2))

return(pow1)
}
`

nls_multstart

`
result1 <- nls_multstart(OPT~ mzmfunc( p1, beta1, beta2, eta, ntotperl, sig , Volt1 = 0, Volt2 = Volt, lamb =lam),

                       data = sitedata,

                       iter = 1000,

                       start_lower = c(p1 = 0.001, beta1 = 0, beta2 = 0, eta = 0 , ntotperl = 0, sig = 0),

                       start_upper = c(p1 = 0.006 , beta1 = 2*pi, beta2 = 2*pi, eta = 3e5 , ntotperl = 1e-9, sig =10e10),

                       supp_errors = 'Y',

                       convergence_count = 300,

                       na.action = na.omit,

                       lower = c(p1 = 0.0001,beta1=0, beta2 = 0, eta =0, ntotperl = 0, sig = 0))

`
capture

Global fit with nls.multstart

I have been wandering around to find a good way for global fitting in R. I used nls.multstart and it works predictably (awesome package)
I want to use this package like I can use with nls in base R.

#Generating sample data
d <- transform(
    data.frame(
        x = seq(0, 1, len = 17),
        group = rep(c("A", "B", "B", "C"), len = 17)
    ),
    y = round(1 / (1.4 + x^ifelse(group == "A", 2.3, ifelse(group == "B", 3.1, 3.5))), 2),
    group = as.factor(group)
)
#Fitting data 
fit <- nls(y ~ 1 / (b + x^p[group]),
    data = d,
    start = list(b = 1, p = rep(3, length(levels(d$group))))
)

"The code is from here"
In the sample code above I can use "[]" to asign a parameter to each group while keeping "b"
as shared parameter.

I tried to follow the same pattern in nls.multstart but I get the following error

fitMulti <- nls.multstart::nls_multstart(
    data = d,
    y ~ 1 / (b + x^p[group]),
    iter = 200,
    start_lower = list(b = 0, p = rep(0, length(levels(d$group)))),
    start_upper = list(b = 5, p = rep(5, length(levels(d$group)))),
    supp_errors = "Y",
    convergence_count = 100,
    na.action = na.omit
)

#ouput
 Error in `as_tibble()`:
! Column names `b` and `p` must not be duplicated.
Use `.name_repair` to specify repair.
Caused by error in `repaired_names()`:
! Names must be unique.
✖ These names are duplicated:
  * "b" at locations 1 and 3.
  * "p" at locations 2 and 4.
Run `rlang::last_trace()` to see where the error occurred.

Is there a way to use nls.multstart to do global fitting in this context?

New version of tidyr::nest

I updated my tidyr the other day, and I get a warning every time I run nls_multstart.

Warning message:
All elements of `...` must be named.

This relates to the new syntax of the tidyr nest() command. I'll submit a PR to fix this.

Update: PR #16

minpack.lm and weights

Hey Dan,

I tried out the package on my specific problem, and it seems to work really well! However, passing arguments through to minpack.lm turned out to be a little bit trickier than expected. Upper and lower worked a charm, but weights gave me errors each time. As far as I can tell, this is because minpack.lm underneath is doing some kind of non-standard evaluation on weights, and it doesn't work when it's obscured a level by nls.multstart.

I just tried out a very simple solution: adding weights as an optional argument to nls.multstart fixes it completely. If not specified, it works as usual. If specified, then it allows one to do weighted nls.

So I'll quickly submit a PR with that.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.