<p><div><div><div><div data-width="100" data-show-faces="false" data-send="true" data-layout="button_count" data-height="21" data-href="https://www.r-bloggers.com/a-simple-guide-to-s3-methods/"></div></div><div><a data-url="https://www.r-bloggers.com/a-simple-guide-to-s3-methods/" data-counturl="https://www.r-bloggers.com/a-simple-guide-to-s3-methods/" data-count="horizontal" data-text="A Simple Guide to S3 Methods" class="twitter-share-button" data-via="rbloggers" href="https://twitter.com/share"></a></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://njtierney.github.io/r/missing%20data/rbloggers/2016/11/06/simple-s3-methods/"> njtierney - rbloggers</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>A few months ago <a target="_blank" rel="nofollow" href="http://www.njtierney.com/r/rbloggers/2016/08/26/SimpleS3/">I wrote about</a> my first solo author submission to the <a target="_blank" rel="nofollow" href="https://journal.r-project.org/">R Journal</a> entitled, “A Simple Guide to S3 Methods”. Unfortunately the article didn’t make it to publication on the R Journal, but admittedly that might have been a bit of a long shot.</p>
<p>So, I thought that it might be good if I instead share the article here on my blog and r bloggers, so that people can comment below and share their thoughts.</p>
<p>It is not a complete guide to S3 methods, but more a primer the on <em>what</em> <em>how</em>, and <em>why</em> S3.</p>
<p>Here we go.</p>
<p>Writing functions in R is an important skill for anyone using R. S3 methods allow for functions to be generalised across different classes and are easy to implement. Whilst many R users are be adept at creating their own functions, it seems that there is room for many more to take advantage of R’s S3 methods. This paper provides a simple and targeted guide to explain what S3 methods are, why people should them, and how they can do it.</p>
<p>A standard principle of programming is DRY – Don’t Repeat Yourself. Under this axiom, the copying and pasting of the same or similar code (copypasta), is avoided and instead replaced with a function, macro, or similar. Having one function to replace several of the same or similar coded sections simplifies code maintenance as it means that only one section of code needs to be maintained, instead of several. This means that if the code breaks, then one simply needs to update the function, rather than finding all of the coded sections that are now broken.</p>
<p>S3 methods in the R programming language are a way of writing functions in R that do different things for objects of different classes. S3 methods are so named as the methods shipped with the release of the third version of the “S” programming language, which R was heavily based upon [@chambers1992, @rclassmethods, @R]. Hence, methods for S 3.0 = S3 Methods.</p>
<p>The function <code>summary()</code> is an S3 method. When applied to an object of class <code>data.frame</code>, <code>summary</code> shows descriptive statistics (Mean, SD, etc.) for each variable. For example, <code>iris</code> is of class <code>data.frame</code>:</p>
<div>
<pre><code><span>class</span><span>(</span><span>iris</span><span>)</span><span>
</span></code></pre>
</div>
<div>
<pre><code>## [1] &quot;data.frame&quot;
</code></pre>
</div>
<p>So applying <code>summary</code> to <code>iris</code> gives us summary information relevant to a dataframe</p>
<div>
<pre><code><span>summary</span><span>(</span><span>iris</span><span>)</span><span>
</span></code></pre>
</div>
<div>
<pre><code>##   Sepal.Length    Sepal.Width     Petal.Length    Petal.Width   
##  Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100  
##  1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300  
##  Median :5.800   Median :3.000   Median :4.350   Median :1.300  
##  Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199  
##  3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800  
##  Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500  
##        Species  
##  setosa    :50  
##  versicolor:50  
##  virginica :50  
##                 
##                 
## 
</code></pre>
</div>
<p><code>summary</code> also performs differently when applied to different object. In fact, you can find all the classes that work with an S3 method by typing the following:</p>
<div>
<pre><code><span>methods</span><span>(</span><span>summary</span><span>)</span><span>
</span></code></pre>
</div>
<div>
<pre><code>##  [1] summary.aov                    summary.aovlist*              
##  [3] summary.aspell*                summary.check_packages_in_dir*
##  [5] summary.connection             summary.data.frame            
##  [7] summary.Date                   summary.default               
##  [9] summary.ecdf*                  summary.factor                
## [11] summary.glm                    summary.infl*                 
## [13] summary.lm                     summary.loess*                
## [15] summary.manova                 summary.matrix                
## [17] summary.mlm*                   summary.nls*                  
## [19] summary.packageStatus*         summary.PDF_Dictionary*       
## [21] summary.PDF_Stream*            summary.POSIXct               
## [23] summary.POSIXlt                summary.ppr*                  
## [25] summary.prcomp*                summary.princomp*             
## [27] summary.proc_time              summary.srcfile               
## [29] summary.srcref                 summary.stepfun               
## [31] summary.stl*                   summary.table                 
## [33] summary.tukeysmooth*          
## see '?methods' for accessing help and source code
</code></pre>
</div>
<p>There’s over 30 different methods!</p>
<p>We can use summary on a linear model, for example:</p>
<div>
<pre><code><span>lm_iris</span><span> </span><span>&lt;-</span><span> </span><span>lm</span><span>(</span><span>Sepal.Length</span><span> </span><span>~</span><span> </span><span>Sepal.Width</span><span>,</span><span> </span><span>data</span><span> </span><span>=</span><span> </span><span>iris</span><span>)</span><span>
</span><span>summary</span><span>(</span><span>lm_iris</span><span>)</span><span>
</span></code></pre>
</div>
<div>
<pre><code>## 
## Call:
## lm(formula = Sepal.Length ~ Sepal.Width, data = iris)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -1.5561 -0.6333 -0.1120  0.5579  2.2226 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   6.5262     0.4789   13.63   &lt;2e-16 ***
## Sepal.Width  -0.2234     0.1551   -1.44    0.152    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.8251 on 148 degrees of freedom
## Multiple R-squared:  0.01382,	Adjusted R-squared:  0.007159 
## F-statistic: 2.074 on 1 and 148 DF,  p-value: 0.1519
</code></pre>
</div>
<p><code>summary</code> produces a description of the linear model, describing how it was called (<code>call</code>), as well as the <code>residuals</code>, <code>coefficients</code>, <code>t-values</code>, <code>p-values</code>, $R^2$, and more. This output is <strong>completely</strong> different to the information output from <code>summary</code> used for the <code>iris</code> dataframe.</p>
<p>So how does the same function, <code>summary</code> perform differently for different objects? The answer is that R is helpful, and <em>hides</em> this information. There are in fact, many different <code>summary</code> functions. For example:</p>
<ul>
<li><code>summary.lm</code></li>
<li><code>summary.data.frame</code></li>
<li><code>summary.Date</code></li>
<li><code>summary.matrix</code></li>
</ul>
<p>Being an S3 method, <code>summary</code> calls the appropriate function based upon the class of the object it operates on. So using <code>summary</code> on an object of class “Date” will evoke the function, <code>summary.Date</code>. <strong>But all you need to do is type <code>summary</code></strong>, and the S3 method does the rest. By abstracting away this detail (the object class), the intent becomes clearer.</p>
<p>To further illustrate, using <code>summary</code> on the <code>iris</code> data will actually call the function <code>summary.data.frame</code>, since <code>iris</code> is of class <code>data.frame</code>. We can find the class of an object using <code>class</code></p>
<div>
<pre><code><span>class</span><span>(</span><span>iris</span><span>)</span><span>
</span></code></pre>
</div>
<div>
<pre><code>## [1] &quot;data.frame&quot;
</code></pre>
</div>
<div>
<pre><code><span>summary.data.frame</span><span>(</span><span>iris</span><span>)</span><span>
</span></code></pre>
</div>
<div>
<pre><code>##   Sepal.Length    Sepal.Width     Petal.Length    Petal.Width   
##  Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100  
##  1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300  
##  Median :5.800   Median :3.000   Median :4.350   Median :1.300  
##  Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199  
##  3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800  
##  Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500  
##        Species  
##  setosa    :50  
##  versicolor:50  
##  virginica :50  
##                 
##                 
## 
</code></pre>
</div>
<p>which is the same as <code>summary(iris)</code></p>
<div>
<pre><code><span>sum1_df</span><span> </span><span>&lt;-</span><span> </span><span>summary.data.frame</span><span>(</span><span>iris</span><span>)</span><span>
</span><span>sum2_df</span><span> </span><span>&lt;-</span><span> </span><span>summary</span><span>(</span><span>iris</span><span>)</span><span>
</span><span>all.equal</span><span>(</span><span>sum1_df</span><span>,</span><span> </span><span>sum2_df</span><span>)</span><span>
</span></code></pre>
</div>
<div>
<pre><code>## [1] TRUE
</code></pre>
</div>
<p>And using summary on the linear model object, <code>lm_iris</code> performs:</p>
<div>
<pre><code><span>summary.lm</span><span>(</span><span>lm_iris</span><span>)</span><span>
</span></code></pre>
</div>
<div>
<pre><code>## 
## Call:
## lm(formula = Sepal.Length ~ Sepal.Width, data = iris)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -1.5561 -0.6333 -0.1120  0.5579  2.2226 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   6.5262     0.4789   13.63   &lt;2e-16 ***
## Sepal.Width  -0.2234     0.1551   -1.44    0.152    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.8251 on 148 degrees of freedom
## Multiple R-squared:  0.01382,	Adjusted R-squared:  0.007159 
## F-statistic: 2.074 on 1 and 148 DF,  p-value: 0.1519
</code></pre>
</div>
<p>the same as <code>summary(lm_iris)</code></p>
<div>
<pre><code><span>sum1_lm</span><span> </span><span>&lt;-</span><span> </span><span>summary.lm</span><span>(</span><span>lm_iris</span><span>)</span><span>
</span><span>sum2_lm</span><span> </span><span>&lt;-</span><span> </span><span>summary</span><span>(</span><span>lm_iris</span><span>)</span><span>
</span><span>all.equal</span><span>(</span><span>sum1_lm</span><span>,</span><span> </span><span>sum2_lm</span><span>)</span><span>
</span></code></pre>
</div>
<div>
<pre><code>## [1] TRUE
</code></pre>
</div>
<p>One could coerce a different method upon a different class, for example using <code>summary.data.frame</code> on an “lm” object:</p>
<div>
<pre><code><span>summary.data.frame</span><span>(</span><span>lm_iris</span><span>)</span><span>
</span></code></pre>
</div>
<div>
<pre><code>##   coefficients       residuals          effects               rank  
##  Min.   :-0.2234   Min.   :-1.5561   Min.   :-71.56593   Min.   :2  
##  1st Qu.: 1.4640   1st Qu.:-0.6333   1st Qu.: -0.65192   1st Qu.:2  
##  Median : 3.1514   Median :-0.1120   Median : -0.00897   Median :2  
##  Mean   : 3.1514   Mean   : 0.0000   Mean   : -0.42040   Mean   :2  
##  3rd Qu.: 4.8388   3rd Qu.: 0.5579   3rd Qu.:  0.61051   3rd Qu.:2  
##  Max.   : 6.5262   Max.   : 2.2225   Max.   :  2.15225   Max.   :2  
##  fitted.values       assign     qr.Length  qr.Class  qr.Mode  df.residual 
##  Min.   :5.543   Min.   :0.00   300      -none-   numeric    Min.   :148  
##  1st Qu.:5.789   1st Qu.:0.25     2      -none-   numeric    1st Qu.:148  
##  Median :5.856   Median :0.50     2      -none-   numeric    Median :148  
##  Mean   :5.843   Mean   :0.50     1      -none-   numeric    Mean   :148  
##  3rd Qu.:5.901   3rd Qu.:0.75     1      -none-   numeric    3rd Qu.:148  
##  Max.   :6.080   Max.   :1.00                                Max.   :148  
##    xlevels         call         terms        
##  Length:0      Length:3      Length:3        
##  Class :list   Class :call   Class1:terms    
##  Mode  :list   Mode  :call   Class2:formula  
##                              Mode  :call     
##                                              
##                                              
##  model.Sepal.Length  model.Sepal.Width 
##  Min.   :4.300000    Min.   :2.000000  
##  1st Qu.:5.100000    1st Qu.:2.800000  
##  Median :5.800000    Median :3.000000  
##  Mean   :5.843333    Mean   :3.057333  
##  3rd Qu.:6.400000    3rd Qu.:3.300000  
##  Max.   :7.900000    Max.   :4.400000
</code></pre>
</div>
<p>However the output may be a bit confusing.</p>
<p>To summarize, the important feature of S3 methods worth noting is that only the <strong>first part</strong>, <code>summary</code>, is required to be used on these objects of different classes.</p>
<h1>Why hide the text?</h1>
<p>Hiding the trailing text after the <code>.</code> avoids the need to use a different <code>summary</code> function for every class. This means that one does not need to remember to use <code>summary.lm</code> for linear models, or <code>summary.data.frame</code> for data frames, or <code>summary.aProposterousClassOfObject</code>. By using S3 methods, cognitive load is reduced – you don’t have to think as much to remember what class an object is – and the commands are more intuitive. To get a summary of most objects, use <code>summary</code>, to plot most objects, use <code>plot</code>. Perhaps the most nifty feature of all is that a user can create their own S3 methods using the same functions such as <code>summary</code> and <code>plot</code>. This means a user can create their own special class of object</p>
<div>
<pre><code><span>test_class</span><span> </span><span>&lt;-</span><span> </span><span>1</span><span>:</span><span>10</span><span>
</span><span>class</span><span>(</span><span>test_class</span><span>)</span><span> </span><span>&lt;-</span><span> </span><span>&quot;myclass&quot;</span><span>
</span><span>class</span><span>(</span><span>test_class</span><span>)</span><span>
</span></code></pre>
</div>
<div>
<pre><code>## [1] &quot;myclass&quot;
</code></pre>
</div>
<p>and then write their own S3 method for it – e.g., <code>summary.myclass</code> or <code>plot.myclass</code>, each proiding appropriate summary information, or nice plots, for that object.</p>
<h1>How to make your own S3 method?</h1>
<p>Creating your own S3 method is not particularly difficult and is usually highly practical. A use case scenario for creating an S3 method is now discussed.</p>
<p>The Residual Sums of Squares (RSS), $\sum(Y_i – \hat{Y})^2$ is a useful metric for determining model accuracy for continuous outcomes. For example, for a Classification and Regression Tree</p>
<div>
<pre><code><span>library</span><span>(</span><span>rpart</span><span>)</span><span>
</span><span>fit.rpart</span><span> </span><span>&lt;-</span><span> </span><span>rpart</span><span>(</span><span>Sepal.Width</span><span> </span><span>~</span><span> </span><span>Sepal.Length</span><span> </span><span>+</span><span> </span><span>Petal.Length</span><span> </span><span>+</span><span> </span><span>Petal.Width</span><span> </span><span>+</span><span> </span><span>Species</span><span>,</span><span> </span><span>data</span><span> </span><span>=</span><span> </span><span>iris</span><span>)</span><span>
</span></code></pre>
</div>
<p>The RSS is calculated as</p>
<div>
<pre><code><span>print_rss</span><span> </span><span>&lt;-</span><span> </span><span>sum</span><span>(</span><span>residuals</span><span>(</span><span>fit.rpart</span><span>)</span><span>**</span><span>2</span><span>)</span><span>
</span></code></pre>
</div>
<p>One might be inclined to write a function to perform this task</p>
<div>
<pre><code><span>rss</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>x</span><span>){</span><span>
</span><span>sum</span><span>(</span><span>residuals</span><span>(</span><span>x</span><span>)</span><span>**</span><span>2</span><span>)</span><span>
</span><span>}</span><span>
</span><span>rss</span><span>(</span><span>fit.rpart</span><span>)</span><span>
</span></code></pre>
</div>
<div>
<pre><code>## [1] 10.17245
</code></pre>
</div>
<p>However, there are many different decision tree models that one would like to compare, say boosted regression trees (BRT), and random forests (RF). The same code will not work:</p>
<div>
<pre><code><span>library</span><span>(</span><span>randomForest</span><span>)</span><span>
</span><span>set.seed</span><span>(</span><span>71</span><span>)</span><span>
</span><span>fit.rf</span><span> </span><span>&lt;-</span><span> </span><span>randomForest</span><span>(</span><span>Sepal.Length</span><span> </span><span>~</span><span> </span><span>.</span><span>,</span><span> </span><span>data</span><span>=</span><span>iris</span><span>,</span><span> </span><span>importance</span><span>=</span><span>TRUE</span><span>,</span><span>
</span><span>proximity</span><span>=</span><span>TRUE</span><span>)</span><span>
</span><span>rss</span><span>(</span><span>fit.rf</span><span>)</span><span>
</span></code></pre>
</div>
<div>
<pre><code>## [1] 0
</code></pre>
</div>
<p>In this case, one could write three functions, one for each decision tree method: “rss_rpart”, “rss_brt”, and “rss_rf”. But to avoid having three functions and instead use just one, one could place all three functions inside of one function, using an if-then-else clause to direct the object of the appropriate class to the appropriate method. This shall be referred to as a “Poor man’s S3 method”.</p>
<div>
<pre><code><span>dt_rss</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span> </span><span>(</span><span>x</span><span>){</span><span>
</span><span>if</span><span> </span><span>(</span><span>&quot;rpart&quot;</span><span> </span><span>%in%</span><span> </span><span>class</span><span>(</span><span>x</span><span>))</span><span> </span><span>{</span><span>
</span><span>result</span><span> </span><span>&lt;-</span><span> </span><span>sum</span><span>((</span><span>residuals</span><span>(</span><span>x</span><span>)</span><span>**</span><span>2</span><span>))</span><span>
</span><span>return</span><span>(</span><span>result</span><span>)</span><span>
</span><span>}</span><span>
</span><span>else</span><span> </span><span>if</span><span> </span><span>(</span><span>&quot;gbm&quot;</span><span> </span><span>%in%</span><span> </span><span>class</span><span>(</span><span>x</span><span>))</span><span> </span><span>{</span><span>
</span><span>result</span><span> </span><span>&lt;-</span><span> </span><span>sum</span><span>(</span><span>x</span><span>$</span><span>residuals</span><span>**</span><span>n</span><span>2</span><span>)</span><span>
</span><span>return</span><span>(</span><span>result</span><span>)</span><span>
</span><span>}</span><span>
</span><span>else</span><span> </span><span>if</span><span> </span><span>(</span><span>&quot;randomForest&quot;</span><span> </span><span>%in%</span><span> </span><span>class</span><span>(</span><span>x</span><span>))</span><span> </span><span>{</span><span>
</span><span>temp</span><span> </span><span>&lt;-</span><span> </span><span>x</span><span>$</span><span>y</span><span> </span><span>-</span><span> </span><span>x</span><span>$</span><span>predicted</span><span> </span><span>result</span><span> </span><span>&lt;-</span><span> </span><span>sum</span><span>(</span><span>temp</span><span>**</span><span>2</span><span>)</span><span> </span><span>return</span><span>(</span><span>result</span><span>)</span><span>
</span><span>}</span><span>
</span><span>else</span><span> </span><span>warning</span><span>(</span><span>paste</span><span>(</span><span>class</span><span>(</span><span>x</span><span>),</span><span> </span><span>&quot;is not of an rpart, gbm, or randomForest object&quot;</span><span>))</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
<p>Here it is in action</p>
<div>
<pre><code><span>dt_rss</span><span>(</span><span>fit.rpart</span><span>)</span><span>
</span></code></pre>
</div>
<div>
<pre><code>## [1] 10.17245
</code></pre>
</div>
<p>The RSS method works, and if it is applied to a class that is not known, a special message is provided</p>
<div>
<pre><code><span>fit.lm</span><span> </span><span>&lt;-</span><span> </span><span>lm</span><span>(</span><span>Sepal.Width</span><span> </span><span>~</span><span> </span><span>Species</span><span>,</span><span> </span><span>data</span><span> </span><span>=</span><span> </span><span>iris</span><span>)</span><span>
</span><span>dt_rss</span><span>(</span><span>fit.lm</span><span>)</span><span>
</span></code></pre>
</div>
<div>
<pre><code>## Warning in dt_rss(fit.lm): lm is not of an rpart, gbm, or randomForest
## object
</code></pre>
</div>
<p>The “poor man’s S3 method” does what it needs to do.<br>
However, one must ask how sustainable this would be for an entire programming language? Imagine if a colleague creates a new tree method that needs it’s own <code>rss()</code>. He will need to convince the maintainer to add his class into your ifelse() chain. Failing this, he could just overwrite the function <code>rss()</code>, with predictably disastrous results. In reality, it’s probably better to do all of these things with one method. R’s S3 methods mean that R developers can utilise a common interface without having to update it when new classes come along. It also means overloading clashes are less likely.</p>
<p>So let us create an S3 method to demonstrate.</p>
<p>First define the S3 method with <code>UseMethod()</code></p>
<div>
<pre><code><span>rss</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>x</span><span>)</span><span> </span><span>UseMethod</span><span>(</span><span>&quot;rss&quot;</span><span>)</span><span>
</span></code></pre>
</div>
<p>This creates the building block of an S3 method, the “root”, if you will.</p>
<p>Here we have specified that our method will be called <code>rss</code>. Now we need to create the special cases of rss – the methods <code>rss.rpart</code>, <code>rss.gbm</code>, and <code>rss.randomForest</code>, where the sections of code after <code>rss.</code> are the classes of object we want them to work on.</p>
<p>A default method can also be created – <code>rss.default</code> – which, as the name suggests, is the default method when the argument <code>x</code> is not a class that has a specific version of the method defined.</p>
<div>
<pre><code><span>rss.default</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>x</span><span>,</span><span> </span><span>...</span><span>){</span><span>
</span><span>warning</span><span>(</span><span>paste</span><span>(</span><span>&quot;RSS does not know how to handle object of class &quot;</span><span>,</span><span> </span><span>class</span><span>(</span><span>x</span><span>),</span><span> </span><span>&quot;and can only be used on classes rpart, gbm, and randomForest&quot;</span><span>))</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
<p>In this case a warning is issued, to let the user know that the object class they were using was not appropriate.</p>
<p>We can now apply the <code>rss</code> method to an <code>rpart</code> model</p>
<div>
<pre><code><span>rss</span><span>(</span><span>fit.rpart</span><span>)</span><span>
</span></code></pre>
</div>
<div>
<pre><code>## [1] 10.17245
</code></pre>
</div>
<p>Also observe what happens when the object used is not of the decision tree classes:</p>
<div>
<pre><code><span>rss</span><span>(</span><span>lm.fit</span><span>)</span><span>
</span></code></pre>
</div>
<div>
<pre><code>## Warning in rss.default(lm.fit): RSS does not know how to handle object of
## class function and can only be used on classes rpart, gbm, and randomForest
</code></pre>
</div>
<p>This guide to S3 methods was written to provide R users with the minimal amount of information to start building their own S3 methods. For a more complete treatment on S3 methods, see <a target="_blank" rel="nofollow" href="http://njtierney.github.io/r/missing%20data/rbloggers/2016/11/06/simple-s3-methods/">Advanced-R</a>, <a target="_blank" rel="nofollow" href="http://njtierney.github.io/r/missing%20data/rbloggers/2016/11/06/simple-s3-methods/">R Packages</a>, and the <a target="_blank" rel="nofollow" href="http://njtierney.github.io/r/missing%20data/rbloggers/2016/11/06/simple-s3-methods/">official S3 documentation</a>.</p>
<p><div><div><div><div data-width="55" data-show-faces="false" data-send="true" data-layout="box_count" data-height="62" data-href="https://www.r-bloggers.com/a-simple-guide-to-s3-methods/"></div></div><div><a data-url="https://www.r-bloggers.com/a-simple-guide-to-s3-methods/" data-counturl="https://www.r-bloggers.com/a-simple-guide-to-s3-methods/" data-count="vertical" data-text="A Simple Guide to S3 Methods" class="twitter-share-button" data-via="rbloggers" href="https://twitter.com/share"></a></div><div></div></div><div></div></div>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="http://njtierney.github.io/r/missing%20data/rbloggers/2016/11/06/simple-s3-methods/"> njtierney - rbloggers</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" rel="nofollow" href="https://www.r-project.org/">R</a> news and <a title="R tutorials" rel="nofollow" href="https://www.r-bloggers.com/?s=tutorial">tutorials</a> on topics such as: <a title="Data science" rel="nofollow" href="https://www.r-bloggers.com/?s=data%20science">Data science</a>, <a title="Big Data" rel="nofollow" href="https://www.r-bloggers.com/?s=Big%20Data">Big Data, <a title="R jobs" rel="nofollow" href="https://www.r-users.com/">R jobs</a>, visualization (<a title="ggplot and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/?s=ggplot2">ggplot2</a>, <a title="Boxplots using lattice and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/?s=boxplot">Boxplots</a>, <a title="Maps and gis" rel="nofollow" href="https://www.r-bloggers.com/?s=map">maps</a>, <a title="Animation in R" rel="nofollow" href="https://www.r-bloggers.com/?s=animation">animation</a>), programming (<a title="RStudio IDE for R" rel="nofollow" href="https://www.r-bloggers.com/?s=RStudio">RStudio</a>, <a title="Sweave and literate programming" rel="nofollow" href="https://www.r-bloggers.com/?s=sweave">Sweave</a>, <a title="LaTeX in R" rel="nofollow" href="https://www.r-bloggers.com/?s=LaTeX">LaTeX</a>, <a title="SQL and databases" rel="nofollow" href="https://www.r-bloggers.com/?s=SQL">SQL</a>, <a title="Eclipse IDE for R" rel="nofollow" href="https://www.r-bloggers.com/?s=eclipse">Eclipse</a>, <a title="git and github, Version Control System" rel="nofollow" href="https://www.r-bloggers.com/?s=git">git</a>, <a title="Large data in R using Hadoop" rel="nofollow" href="https://www.r-bloggers.com/?s=hadoop">hadoop</a>, <a title="Web Scraping of google, facebook, yahoo, twitter and more using R" rel="nofollow" href="https://www.r-bloggers.com/?s=Web+Scraping">Web Scraping</a>) statistics (<a title="Regressions and ANOVA analysis tutorials" rel="nofollow" href="https://www.r-bloggers.com/?s=regression">regression</a>, <a title="principal component analysis tutorial" rel="nofollow" href="https://www.r-bloggers.com/?s=PCA">PCA</a>, <a title="Time series" rel="nofollow" href="https://www.r-bloggers.com/?s=time+series">time series</a>, <a title="finance trading" rel="nofollow" href="https://www.r-bloggers.com/?s=trading">trading</a>) and more...
<img height="1" alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/LZRDBN7qVjk"></a></div>