Intro to R Course
  • Prepare for the course
  • Copyright
  • Practical Sessions
  • Resources
  • Source Code
  • Report an issue
  1. Session 1
  2. Functions that make the work
  • Welcome
  • Session 1
    • Getting familiar with RStudio
    • Setting up your Workspace
    • Functions that make the work
  • Session 2
    • Data manipulation using the Tidyverse
    • Filtering rows
    • Creating variables
    • Grouping and summarising
  • Session 3
    • Intro to Data Cleaning
    • Variable Class
    • Recoding variables
    • Derived Variables & Export
  • Session 4
    • Counting cases
    • Crosstabulations and richer tables
    • Tables of things you cannot count
    • The whole table in one line

On this page

  • Part 7 · Functions as Grammar Models
    • What is a function?
    • Your first verbs
  • Part 8 · Vectors and columns
    • A dataframe is a collection of vectors
  • Part 9 · Numeric functions on vectors
  • Exercise summary
  1. Session 1
  2. Functions that make the work

Functions that make the work

Session 1 practical exercises

Your head of department, Kassandra, has just handed you a small sample of the unit’s surveillance data set (imd_S1.xlsx) — a few dozen cases from the invasive meningococcal disease registry. They are still working on your data permit, but this very little linelist can be useful for you to become acquainted with the data, and do a bit of practice before the actual work begins in a few days

“Get familiar with it”, she said. Before any analysis, before any cleaning, before any conclusions: you need to know what you are working with. That is what this exercise is about. If you haven’t done it yet, go to the data set page to learn about the data you will be using through this course.

Make sure imd_raw is loaded in your Environment before you start. If it is not, go back to E2 and re-run your import lines.

Part 7 · Functions as Grammar Models

What is a function?

You have already used several functions: here::here(), rio::import(), pacman::p_load(). But what exactly is a function?

Think back to your language classes. A sentence needs a verb — an action word — to mean anything. “Run”, “calculate”, “summarise” — verbs tell you what is happening. In R, functions are verbs. They tell R what action to perform.

This is the Grammar Model we will use throughout the course:

Writing code is the art of giving precise instructions. Every instruction has a verb (the function), something to act on (the object), and sometimes additional specifications (the arguments).

verb(object, argument = specification)
  • In plain English: “Calculate the mean of age, removing missing values.”
  • In R: mean(imd_raw$age, na.rm = TRUE)

The parallel is exact:

Grammar R code Example
Verb Function name mean
Object What you act on imd_raw$age
Modifier Named argument na.rm = TRUE

This model will not change. Every function you learn from here on fits this structure — the verbs will multiply, but the grammar stays the same.

TipSpelling and capitalisation matter!

The language analogy also applies to spelling, R will not understand if you type mena instead of mean.

R is case-sensitive, it will not understand MEAN or Mean, only mean.

Your first verbs

Let us start with three simple functions that ask questions about your data set:

Action — Run these lines one by one and read what R tells you:

nrow(imd_raw)   
ncol(imd_raw)
names(imd_raw)

Each of these is a verb acting on the same object (imd_raw) but asking a different question:

  • nrow() — “How many rows does this have?”
  • ncol() — “How many columns does this have?”
  • names() — “What are the column names?”

Notice that none of these need additional arguments. The object alone is enough. Some verbs are simple — just an action and a target.

In the Grammar Model, what does the function name represent?

By the way, did you realize how the previous functions created different outputs? nrow() and ncol() just produced one number - the answer to the question is just that; but names() produced something different, an answer with more than one reply. Because there is more than one column, the answer to that question has to be all existing names

In R this is called a vector

Part 8 · Vectors and columns

Vectors are a sequence of values living together in a single object. R is a vectorised programming language, meaning that information is processed though these. In fact, your entire dataframe is built as a collection of columns representing variables, with each column constituting a vector itself.

A dataframe is a collection of vectors

When you ran names(imd_raw), R listed the column names of your dataframe. Each of those columns is a vector — a sequence of values of the same type.

Think of a dataframe as a table where: - Each row is one observation (one case) - Each column is one variable — and that column is a vector

This means your dataframe imd_raw is not one object — it is many vectors living together in a shared structure. To extract a single column from a dataframe, use the $ operator like this:

imd_raw$age

This tells R: “From the object imd_raw, give me the column called age.” R will print all the values in that column.

Action — Extract a few more columns and observe what R returns

TipRStudio support

Notice when you write the $ operator after the dataframe name, RStudio opens a little pop-up list containing the variable names. This can make it easier to navigate, and you can also start typing the name and the available names will narrow down to match your “search”

As any other piece of information in R, you could very well start from loaded data and extract one variable into a new object for further use. Let’s do it for the sake of teaching - and then you will understand why it wouldn’t be necessary in the first place

Action — Save the age of your cases in a new object named patients_age

And, since we have the object in our Environment, let’s show something else. Before, you used nrow() to ask how many observations/row the data had. Now we have a vector, and we want to know how many values it contains, for which we have a function called length()

Action — Compare the number of rows in imd_raw and the values contained in patients_age. Would you create an object for this action?

nrow(imd_raw)
length(patients_age)
NoteReflection question

