## 2.4 Working with vectors

Manipulating, summarising and sorting data using R is an important skill to master but one which many people find a little confusing at first. We’ll go through a few simple examples here using vectors to illustrate some important concepts but will build on this in much more detail in Chapter 3 where we will look at more complicated (and useful) data structures.

Take a look at this video for a quick introduction to working with vectors in R using positional and logical indexes

### 2.4.1 Extracting elements

To extract (also known as indexing or subscripting) one or more values (more generally known as elements) from a vector we use the square bracket `[ ]`

notation. The general approach is to name the object you wish to extract from, then a set of square brackets with an index of the element you wish to extract contained within the square brackets. This index can be a position or the result of a logical test.

#### Positional index

To extract elements based on their position we simply write the position inside the `[ ]`

. For example, to extract the 3rd value of `my_vec`

```
# remind ourselves what my_vec looks like
my_vec ## [1] 2 3 1 6 4 3 3 7
3] # extract the 3rd value
my_vec[## [1] 1
# if you want to store this value in another object
<- my_vec[3]
val_3
val_3## [1] 1
```

Note that the positional index starts at 1 rather than 0 like some other other programming languages (i.e. Python).

We can also extract more than one value by using the `c()`

function inside the square brackets. Here we extract the 1^{st}, 5^{th}, 6^{th} and 8^{th} element from the `my_vec`

object

```
c(1, 5, 6, 8)]
my_vec[## [1] 2 4 3 7
```

Or we can extract a range of values using the `:`

notation. To extract the values from the 3^{rd} to the 8^{th} elements

```
3:8]
my_vec[## [1] 1 6 4 3 3 7
```

#### Logical index

Another really useful way to extract data from a vector is to use a logical expression as an index. For example, to extract all elements with a value greater than 4 in the vector `my_vec`

```
> 4]
my_vec[my_vec ## [1] 6 7
```

Here, the logical expression is `my_vec > 4`

and R will only extract those elements that satisfy this logical condition. So how does this actually work? If we look at the output of just the logical expression without the square brackets you can see that R returns a vector containing either `TRUE`

or `FALSE`

which correspond to whether the logical condition is satisfied for each element. In this case only the 4^{th} and 8^{th} elements return a `TRUE`

as their value is greater than 4.

```
> 4
my_vec ## [1] FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE
```

So what R is actually doing under the hood is equivalent to

```
c(FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE)]
my_vec[## [1] 6 7
```

and only those element that are `TRUE`

will be extracted.

In addition to the `<`

and `>`

operators you can also use composite operators to increase the complexity of your expressions. For example the expression for ‘greater or equal to’ is `>=`

. To test whether a value is equal to a value we need to use a double equals symbol `==`

and for ‘not equal to’ we use `!=`

(the `!`

symbol means ‘not’).

```
>= 4] # values greater or equal to 4
my_vec[my_vec ## [1] 6 4 7
< 4] # values less than 4
my_vec[my_vec ## [1] 2 3 1 3 3
<= 4] # values less than or equal to 4
my_vec[my_vec ## [1] 2 3 1 4 3 3
== 4] # values equal to 4
my_vec[my_vec ## [1] 4
!= 4] # values not equal to 4
my_vec[my_vec ## [1] 2 3 1 6 3 3 7
```

We can also combine multiple logical expressions using Boolean expressions. In R the `&`

symbol means AND and the `|`

symbol means OR. For example, to extract values in `my_vec`

which are less than 6 AND greater than 2

```
<- my_vec[my_vec < 6 & my_vec > 2]
val26
val26## [1] 3 4 3 3
```

or extract values in `my_vec`

that are greater than 6 OR less than 3

```
<- my_vec[my_vec > 6 | my_vec < 3]
val63
val63## [1] 2 1 7
```

### 2.4.2 Replacing elements

We can change the values of some elements in a vector using our `[ ]`

notation in combination with the assignment operator `<-`

. For example, to replace the 4^{th} value of our `my_vec`

object from `6`

to `500`

```
4] <- 500
my_vec[
my_vec## [1] 2 3 1 500 4 3 3 7
```

We can also replace more than one value or even replace values based on a logical expression

```
# replace the 6th and 7th element with 100
c(6, 7)] <- 100
my_vec[
my_vec## [1] 2 3 1 500 4 100 100 7
# replace element that are less than or equal to 4 with 1000
<= 4] <- 1000
my_vec[my_vec
my_vec## [1] 1000 1000 1000 500 1000 100 100 7
```

### 2.4.3 Ordering elements

In addition to extracting particular elements from a vector we can also order the values contained in a vector. To sort the values from lowest to highest value we can use the `sort()`

function

```
<- sort(my_vec)
vec_sort
vec_sort## [1] 7 100 100 500 1000 1000 1000 1000
```

To reverse the sort, from highest to lowest, we can either include the `decreasing = TRUE`

argument when using the `sort()`

function

```
<- sort(my_vec, decreasing = TRUE)
vec_sort2
vec_sort2## [1] 1000 1000 1000 1000 500 100 100 7
```

or first sort the vector using the `sort()`

function and then reverse the sorted vector using the `rev()`

function. This is another example of nesting one function inside another function.

```
<- rev(sort(my_vec))
vec_sort3
vec_sort3## [1] 1000 1000 1000 1000 500 100 100 7
```

