2

not for the first time, I guess that the answer is quite simple. But searching for R solutions is regularly hard work and after two hours its probably at time to ask someone...

I am working with a non-linear formula (this is only the first work on it, it will actually become non-linear soon) and to test my initial values, i would like to simply calculate the values over a series of x values.

Here is some code:

x <- c(1,2,3,4,5,6,7,8,9,10,11,12) #etc
y <- c(NA,332,248,234,84,56,26,24,27,33,37,25) #etc
# This is my formula I shall soon expand
fEst <- y ~ 1 / (x / a + 1) * b
# Initial value
a <- 800
# Initial value based on inverted formula and second measure
b <- y[2] * (x[2] / a + 1)

# Can i use my formula fEst to do this step?
p <- 1 / (x / a + 1) * b

The point is that I am working on the formula - and it seems strange to make each change, twice...

What I found was a package nls2 where something like this was possible and a function apply.a.formula which seems to be an element from another package - but as this is a very basic use of a function, I guess that the R base packe already has the appropriate functions. Just ... where?

Thanks!

BurninLeo
  • 4,240
  • 4
  • 39
  • 56

1 Answers1

3

I came across this thread whilst looking up the avenues you'd tried and the solution posted by Gabor. Note that apply.a.formula() is a made up function name that the OP in the thread was looking to find a real function for.

Using the example that Gabor provided in the thread this is a solution using the nls2 package:

## your data
x <- c(1,2,3,4,5,6,7,8,9,10,11,12) #etc
y <- c(NA,332,248,234,84,56,26,24,27,33,37,25) #etc
# This is my formula I shall soon expand
fEst <- y ~ 1 / (x / a + 1) * b
# Initial value
a <- 800
# Initial value based on inverted formula and second measure
b <- y[2] * (x[2] / a + 1)

## install.packages("nls2", depend = TRUE) if not installed
require(nls2)
fitted(nls2(fEst, start = c(a = a, b = b), alg = "brute"))

The last line gives:

R> fitted(nls2(fEst, start = c(a = a, b = b), alg = "brute"))
 [1] 332.4145 332.0000 331.5866 331.1741 330.7627 330.3524 329.9430 329.5347
 [9] 329.1273 328.7210 328.3157 327.9113
attr(,"label")
[1] "Fitted values"

which is essentially the same as 1 / (x / a + 1) * b would give:

R> 1 / (x / a + 1) * b
 [1] 332.4145 332.0000 331.5866 331.1741 330.7627 330.3524 329.9430 329.5347
 [9] 329.1273 328.7210 328.3157 327.9113

From the comments, Carl Witthoft notes that if you want to generalise equations like 1 / (x / a + 1) * b then a function might be a useful way of encapsulating the operation without typing out 1 / (x / a + 1) * b every time. For example

myeqn <- function(a, b, x) { 1 / (x / a + 1) * b }

R> myeqn(a, b, x)
[1] 332.4145 332.0000 331.5866 331.1741 330.7627 330.3524 329.9430 329.5347
[9] 329.1273 328.7210 328.3157 327.9113
Gavin Simpson
  • 170,508
  • 25
  • 396
  • 453
  • Arg - I am sorry for mixing the "made up function name" up with the solution. However, I cannot believe that applying a formula to data (probably the most self-evident application) requires an extra package... – BurninLeo May 09 '12 at 11:57
  • 1
    @BurninLeo It might help to know where the `formula` interface was motivated from; a way to symbolically describe a statistical model. It uses a well known Wilkinson Rogers notation for formulas where characters such as `*` and `` \ `` have special meanings. Given the particular motivation for the formula interface, it is not surprising at all if you need extra scaffolding and functions to turn it into something that can be used as a function. `nls()` function has special code to deal with formulas as equations. The **nls2** package expands on that. I don't see how `nls()` can be used here. – Gavin Simpson May 09 '12 at 12:18
  • Hmm - it makes (some) sense when turned this way. Thank you for the explanation! – BurninLeo May 09 '12 at 12:21
  • 2
    All the same -- @BurninLeo it might be that you really just want to create a function `y<-function(a,b,x) {stuff_goes_here}` . It depends on your ultimate intent. To use `nls2` or other fitting function packages, the answer here is good. If you only want to crank some values and compare with your original `y`, then you only need to write a function, not a formula. – Carl Witthoft May 09 '12 at 14:35
  • 1
    Yes, actually I went to using a function instead of a formula. I lately realized that nls() works with a y~function as well. This makes the whole thing easier :) – BurninLeo May 10 '12 at 13:43
  • @Carl-Witthoft, `function` is definitely the way to go, please add an answer here saying that! – smci Mar 08 '14 at 08:13
  • @smci Thanks for the note :-) . I don't think it's worth posting an answer, as it's really a comment on how to approach a problem. – Carl Witthoft Mar 08 '14 at 13:49
  • @smci I'll promote Carl's comment to the Answer in that case so it is more visible to future visitors – Gavin Simpson Mar 08 '14 at 14:29