--- title: "Introduction to Functions" output: html_document: theme: readable highlight: tango self_contained: false --- ## Key Concepts A function is a basic data recipe. It is also an input-output machine. It accepts arguments, and returns the final product of the recipe. * The function `function()` * arguments * argument values * argument default values * explicit vs implicit argument calls * return values * arrow vs. equal sign ## Loan Calculator Let's create a mortgage calculator as a simple example. A mortgage calculator considers the total loan amount (the principal), the interest rate or APR (annual percentage rate), and the period of the loan in order to determine how much needs to be paid each month so that payments are distributed equally across the loan term. ![](https://res.cloudinary.com/value-penguin/image/upload/c_limit,dpr_1.0,f_auto,h_1600,q_auto,w_1600/v1/mortgages/amort-30-yr) If we look up an amortization (repayment schedule) formula, we see it is calculated as follows: $$ monthly \ payments = \frac{principal \cdot interest \ rate}{1-(1+interest \ rate)^{- \ loan \ duration}} $$ When we translate this mathematical formula into R code, the new function will look like this: ```{r eval=FALSE} calcMortgage <- function( principal, years, APR ) { months <- years * 12 # covert years to months int.rate <- APR / 12 # convert annual rate to monthly # amortization formula monthly.payment <- ( principal * int.rate ) / (1 - (1 + int.rate)^(-months) ) monthly.payment <- round( monthly.payment, 2 ) return( monthly.payment ) } ``` ```{r, include=FALSE} tutorial::go_interactive( greedy=FALSE ) ``` ```{r ex="example-01", type="pre-exercise-code", tut=TRUE} calcMortgage <- function( principal, years, APR ) { months <- years * 12 int.rate <- APR / 12 # amortization formula monthly.payment <- ( principal * int.rate ) / (1 - (1 + int.rate)^(-months) ) monthly.payment <- round( monthly.payment, 2 ) return( monthly.payment ) } ``` ```{r ex="example-01", type="sample-code", tut=TRUE} # Check the function's arguments: args( calcMortgage ) # Calculate a mortgage for a $100,000 house for 30 years with a 4.5 percent interest rate (0.045 APR) calcMortgage( principal=100000, years=30, APR=0.045 ) # Try: calcMortgage( principal=100000 ) calcMortgage( principal=100000, APR=0.045 ) ```
What happens if you omit an argument from the function? Why?
# Default Arguments We can add default values for arguments. These defaults allow us to utilize the function without specifying values for those arguments. ```{r eval=FALSE} calcMortgage <- function( principal, years=30, APR=0.05 ) { months <- years * 12 # covert years to months int.rate <- APR / 12 # convert annual rate to monthly # amortization formula monthly.payment <- ( principal * int.rate ) / (1 - (1 + int.rate)^(-months) ) monthly.payment <- round( monthly.payment, 2 ) return( monthly.payment ) } ``` ```{r ex="example-02", type="pre-exercise-code", tut=TRUE} calcMortgage <- function( principal, years=30, APR=0.05 ) { months <- years * 12 int.rate <- APR / 12 # amortization formula monthly.payment <- ( principal * int.rate ) / (1 - (1 + int.rate)^(-months) ) monthly.payment <- round( monthly.payment, 2 ) return( monthly.payment ) } ``` ```{r ex="example-02", type="sample-code", tut=TRUE} # Notice the new default arguments: args( calcMortgage ) # Calculate a mortgage for a $100,000 house for 30 years with a 4.5 percent APR calcMortgage( principal=100000, years=30, APR=0.045 ) # Now try: calcMortgage( principal=100000 ) calcMortgage( principal=100000 ) ```
Note that **calcMortgage( principal=100000 )** now works because the function uses the default values for years and APR.
## Defaults ```{r ex="example-03", type="pre-exercise-code", tut=TRUE} calcMortgage <- function( principal, years=30, APR=0.045 ) { months <- years * 12 int.rate <- APR / 12 # amortization formula monthly.payment <- ( principal * int.rate ) / (1 - (1 + int.rate)^(-months) ) monthly.payment <- round( monthly.payment, 2 ) return( monthly.payment ) } ``` ```{r ex="example-03", type="sample-code", tut=TRUE} args( calcMortgage ) # Calculate a mortgage for a $100,000 house for 15 years with a 3 percent APR calcMortgage( principal=100000, years=15, APR=0.03 ) ```
Can you still use custom values for those arguments after defaults are set?
# Implicit Argument Calls An explicit call to arguments always uses the formal argument name such as `principal=100000`. You can, however, also use implicit argument calls. These rely on the order arguments are specified in the function, and the order of your values in your call. Implicit arguments calls can be risky, however, because it is very easy to mix them up. ```{r ex="example-04", type="pre-exercise-code", tut=TRUE} calcMortgage <- function( principal, years=30, APR=0.045 ) { months <- years * 12 int.rate <- APR / 12 # amortization formula monthly.payment <- ( principal * int.rate ) / (1 - (1 + int.rate)^(-months) ) monthly.payment <- round( monthly.payment, 2 ) return( monthly.payment ) } ``` ```{r ex="example-04", type="sample-code", tut=TRUE} # Try these: calcMortgage( 100000, 30, 0.05 ) calcMortgage( 30, 100000, 0.05 ) ```
Which of these calculations is correct? Explain why.
# Object Assignment vs Argument Assignment ```{r, eval=F} principal <- 100000 # never use equals here calcMortgage( principal=100000 ) # never use arrows here ```
---- # Your Turn
Create a function to convert Fahrenheit temperatures to Celsius. * What arguments do you need? * How many decimals do you need? Consider using the `round( number, decimals )` function to simplify output. * Don't forget a return statement!
$$ celsius = ( \ fahrenheit − 32 \ ) × \frac{5}{9} $$ If you want to check your work, **212 degees Fahrenheit** is equivalent to **100 degrees Celsius**.
```{r ex="example-05", type="sample-code", tut=TRUE} convertToCelsius <- function() # arguments here { # your code here } temp.in.fahrenheit <- 212 convertToCelsius( temp.in.fahrenheit ) ```
Can you use this function to convert from Celsius to Fahrenheit?