Whilst sorting a single vector is fun, perhaps a more useful task would be to sort one vector according to the values of another vector. To do this we should use the `order()`

function in combination with `[ ]`

. To demonstrate this let’s create a vector called `height`

containing the height of 5 different people and another vector called `p.names`

containing the names of these people (so Joanna is 180 cm, Charlotte is 155 cm etc)

```
<- c(180, 155, 160, 167, 181)
height
height## [1] 180 155 160 167 181
<- c("Joanna", "Charlotte", "Helen", "Karen", "Amy")
p.names
p.names## [1] "Joanna" "Charlotte" "Helen" "Karen" "Amy"
```

Our goal is to order the people in `p.names`

in ascending order of their `height`

. The first thing we’ll do is use the `order()`

function with the `height`

variable to create a vector called `height_ord`

```
<- order(height)
height_ord
height_ord## [1] 2 3 4 1 5
```

OK, what’s going on here? The first value, `2`

, (remember ignore `[1]`

) should be read as ‘the smallest value of `height`

is the second element of the `height`

vector’. If we check this by looking at the `height`

vector above, you can see that element 2 has a value of 155, which is the smallest value. The second smallest value in `height`

is the 3^{rd} element of `height`

, which when we check is 160 and so on. The largest value of `height`

is element `5`

which is 181. Now that we have a vector of the positional indices of heights in ascending order (`height_ord`

), we can extract these values from our `p.names`

vector in this order

```
<- p.names[height_ord]
names_ord
names_ord## [1] "Charlotte" "Helen" "Karen" "Joanna" "Amy"
```

You’re probably thinking ‘what’s the use of this?’ Well, imagine you have a dataset which contains two columns of data and you want to sort each column. If you just use `sort()`

to sort each column separately, the values of each column will become uncoupled from each other. By using the ‘order()’ on one column, a vector of positional indices is created of the values of the column in ascending order This vector can be used on the second column, as the index of elements which will return a vector of values based on the first column.

### 2.4.4 Vectorisation

One of the great things about R functions is that most of them are vectorised. This means that the function will operate on all elements of a vector without needing to apply the function on each element separately. For example, to multiple each element of a vector by 5 we can simply use

```
# create a vector
<- c(3, 5, 7, 1, 9, 20)
my_vec2
# multiply each element by 5
* 5
my_vec2 ## [1] 15 25 35 5 45 100
```

Or we can add the elements of two or more vectors

```
# create a second vector
<- c(17, 15, 13, 19, 11, 0)
my_vec3
# add both vectors
+ my_vec3
my_vec2 ## [1] 20 20 20 20 20 20
# multiply both vectors
* my_vec3
my_vec2 ## [1] 51 75 91 19 99 0
```

However, you must be careful when using vectorisation with vectors of different lengths as R will quietly recycle the elements in the shorter vector rather than throw a wobbly (error).

```
# create a third vector
<- c(1, 2)
my_vec4
# add both vectors - quiet recycling!
+ my_vec4
my_vec2 ## [1] 4 7 8 3 10 22
```

### 2.4.5 Missing data

In R, missing data is usually represented by an `NA`

symbol meaning ‘Not Available’. Data may be missing for a whole bunch of reasons, maybe your machine broke down, maybe you broke down, maybe the weather was too bad to collect data on a particular day etc etc. Missing data can be a pain in the proverbial both from an R perspective and also a statistical perspective. From an R perspective missing data can be problematic as different functions deal with missing data in different ways. For example, let’s say we collected air temperature readings over 10 days, but our thermometer broke on day 2 and again on day 9 so we have no data for those days

```
<- c(7.2, NA, 7.1, 6.9, 6.5, 5.8, 5.8, 5.5, NA, 5.5)
temp
temp## [1] 7.2 NA 7.1 6.9 6.5 5.8 5.8 5.5 NA 5.5
```

We now want to calculate the mean temperature over these days using the `mean()`

function

```
<- mean(temp)
mean_temp
mean_temp## [1] NA
```

Flippin heck, what’s happened here? Why does the `mean()`

function return an `NA`

? Actually, R is doing something very sensible (at least in our opinion!). If a vector has a missing value then the only possible value to return when calculating a mean is `NA`

. R doesn’t know that you perhaps want to ignore the `NA`

values (R can’t read your mind - yet!). Happily, if we look at the help file (use `help("mean")`

- see the next section for more details) associated with the `mean()`

function we can see there is an argument `na.rm =`

which is set to `FALSE`

by default.

na.rm - a logical value indicating whether NA values should be stripped before the computation proceeds.

If we change this argument to `na.rm = TRUE`

when we use the `mean()`

function this will allow us to ignore the `NA`

values when calculating the mean

```
<- mean(temp, na.rm = TRUE)
mean_temp
mean_temp## [1] 6.2875
```

It’s important to note that the `NA`

values have not been removed from our `temp`

object (that would be bad practice), rather the `mean()`

function has just ignored them. The point of the above is to highlight how we can change the default behaviour of a function using an appropriate argument. The problem is that not all functions will have an `na.rm =`

argument, they might deal with `NA`

values differently. However, the good news is that every help file associated with any function will **always** tell you how missing data are handled by default.