Fitting data to an equation without free parameters
First, let's clarify what it means "to see how well my data fits to the equation" when you have a fixed equation as in your original question. You have data on $x$ and $y$, and your equation:
$$y=(3.5-(x/10))(x/25)^{5/2}$$
has no free parameters. Here's a plot; data points are circles, the equation a solid curve:
So to answer your original question, your data don't fit that equation very well.
Fitting parameters of an equation to match data
Second, "fitting an equation" generally means having a general form of a relation between $y$ and $x$ in mind, but the details of the form depend on some additional unknown parameters of the equation. "Fitting" then means using the data to estimate the values of the parameters that best match the data, say by minimizing the sum of the squares of the discrepancies between the curve and the data. That is what's implicit in the form of the equation in your comment. (I corrected an apparently missing parenthesis so that it matches your original parameter-free equation at $z=25$):
$$y = \frac{35-x}{35-z}\left(\frac{x}{z}\right)^{(z/10)}$$
Now there is something to "fit": find the value of $z$ that comes closest to your data. The simplest R function to do this is nls
. (The R code I used is at the end of the answer.) The best fit to your $x$ and $y$ data is provided by a $z$ value of 33.1, not the value of 25 that would match your first parameter-free equation. It comes closer, but doesn't do very well, either, substantially below most of the true values:
It looks like your equation might have an even more general form, like:
$$y = \frac{a-x}{a-z}\left(\frac{x}{z}\right)^{(z/b)}$$
where $z$, $a$ and $b$ are parameters whose values might be estimated from the data. With that more general form, you can come fairly close to your data, at $z=34.0$, $a=36.7$, and $b=17.8$:
Dangers in fitting equations
Third, you must be very careful if you head down this fitting path. As John von Neumann allegedly said, "With four parameters I can fit an elephant, and with five I can make him wiggle his trunk." Overfitting is a serious temptation when you start playing with data.
In a case like yours you have to think about what the parameters might mean in the real world. It seems that there are competing processes that lead to a peak in growth rate ($y$) at a certain temperature ($x$), and if the parameters $z$, $a$ and $b$ have definite meanings in terms of those competing processes then you might be justified in doing this type of fit. You might, say, learn something about how those processes differ from one strain of bacteria to another. But if such parameters (or the fixed values in your original equation) were simply chosen by someone to make some earlier set of data fit a particular curve then you are headed for big trouble.
Comparing fits to different data sets
If you want to compare the parameter values fitted to two different data sets, it's best to start by examining whether the overall fits differ between the data sets. There is a "useful and rather easily overlooked" way to do this with nls
as Peter Dalgaard put it in a recent answer on R-help. (It can be found at the very bottom of the nls
help page.)
Instead of working with separate vectors of $x$ and $y$ values from different experiments, construct a pooled data frame containing all the data. Each row should contain an $x$ value, the associated observed $y$ value, and a factor variable indicating the specific experiment. (Make sure the experiments are coded as factors, not as numbers.)
nls
then allows you to fit different sets of parameter values to different experiments. Instead of specifying general parameters like Topt
in your call, you can subscript the parameters by experiment, e.g. Topt[expt]
, where "expt" is the name of the factor distinguishing experiments.
Thus you can use anova
to compare a fit to all the data, ignoring individual experiments, against a fit that allows different parameter values for different experiments. If these fits aren't statistically distinguishable, then you shouldn't be looking at differences of individual fitted parameter values among experiments. There's an example below where I present R code.
If the fits do differ, then you can consider comparing fitted parameter values. In the limit of very large samples the fitted values should have normal distributions, but it's not clear what "large" means for nonlinear fits and the meaning might differ depending on the equation. Thus there will be questions about the validity of p-values.
If you are willing to assume normality, nls
reports standard errors for the parameter values, which you can use to obtain p-values under that assumption. A z-test can provide a rough overview, but it would probably be better to use the approach of Welch's t-test, which allows for different standard errors and degrees of freedom between two parameter estimates. To apply that approach, note that terms like $\frac{s_i^2}{N_i}$ in the formula for Welch's test are equivalent to $SE_i^2$ in the nls
output.
R code
In terms of R code, it was simplest to define a general function for your temperature-response curve:
trcFunc <- function(x,z,a,b){((a-x)/(a-z))*((x/z)^(z/b))}
then give specific values for the parameters that matched your original equation, to compare your data to the curve:
plot(x,y)
curve(trcFunc(x,25,35,10),add=TRUE)
For fitting, I used the nls
function, for example for $z$ alone
Zfit <- nls(y~trcFunc(x,z,35,10),start=list(z=30))
or for all 3 parameter values
ZABfit <- nls(y~trcFunc(x,z,a,b),start=list(z=30,a=35,b=10))
Get the fitted parameter values with
ZABfit
Nonlinear regression model
model: y ~ trcFunc(x, z, a, b)
data: parent.frame()
z a b
33.98 36.74 17.84
residual sum-of-squares: 1.228
Number of iterations to convergence: 5
Achieved convergence tolerance: 1.35e-06
and compare data and curve:
plot(x,y,main="fit z, a, b")
curve(trcFunc(x,33.98,36.74,17.84),add=TRUE)
New form for relation; comparing fits With the new general form for the relation of $y$ to $x$ in an edit to the OP, a new general function for fitting is defined as:
newFunc <- function(x,Topt,Tmax,Ymax){Ymax*((Tmax-x)/(Tmax-Topt))*(x/Topt)^(Topt/(Tmax-Topt))}
For comparing two experiments, take expt1
as the data at the beginning of the question and expt2
as the second data set (x2,y2) toward the end, and construct a pooled data frame as suggested above. Then the fit ignoring the differences between experiments is:
fitPool <- nls(y~newFunc(x,Topt,Tmax,Ymax),data=newDF,start=list(Topt=25,Tmax=35,Ymax=2.5))
and that allowing separate parameter values for the two experiments is:
fitSeparate <- nls(y~newFunc(x,Topt[expt],Tmax[expt],Ymax[expt]),data=newDF,start=list(Topt=c(25,25),Tmax=c(35,35),Ymax=c(2.5,2.5)))
The pooled and separate fits are not significantly different:
> anova(fitPool,fitSeparate)
Analysis of Variance Table
Model 1: y ~ newFunc(x, Topt, Tmax, Ymax)
Model 2: y ~ newFunc(x, Topt[expt], Tmax[expt], Ymax[expt])
Res.Df Res.Sum Sq Df Sum Sq F value Pr(>F)
1 19 1.9215
2 16 1.4410 3 0.48046 1.7782 0.1918
Warning on choice of starting values
Note that, as can happen in non-linear curve fitting, what you get as the "best" fit can depend on what you provide as an initial guess for the parameter values. With your data, if I provided an initial guess of 26 for $z$ and fixed values of 35 and 10 for $a$ and $b$:
Zfit26start <- nls(y~trcFunc(x,z,35,10),start=list(z=26))
the value returned for $z$ is 13.1,which doesn't fit very well at all:
This happened because the program wasn't set up to evaluate an entire range of $z$ values and got stuck in what's called a "local optimum" when it started searching from $z=26$. If I tried starting values of $z$ from 20 to 25 then the nls
program returned an error:
Error in numericDeriv(form[[3L]], names(ind), env) :
Missing value or an infinity produced when evaluating the model
while starting values of 19 or less gave the poorly fitting estimate of 13.1 for $z$. With a non-linear curve fit you can't count on getting the "global" optimum without doing a lot of exploration.