We provide effective and economically affordable training courses for R and Python, click here for more details and course registration !

S3 class system is the most used R object oriented programming mechanism. The calling of ‘S3’ comes from the third version of S, which is the ancestor of R programming language. You may not notice S3 when using R for data analysis, but actually It exists everywhere. For example, when a data frame is printed, the S3 type method associated with class ‘data.frame’ is aroused and implemented. To understand S3 class more easily, let us first look at some basic data objects in R. In the following code example, a matrix ‘mtx1’ and a data frame ‘df1’ are created. We then set some attributes to each of them, and use class() function to show the class for each of them.

#create a matrix
mtx1 <- matrix(c(1:6), nrow=2, byrow=TRUE)
print("Matrix 1 is")
[1] "Matrix 1 is"
#print this matrix
print(mtx1)
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6

#attributes of matrix
attributes(mtx1)
$dim
[1] 2 3

#class of matrix
> class(mtx1)
[1] "matrix" "array" 

#create a new attribute name for matrix
names(mtx1) <- c('1','2','3','4','5','6')
#show attributes of matrix again
attributes(mtx1)
$dim
[1] 2 3

$names
[1] "1" "2" "3" "4" "5" "6"
#create a data frame df1
df1 <- data.frame(mtx1)
#print data frame
df1
  X1 X2 X3
1  1  2  3
2  4  5  6
vec1 <-  c("A", "B", "A","B","A","B")
#assign an attribute 'images' to data frame
attr(df1, "images") <-vec1
attributes(df1)
$names
[1] "X1" "X2" "X3"

$class
[1] "data.frame"

$row.names
[1] 1 2

$images
[1] "A" "B" "A" "B" "A" "B"
#show value of attribute 'images' for df1
attr(df1, "images")
[1] "A" "B" "A" "B" "A" "B"
#show class of df1
class(df1)
[1] "data.frame"

We notice that for a print function, the contents and format shown for a matrix and data frame are different. Because print is a generic function in R, which means it applies a different method (actually is function too) for different class. When print() sees a data frame, then a method print.data.frame is applied, because a method with print function exists in R. And the method print.default is applied when a matrix is to be printed out, because there is not a particular method existing for a matrix associated with print function in R. Next code example show this mechanism.

#method for print exist for class 'data.frame'
print.data.frame
function (x, ..., digits = NULL, quote = FALSE, right = TRUE, 
    row.names = TRUE, max = NULL) 
{
    n <- length(row.names(x))
    if (length(x) == 0L) {
        cat(sprintf(ngettext(n, "data frame with 0 columns and %d row", 
            "data frame with 0 columns and %d rows"), n), "\n", 
            sep = "")
    }
    else if (n == 0L) {
        print.default(names(x), quote = FALSE)
        cat(gettext("<0 rows> (or 0-length row.names)\n"))
    }
    else {
        if (is.null(max)) 
            max <- getOption("max.print", 99999L)
        if (!is.finite(max)) 
            stop("invalid 'max' / getOption(\"max.print\"): ", 
                max)
        omit <- (n0 <- max%/%length(x)) < n
        m <- as.matrix(format.data.frame(if (omit) 
            x[seq_len(n0), , drop = FALSE]
        else x, digits = digits, na.encode = FALSE))
        if (!isTRUE(row.names)) 
            dimnames(m)[[1L]] <- if (isFALSE(row.names)) 
                rep.int("", if (omit) 
                  n0
                else n)
            else row.names
        print(m, ..., quote = quote, right = right, max = max)
        if (omit) 
            cat(" [ reached 'max' / getOption(\"max.print\") -- omitted", 
                n - n0, "rows ]\n")
    }
    invisible(x)
}
<bytecode: 0x0000020bd021c5a8>
<environment: namespace:base>
#no method for matrix with generic function 'print'.
print.matrix
Error: object 'print.matrix' not found

#to show all the methods with generic function 'print'
#there are more than 250, show first 20 only
methods(print)
  [1] print.acf*                                          
  [2] print.activeConcordance*                            
  [3] print.AES*                                          
  [4] print.all_vars*                                     
  [5] print.anova*                                        
  [6] print.any_vars*                                     
  [7] print.aov*                                          
  [8] print.aovlist*                                      
  [9] print.ar*                                           
 [10] print.Arima*                                        
 [11] print.arima0*                                       
 [12] print.AsIs                                          
 [13] print.aspell*                                       
 [14] print.aspell_inspect_context*                       
 [15] print.bibentry*                                     
 [16] print.Bibtex*                                       
 [17] print.browseVignettes*                              
 [18] print.by  

#to show all the generic functions which have methods
#for class 'data.frame'
#you can find 'print' in the list
methods(class="data.frame")
 [1] $<-           [             [[            [[<-         
 [5] [<-           aggregate     anyDuplicated anyNA        
 [9] as.data.frame as.list       as.matrix     as.vector    
[13] by            cbind         coerce        dim          
[17] dimnames      dimnames<-    droplevels    duplicated   
[21] edit          filter        format        formula      
[25] head          initialize    intersect     is.na        
[29] Math          merge         na.exclude    na.omit      
[33] Ops           plot          print         prompt       
[37] rbind         row.names     row.names<-   rowsum       
[41] setdiff       setequal      show          slotsFromS3  
[45] split         split<-       stack         str          
[49] subset        summary       Summary       t            
[53] tail          transform     type.convert  union        
[57] unique        unstack       within        xtfrm    

#to show all the generic functions having method for class 'matrix'
#you can not find 'print' in the list
methods(class="matrix")
 [1] anyDuplicated as.data.frame as.raster     boxplot      
 [5] coerce        determinant   duplicated    edit         
 [9] head          initialize    isSymmetric   Math         
[13] Math2         Ops           relist        subset       
[17] summary       tail          unique                         

With the knowledge of S3 class, new class can be created and assigned to an object. And new method can be written for generic function specifically for this new class. In the following code example, we create a new class ‘type’ and assigned to df1. Then new method print.test is created applied when df1 is printed out.

#to set a new class of df1
class(df1)<- 'test'
#define the method associated with generic function 'print'
#for class 'test'
print.test <- function(x) {
  print("this is a test") 
}
#then print of df1 will be different as before
print(df1)
[1] "this is a test"

For getting more knowledge of R, you can watch R tutorial videos on our YouTube channel !


0 Comments

Leave a Reply

Avatar placeholder