----

```{css, echo=F} div.powered-by-datacamp{ margin-bottom:40px; display: none; } div.datacamp-exercise{ margin-bottom:40px; } .datacamp-exercise .dcl-btn-primary { /* background-color: #fdc551; */ /* color: #6d561e; */ background-color: LightSteelBlue; /* #d9f5ff; #008B8B; */ color: white; /* #008B8B; */ } div.question{ background-color: LightSteelBlue; border-radius: 10px; border: 1px solid lightgray; padding-top:10px; padding-bottom:10px; font-size: 85%; font-family: Verdana; /* font-weight: bold; */ color: white; padding-left:05%; padding-right:05%; margin-bottom:40px; } div.quiz{ background-color: #bcb2a4; /* #b45959; */ border-radius: 10px; border: 1px solid lightgray; padding-top:10px; padding-bottom:10px; font-size: 87%; font-family: Verdana; /* font-weight: bold; */ color: white; padding-left:05%; padding-right:05%; margin-bottom:40px; } body{font-family:system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif; font-size:calc(1.5em + 0.25vw); font-weight:300;line-height:1.65; -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale; margin-left:20%; margin-right:20%} body,aside,main{flex-direction:column} body{display:flex;min-height:100vh} /* body,blockquote,figure{margin:0} */ blockquote,figure{margin:0} #TOC { margin-top:30px; margin-bottom:80px } img { padding:5px; display: block; margin-left: auto; margin-right: auto; /* width: 80%; */ max-width:80%; margin-top:60px; margin-bottom:60px } a{ /* color:inherit; */ color:darkred; text-decoration:inherit; transition:color .2s} a.selected,a:hover{color:#949494} article a,b,strong,th{font-weight:400} h1{ font-weight:300; margin-top:100px !important; margin-bottom:30px; color:darkred; } h2,h3,h4,h5,h6{ font-weight:300; margin-top:60px !important; margin-bottom:30px;} p.caption { text-align: center; font-style: italic; margin-bottom:30px; } article a{color:#68f} article header a, article footer a{font-weight:inherit;color:inherit} /* header time{color:#949494} */ header time{color:green} hr{border:1px solid rgba(148,148,148,0.3);margin:2em 0} blockquote{border-left:4px solid #68f;padding-left:1.5em} /* img{border-radius:2px;max-width:100%;height:auto;margin:.5em 0} */ @media (prefers-color-scheme: light){body{background:#fff !important;color:#000 !important} } @media (prefers-color-scheme: dark){body{background:#282828 !important;color:#fff !important} } main,article{flex-grow:1} header,footer{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center} header nav>*,footer nav>*{margin:0 .8em} header nav>:first-child,footer nav>:first-child{margin-left:0} header nav>:last-child,footer nav>:last-child{margin-right:0} pre{ background:#f7f7f7; /* background:rgba(38,38,38,0.8); color:#fff; */ color:black; border-radius:2px; font-size:.7em; margin:1.5em 0; padding:.8em 1.2em; white-space:pre-wrap; margin-top:30px; margin-bottom:40px } /* display: block; margin-left: auto; margin-right: auto; max-width:80%;} */ p code{ /* background:rgba(148,148,148,0.2); background:#cccccc; */ /* background:#f2f2f2;*/ opacity:.5; border-radius:4px; font-size:.8em; margin:0 .1em; padding:.2em .4em } table{ border-spacing:1px; /* box-shadow:0px 0px 0px 1px rgba(148,148,148,0.16) inset */ margin-top:80px; margin-bottom:100px !important; margin-left: auto; margin-right: auto; align:center} /* tr:hover,tr:nth-child(even) */ td{ /* background:rgba(148,148,148,0.06); */ padding: 3px 10px 3px 10px } th{ /* background:rgba(148,148,148,0.1); */ text-align:inherit} /* th,td{ */ /* box-shadow:0px 0px 0px 1px rgba(148,148,148,0.16); */ /* padding:.5em 1em} */ /* .c{color:#a29f90} .err{color:#960050;background-color:#1e0010} .k{color:#66d9ef} .l{color:#ae81ff} .n{color:#f8f8f2} .o{color:#f92672} .p{color:#f8f8f2} .cm,.cp,.c1,.cs{color:#75715e} .ge{font-style:italic} .gs{font-weight:bold} .kc,.kd{color:#66d9ef} .kn{color:#f92672} .kp,.kr,.kt{color:#66d9ef} .ld{color:#e6db74} .m{color:#ae81ff} .s{color:#e6db74} .na{color:#a6e22e} .nb{color:#f8f8f2} .nc{color:#a6e22e} .no{color:#66d9ef} .nd{color:#a6e22e} .ni{color:#f8f8f2} .ne,.nf{color:#a6e22e} .nl,.nn{color:#f8f8f2} .nx{color:#a6e22e} .py{color:#f8f8f2} .nt{color:#f92672} .nv{color:#f8f8f2} .ow{color:#f92672} .w{color:#f8f8f2} .mf,.mh,.mi,.mo{color:#ae81ff} .sb,.sc,.sd,.s2{color:#e6db74} .se{color:#ae81ff} .sh,.si,.sx,.sr,.s1,.ss{color:#e6db74} .bp,.vc,.vg,.vi{color:#f8f8f2} .il{color:#ae81ff} .gu{color:#75715e} .gd{color:#f92672} .gi{color:#a6e22e} */ h1{font-size:1.85em} /* header h1{margin:0} */ article header{flex-direction:column;align-items:inherit} article header{margin-bottom:1.5em} /* article header h1{margin:.2em 0} */ /* article footer{padding:1em 0} */ /* .footer { background-color:#726e6e; height:100px; color:white; padding: 20px 3px 20px 3px; position: absolute; min-width:100%; max-width:100%; margin:0px; width:100%; } */ .footer { background-color:#726e6e; height:100px; color:white; padding: 20px 3px 20px 3px; position: absolute; left: 0; right: 0; width: 100%; margin-top:80px; } .footer a{ color:orange; text-decoration:bold !important; } /* nav{margin:.5em 0} */ body>header h1{width:100%;line-height:1.8;margin-bottom:.5em} /* The navigation bar */ .navbar { overflow: hidden; /* background-color: #333; */ background-color: #f7f7f7; color: orange; /* position: fixed; */ /* Set the navbar to fixed position */ top: 0; /* Position the navbar at the top of the page */ width: 100%; /* Full width */ } /* Links inside the navbar */ .nav.navbar-nav li a { /* background: #ddd; #f7f7f7 */ color: darkgray; } /* Change background on mouse-over */ .nav.navbar-nav li a:hover { /* background: #ddd; #f7f7f7 */ color: orange; } /* highlight current tab */ .navbar-inverse .navbar-nav>.active>a, .navbar-inverse .navbar-nav>.active>a:focus, .navbar-inverse .navbar-nav>.active>a:hover { color: black; background-color: #f7f7f7; } ``` ```{r, eval=F, echo=F} p { color: black; margin: 0 0 20px 0; } td { padding: 3px 10px 3px 10px; text-align: center; } table { margin-left: auto; margin-right: auto; margin-top:80px; margin-bottom:100px; } h1, h2{ margin-top:100px; margin-bottom:40px; } H5{ text-align: center; color: gray; font-size:0.8em; } img { max-width: 90%; display: block; margin-right: auto; margin-left: auto; margin-top:30px; margin-bottom:40px; } div.powered-by-datacamp{ margin-bottom:40px; display: none; } div.datacamp-exercise{ margin-bottom:40px; } div.sourceCode { margin-bottom:40px; margin-bottom:60px; } pre.code { display: block; margin-bottom:20px; margin-bottom:20px; } code { font-size: 92%; margin-bottom: 10px; margin-top: 10px; } ```