Site icon R-bloggers

Dealing with S3 methods in R with a simple example

[This article was first published on R – insightR, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

By Gabriel Vasconcelos

S3 objects

R has three object systems: S3, S4 and RC. S3 is by far the easiest to work with and it can make you codes much understandable and organized, especially if you are working on a package. The idea is very simple. First we must define a class to some object in R and then we define methods (functions) for this class based on generic functions that you may create or use the ones available.

Step 1: Defining the object’s class

The function below runs a linear regression and estimate the relevant statistics. Note that in the function I generate several objects and in the end I put them all in a list. Finally, I define the attribute class for my list.

regression=function(x,y){
  x=cbind(1,x)
  beta=solve(t(x)%*%x)%*%t(x)%*%y
  residuals=y-x%*%beta
  fitted.values=x%*%beta
  sigmae=(t(residuals)%*%residuals)/(nrow(x)-ncol(x))
  stde=sqrt(diag(c(sigmae)*solve(t(x)%*%x)))
  tstat=beta/stde
  pvalue=2*pt(-abs(tstat),df=nrow(x)-ncol(x))
  res=list(coefficients=beta,residuals=residuals,fitted.values=fitted.values,
           stde=stde,tstat=tstat,pvalue=pvalue,y=y)
  class(res)="regression" # Class definition
  return(res)
}

Now let’s use the function in some data and see what happens. If I ask R for the class of the resulting object it gives me the defined class “regression”. Additionally, there are some cool stuff you can do that has nothing to do with the class but with the way I defined the list res. If you type coef(res), residuals(res) or fitted(res) you will get coefficients, residuals and fitted values. This will happen every time you name the objects in the list in the way I just did.

set.seed(123)
x=matrix(rnorm(10*100),100,10)
colnames(x)=1:10
y=x%*%rep(1,ncol(x))+rnorm(100)
test=regression(x,y)
class(test) # check the class

## [1] "regression"

Step 2: Defining methods for “regression”“ class

If you look at the documentation in some functions you will read “S3 method for class ‘XXX’”. Try ?summary.lm for example. summary is a generic function that will define which method to call. The .lm tells R that the method to be called in this case is the one defined for the class lm.

To define our own method we just need to create a function using generic.class. However, the defined function must have all arguments in the generic function in the same order. For example, summary takes the argument “object” and the argument “…”. Your function must have the same two arguments in the same order plus the extra arguments you need. There are some exceptions. The function plot takes “x”, “y” and “…” but you may write your plot method without the argument “y”.

In the code below I defined a plot and a summary method for the class “regression”.

plot.regression=function(x,...){
  plot(x$y,main="Fitted x Observed",type="l")
  lines(fitted(x),col=2)
}

summary.regression=function(object,digits=4,...){
  tab=cbind(coef(object),object$stde,object$tstat,object$pvalue)
  colnames(tab)=c("coef","stde","t","p")
  rownames(tab)=rownames(coef(object))
  rownames(tab)[1]="Cons."
  print(tab,digits=digits)
}

Now we can call your functions using only their generic name and R will automatically identify the right method to use.

summary(test,3)

##        coef  stde     t        p
## Cons. 0.137 0.109  1.25 2.14e-01
## 1     1.065 0.120  8.87 6.94e-14
## 2     0.996 0.112  8.88 6.73e-14
## 3     0.853 0.112  7.61 2.67e-11
## 4     1.138 0.109 10.47 3.37e-17
## 5     1.070 0.113  9.45 4.37e-15
## 6     0.963 0.118  8.17 1.92e-12
## 7     1.093 0.104 10.55 2.35e-17
## 8     1.110 0.110 10.12 1.82e-16
## 9     0.951 0.103  9.27 1.03e-14
## 10    1.137 0.106 10.69 1.20e-17

plot(test)

Final Remarks

As you can see, S3 objects are very easy to deal with. You can also define multiple classes to an object. If you are writing a package you have to be careful to export the functions in the right way. Fortunately, the RStudio tool for packages combined with the roxygen2 package does most of the job for you. You can identify generic functions reading the description in their documentation.


To leave a comment for the author, please follow the link and comment on their blog: R – insightR.

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.