When should you store information in new objects and when should you just call the function to print the result?

This is not a minor question. Creating objects is the way of granting information is not lost. However, is it always necessary to keep the result? Sometimes you may just want to quickly check something, but the information serves no other purpose. So always think about the print vs assign key feature of R

Both functions should return the same number — because each column has exactly one value per row, thus making the number of rows identical to the number of items contained in the vector of the age column of the data

What is a vector in R?

Part 9 · Numeric functions on vectors

Now that you know how to extract a column, you can apply functions to it. This is where R starts to become genuinely useful. During the presentation, we saw the functions mean() and sum() in action. Now it’s your turn:

Action — What is the mean age of your current cases? Use your age object and the data column and compare the result

As you can see, there is no point in creating an intermediate object when you can directly access the data using the $ operator. This is usually the quickest way of accessing information within dataframes, and dataframes will be our main working objects for data analysis

Let’s try a few more numeric functions, to see their different outputs

Action — Run these functions on the age column:

mean(imd_raw$age)
sum(imd_raw$age)
min(imd_raw$age)
max(imd_raw$age)
range(imd_raw$age)
quantile(imd_raw$age)
table(imd_raw$age)

Read the output of each one carefully. Notice that range() returns two values and quantile() returns five — vectors can hold multiple values, and functions can return multiple values. Each of those functions is answering a very specific question. Think about their Grammar Model

Exercise summary

You are done with the Session 1 practicals. You now have a working R Project, your packages loaded, your data imported, and your first functions under your belt. In Session 2 you will meet Kassandra, and you will learn about the true power of R: the Tidyverse.

This is what you practiced and learned:

Grammar Model Function = verb, object = what to act on, arguments = modifiers
nrow() , ncol() , names() Ask basic questions about a dataframe’s structure
$ Extracts a column from a dataframe as a vector
class() Returns the type of an object or column
length() Returns the number of elements in a vector
mean() , sum() , min() , max() Numeric summaries of a vector
range() , quantile() Return multiple values describing the distribution
table() Counts occurrences of each value in a categorical vector
Setting up your Workspace
Data manipulation using the Tidyverse
Source Code
---
title: "Functions that make the work"
subtitle: "Session 1 practical exercises"
format:
  html:
    code-fold: false
---

```{r}
#| include: false
library(webexercises)
```

Your head of department, Kassandra, has just handed you a small sample of the unit's surveillance data set (`imd_S1.xlsx`) — a few dozen cases from the invasive meningococcal disease registry. They are still working on your data permit, but this very little linelist can be useful for you to become acquainted with the data, and do a bit of practice before the actual work begins in a few days

*"Get familiar with it"*, she said. Before any analysis, before any cleaning, before any conclusions: you need to know what you are working with. That is what this exercise is about. If you haven't done it yet, go to the data set page to learn about the data you will be using through this course.

Make sure `imd_raw` is loaded in your Environment before you start. If it is not, go back to E2 and re-run your import lines.

## Part 7 · Functions as Grammar Models

### What is a function?

You have already used several functions: `here::here()`, `rio::import()`, `pacman::p_load()`. But what exactly is a function?

Think back to your language classes. A sentence needs a **verb** — an action word — to mean anything. *"Run"*, *"calculate"*, *"summarise"* — verbs tell you what is happening. In R, **functions are verbs**. They tell R what action to perform.

This is the Grammar Model we will use throughout the course:

> **Writing code is the art of giving precise instructions.** Every instruction has a verb (the function), something to act on (the object), and sometimes additional specifications (the arguments).

```{r}
#| eval: false
verb(object, argument = specification)
```

-   In plain English: *"Calculate the mean of age, removing missing values."*
-   In R: `mean(imd_raw$age, na.rm = TRUE)`

The parallel is exact:

| Grammar  | R code          | Example        |
|----------|-----------------|----------------|
| Verb     | Function name   | `mean`         |
| Object   | What you act on | `imd_raw$age`  |
| Modifier | Named argument  | `na.rm = TRUE` |

This model will not change. Every function you learn from here on fits this structure — the verbs will multiply, but the grammar stays the same.

::: callout-tip
### Spelling and capitalisation matter!

The language analogy also applies to spelling, R will not understand if you type `mena` instead of `mean`.

R is case-sensitive, it will not understand `MEAN` or `Mean`, only `mean`.
:::

### Your first verbs

Let us start with three simple functions that ask questions about your data set:

**Action** — Run these lines one by one and read what R tells you:

```{r}
#| eval: false
nrow(imd_raw)   
ncol(imd_raw)
names(imd_raw)
```

Each of these is a verb acting on the same object (`imd_raw`) but asking a different question:

-   `nrow()` — *"How many rows does this have?"*
-   `ncol()` — *"How many columns does this have?"*
-   `names()` — *"What are the column names?"*

Notice that none of these need additional arguments. The object alone is enough. Some verbs are simple — just an action and a target.

```{r}
#| echo: false
opts_grammar <- c(
  "The name of the object you want to create",
  answer = "The action R will perform — equivalent to a verb in a sentence",
  "The file where the result will be saved",
  "The argument that controls how the function behaves"
)
```

