The inner workings of R objects
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
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
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.