# The inner workings of R objects

June 29, 2012
By

(This article was first published on Insights of a PhD student » R, and kindly contributed to R-bloggers)

R is an object oriented language. You provide a name and R supplies that name with various properties. In the simplest case, you can assign a number to a name. This will only have a few attributes, such as its class, length etc:

i <- 5
names(i)
#NULL
class(i)
#[1] "integer"
attr(i, "name")
#NULL
dim(i)
#NULL

Larger objects have more attributes of course:

data(cars)
names(cars)
#[1] "speed" "dist"
class(cars)
#[1] "data.frame"
dim(cars)
#[1] 50  2

A great way to get an overview of an object is the structure command, str(). This tells you whats in the object, dimensionality,  slot names, classes. All sorts.

str(cars)
#'data.frame':	50 obs. of  2 variables:
# $speed: num 4 4 7 7 8 9 10 10 10 11 ... #$ dist : num  2 10 4 22 16 10 18 26 34 17 ...

Its also a great way to diagnose unexpected behaviour, for instance if you try to plot two variables and expect a boxplot but get a scatterplot because the independent variable is of numeric/integer class rather than the factor class.

Many functions (e.g. lm, lme, lmer, aov…)  produce objects with a wide variety of useful components which are given names within. While there are often accessor functions such coef(), you need to know the name of that function. Another way around this is to inspect the object itself, find the slot of interest and pull it out. The slots are often described on the functions help page, but most have usefully descriptive names.

str(lm(dist ~ speed, cars))
# List of 12
# $coefficients : Named num [1:2] -17.58 3.93 # ..- attr(*, "names")= chr [1:2] "(Intercept)" "speed" #$ residuals    : Named num [1:50] 3.85 11.85 -5.95 12.05 2.12 ...
# ..- attr(*, "names")= chr [1:50] "1" "2" "3" "4" ...
# $effects : Named num [1:50] -303.914 145.552 -8.115 9.885 0.194 ... # ..- attr(*, "names")= chr [1:50] "(Intercept)" "speed" "" "" ... #$ rank         : int 2
# $fitted.values: Named num [1:50] -1.85 -1.85 9.95 9.95 13.88 ... # ..- attr(*, "names")= chr [1:50] "1" "2" "3" "4" ... #$ assign       : int [1:2] 0 1
# $qr :List of 5 # ..$ qr   : num [1:50, 1:2] -7.071 0.141 0.141 0.141 0.141 ...
# etc etc etc

Accessing these slots allows one to have much more control over plots especially, but also further analysis (if you know what youre doing). You can get away from the defaults of plotting methods and create plots that arent normally possible using the plot method for a given object. For example, a recent question on the SIG-Ecology mailing list was about adding points to the following effect plot.

By using various elements from the effect object it was possible to produce the plot that was needed. Perhaps not the most elegant solution, but it worked, and with some fine tuning could look better (in my opinion) than the effect plot methods output.

X<-rnorm(100)
Y<-rnorm(100)
Z<-rnorm(100)
library(nlme)
m1<-gls(Y~X+Z)

Y1 <- effect('X', m1)$fit # gives the y coordinates for the think line X1 <- as.matrix(effect('X', m1)$x) # gives the x coordinates
effect('X', m1)$se # gives the SE values low <- effect('X', m1)$lower
up <- effect('X', m1)\$upper # gives the y values from the red lines

y1<-c(min(Y), max(Y))
x1<-c(min(X), max(X))
plot(Y1 ~ X1, xlim = x1, ylim = y1, ty="l")
lines(low ~ X1, lty=2, col="red")
lines(up ~ X1, lty=2, col="red")
points(Y~X)


So, next time you struggle with plotting an object for example…look at its internal structure, grab the relevant part and make the plot yourself!

* For the second plot I just decreased the margin size is why it looks a bit different and has no axis or main titles. But thats a topic for another post