**In the Grammar Model, what does the function name represent?** `r longmcq(opts_grammar)`

By the way, did you realize how the previous functions created different outputs? `nrow()` and `ncol()` just produced one number - the answer to the question is just that; but `names()` produced something different, an answer with more than one reply. Because there is more than one column, the answer to that question has to be all existing names

In R this is called a **vector**

## Part 8 · Vectors and columns

Vectors are a sequence of values living together in a single object. R is a vectorised programming language, meaning that information is processed though these. In fact, your entire dataframe is built as a collection of columns representing variables, with each column constituting a vector itself.

### A dataframe is a collection of vectors

When you ran `names(imd_raw)`, R listed the column names of your dataframe. Each of those columns is a **vector** — a sequence of values of the same type.

Think of a dataframe as a table where: - Each **row** is one observation (one case) - Each **column** is one variable — and that column is a vector

This means your dataframe `imd_raw` is not one object — it is many vectors living together in a shared structure. To extract a single column from a dataframe, use the `$` operator like this:

```{r}
#| eval: false
imd_raw$age
```

This tells R: *"From the object `imd_raw`, give me the column called `age`."* R will print all the values in that column.

**Action** — Extract a few more columns and observe what R returns

::: callout-tip
### RStudio support

Notice when you write the `$` operator after the dataframe name, RStudio opens a little pop-up list containing the variable names. This can make it easier to navigate, and you can also start typing the name and the available names will narrow down to match your "search"
:::

As any other piece of information in R, you could very well start from loaded data and extract one variable into a new object for further use. Let's do it for the sake of teaching - and then you will understand why it wouldn't be necessary in the first place

**Action** — Save the age of your cases in a new object named `patients_age`

And, since we have the object in our Environment, let's show something else. Before, you used `nrow()` to ask how many observations/row the data had. Now we have a vector, and we want to know how many values it contains, for which we have a function called `length()`

**Action** — Compare the number of rows in `imd_raw` and the values contained in `patients_age`. Would you create an object for this action?

```{r}
#| eval: false
nrow(imd_raw)
length(patients_age)
```

::: callout-note
### Reflection question

When should you store information in new objects and when should you just call the function to print the result?

This is not a minor question. Creating objects is the way of granting information is not lost. However, is it always necessary to keep the result? Sometimes you may just want to quickly check something, but the information serves no other purpose. So always think about the print vs assign key feature of R
:::

Both functions should return the same number — because each column has exactly one value per row, thus making the number of rows identical to the number of items contained in the vector of the age column of the data

```{r}
#| echo: false
opts_vector <- c(
  "A column that contains only numeric values",
  "Any object stored in the R Environment",
  answer = "A sequence of values of the same type — equivalent to a single column in a dataframe",
  "A dataframe with only one row"
)
```

**What is a vector in R?** `r longmcq(opts_vector)`

## Part 9 · Numeric functions on vectors

Now that you know how to extract a column, you can apply functions to it. This is where R starts to become genuinely useful. During the presentation, we saw the functions `mean()` and `sum()` in action. Now it's your turn:

**Action** — What is the mean `age` of your current cases? Use your age object and the data column and compare the result

As you can see, there is no point in creating an intermediate object when you can directly access the data using the `$` operator. This is usually the quickest way of accessing information within dataframes, and dataframes will be our main working objects for data analysis

Let's try a few more numeric functions, to see their different outputs

**Action** — Run these functions on the `age` column:

```{r}
#| eval: false
mean(imd_raw$age)
sum(imd_raw$age)
min(imd_raw$age)
max(imd_raw$age)
range(imd_raw$age)
quantile(imd_raw$age)
table(imd_raw$age)
```

Read the output of each one carefully. Notice that `range()` returns two values and `quantile()` returns five — vectors can hold multiple values, and functions can return multiple values. Each of those functions is answering a very specific question. Think about their Grammar Model

## Exercise summary

**You are done with the Session 1 practicals.** You now have a working R Project, your packages loaded, your data imported, and your first functions under your belt. In Session 2 you will meet Kassandra, and you will learn about the true power of R: the Tidyverse.

This is what you practiced and learned:

|  |  |
|------------------------------------|------------------------------------|
| **Grammar Model** | Function = verb, object = what to act on, arguments = modifiers |
| **`nrow()` , `ncol()` , `names()`** | Ask basic questions about a dataframe's structure |
| **`$`** | Extracts a column from a dataframe as a vector |
| **`class()`** | Returns the type of an object or column |
| **`length()`** | Returns the number of elements in a vector |
| **`mean()` , `sum()` , `min()` , `max()`** | Numeric summaries of a vector |
| **`range()` , `quantile()`** | Return multiple values describing the distribution |
| **`table()`** | Counts occurrences of each value in a categorical vector |

```{=html}
<script>
document.addEventListener("DOMContentLoaded", function() {
  var radiogroups = document.getElementsByClassName("webex-radiogroup");
  for (var i = 0; i < radiogroups.length; i++) {
    radiogroups[i].onchange = radiogroups_func;
  }
});
</script>
```

© 2026 – Intro to R Course