# Fitting Legendre (orthogonal) polynomials in R

February 10, 2009
By

(This article was first published on Gregor Gorjanc, and kindly contributed to R-bloggers)

Frederick Novomestky packaged a series of orthogonal polynomials in the orthopolynom R package. However, his functions can not be used "directly" in a statistical model, say in lm(). There is no need to use functions from orthopolynom package, since there is a poly() function in stats package that is shipped with R. Nevertheless, I played with class of Legendre polynomials. (Wikipedia, Wolfram) This class of polynomials is very popular in my field since the introduction of so called random regression models (e.g. link1, link2, link3, ..., and some of our work), though the splines (Wikipedia, Wolfram) are making their way through (see this link and follow references). Let's go to orthopolynom package. Say we want to use Legendre polynomial of 4th order for a variable x. First we need to get the coefficients for basis functions:
library(package="orthopolynom")
(leg4coef <- legendre.polynomials(n=4, normalized=TRUE))
[[1]]0.7071068[[2]]1.224745*x[[3]]-0.7905694 + 2.371708*x^2[[4]]-2.806243*x + 4.677072*x^3[[5]]0.7954951 - 7.954951*x^2 + 9.280777*x^4
To use this polynomial in a model, we need to create a design matrix with sensible column names and without the intercept:
x <- 1:100leg4 <- as.matrix(as.data.frame(polynomial.values(polynomials=leg4coef,                                                  x=scaleX(x, u=-1, v=1))))colnames(leg4) <- c("leg0", "leg1", "leg2", "leg3", "leg4")leg4 <- leg4[, 2:ncol(leg4)]
Now we can use this in a model, e.g., lm(y ~ leg4). I made this whole process easier - with the functions bellow, we can simply use lm(y ~ Legendre(x=scaleX(x, u=-1, v=1), n=4)). I contacted Fred and I hope he will add some version of these functions to his package.

Update 2009-03-16: If we want that the intercept has a value of 1, we need to rescale the polynomial coefficients by multiplying with sqrt(2).
Legendre <- function(x, n, normalized=TRUE, intercept=FALSE, rescale=TRUE){  ## Create a design matrix for Legendre polynomials  ## x - numeric  ## n - see orthopolynom  ## normalized - logical, see orthopolynom  ## intercept - logical, add intercept  tmp <- legendre.polynomials(n=n, normalized=normalized)  if(!intercept) tmp <- tmp[2:length(tmp)]  polynomial.values(polynomials=tmp, x=x, matrix=TRUE)}polynomial.values <- function(polynomials, x, matrix=FALSE){  ## Changed copy of polynomial.vales from orthopolynom in order  ## to add matrix argument  require(polynom)  n <- length(polynomials)  if(!matrix) {    values <- vector(mode="list", length=n)  } else {    values <- matrix(ncol=n, nrow=length(x))  }  j <- 1  while(j <= n) {    if(!matrix) {      values[[j]] <- predict(polynomials[[j]], x)    } else {      values[, j] <- predict(polynomials[[j]], x)    }    j <- j + 1  }  values}

R-bloggers.com offers daily e-mail updates about R news and tutorials on topics such as: visualization (ggplot2, Boxplots, maps, animation), programming (RStudio, Sweave, LaTeX, SQL, Eclipse, git, hadoop, Web Scraping) statistics (regression, PCA, time series, trading) and more...