By default poly()
uses an orthogonal polynomial representation, which is more numerically stable. You can use raw=TRUE
if you want to match the naive representation.
set.seed(101)
dd <- data.frame(Time=c(1980:2016),
y=rnorm(2016-1980+1))
(c1 <- coef(lm(y~Time+I(Time^2),dd)))
## (Intercept) Time I(Time^2)
## 6.684138e+03 -6.686392e+00 1.672101e-03
(c2 <- coef(lm(y~poly(Time,2),dd)))
## (Intercept) poly(Time, 2)1 poly(Time, 2)2
## -0.04713527 -0.30359154 1.03594479
c3 <- coef(lm(y~poly(Time,2,raw=TRUE),dd))
all.equal(unname(c1),unname(c3)) ## TRUE
You'll notice among other things that the intercept and slope given by the raw polynomials refer to the expected values at Time=0, which if you're using Time in CE (Common Era=AD) years is a little ridiculous.
If you want both interpretability and numerical stability you can get a reasonable compromise by centering your time variable (setting time to zero at the beginning of your observation period is also reasonable).
dd$cTime <- dd$Time-mean(dd$Time)
c4 <- coef(lm(y~poly(cTime,2,raw=TRUE),dd))
unname(c4)
## [1] -0.237754839 -0.004674513 0.001672101