Measure central tendency

We’ll illustrate measures of central tendency with the msleep dataset that comes from tidyverse. msleep contains some data about how much different kinds of mammals sleep. Here’s what the first few rows of msleep look like.

msleep |> head()
# A tibble: 6 × 11
  name    genus vore  order conservation sleep_total sleep_rem sleep_cycle awake
  <chr>   <chr> <chr> <chr> <chr>              <dbl>     <dbl>       <dbl> <dbl>
1 Cheetah Acin… carni Carn… lc                  12.1      NA        NA      11.9
2 Owl mo… Aotus omni  Prim… <NA>                17         1.8      NA       7  
3 Mounta… Aplo… herbi Rode… nt                  14.4       2.4      NA       9.6
4 Greate… Blar… omni  Sori… lc                  14.9       2.3       0.133   9.1
5 Cow     Bos   herbi Arti… domesticated         4         0.7       0.667  20  
6 Three-… Brad… herbi Pilo… <NA>                14.4       2.2       0.767   9.6
# ℹ 2 more variables: brainwt <dbl>, bodywt <dbl>

Mean

The mean is a variable’s average value.

It can be computed in two ways:

  • by summing all observations together using sum(), then dividing by the total number of observations n()
  • by using the mean() function

For example, to find the mean hours of sleep in msleep:

msleep |>
  summarise(
    mean_by_hand     = sum(sleep_total) / n(),
    mean_by_function = mean(sleep_total)
  )
# A tibble: 1 × 2
  mean_by_hand mean_by_function
         <dbl>            <dbl>
1         10.4             10.4

Same number!

Means by group

To find the mean hours of sleep for each genus in msleep, add group_by() for the variable you want to group by, then pipe that into summarise():

msleep |>
  group_by(genus) |>
  summarise(
    mean_sleep = mean(sleep_total)
  )
# A tibble: 77 × 2
   genus       mean_sleep
   <chr>            <dbl>
 1 Acinonyx          12.1
 2 Aotus             17  
 3 Aplodontia        14.4
 4 Blarina           14.9
 5 Bos                4  
 6 Bradypus          14.4
 7 Callorhinus        8.7
 8 Calomys            7  
 9 Canis             10.1
10 Capreolus          3  
# ℹ 67 more rows

I’m just seeing “NA”

mean() worked for sleep_total, but if we try it with sleep_rem (hours of REM sleep), we get “NA” instead of a number.

msleep |>
  summarise(
    mean_REM = mean(sleep_rem)
  )
# A tibble: 1 × 1
  mean_REM
     <dbl>
1       NA

This is because the data has not recorded the REM sleep for every animal. Where the hours of REM sleep are unknown, the data contains the value NA. NA stands for “not available”. And any NAs in this variable will make the mean() function return NA instead of an actual number.

To force mean() to overlook the NAs and return the mean of all the values we do have, use the code na.rm = TRUE (na.rm stands for “NA remove”).

msleep |>
  summarise(
    mean_REM = mean(sleep_rem, na.rm = TRUE)
  )
# A tibble: 1 × 1
  mean_REM
     <dbl>
1     1.88

Median

The median is the value for which 50% of observations a lower and 50% are higher. Think of it as the mid-point of the list of sorted values.

msleep |>
  summarise(
    median_sleep = median(sleep_total)
  )
# A tibble: 1 × 1
  median_sleep
         <dbl>
1         10.1

Medians by group

msleep |>
  group_by(genus) |>
  summarise(
    median_sleep = median(sleep_total)
  )
# A tibble: 77 × 2
   genus       median_sleep
   <chr>              <dbl>
 1 Acinonyx            12.1
 2 Aotus               17  
 3 Aplodontia          14.4
 4 Blarina             14.9
 5 Bos                  4  
 6 Bradypus            14.4
 7 Callorhinus          8.7
 8 Calomys              7  
 9 Canis               10.1
10 Capreolus            3  
# ℹ 67 more rows

I’m just seeing “NA”

na.rm works for median() too.

Attempting to find the median of a variable containing NAs:

msleep |>
  summarise(
    median_REM = median(sleep_rem)
  )
# A tibble: 1 × 1
  median_REM
       <dbl>
1         NA

With na.rm = TRUE:

msleep |>
  summarise(
    median_REM = median(sleep_rem, na.rm = TRUE)
  )
# A tibble: 1 × 1
  median_REM
       <dbl>
1        1.5

Mode

The mode of a variable is that variable’s most frequent value, or in other words, the value that occurs the most often.

There’s no mode() function in R. So we find the mode by generating a frequency table and looking at it to find which value has the greatest frequency.

msleep |>
  count(vore)
# A tibble: 5 × 2
  vore        n
  <chr>   <int>
1 carni      19
2 herbi      32
3 insecti     5
4 omni       20
5 <NA>        7

The mode of vore is “herbi”.

The arrange() function from tidyverse will sort whatever column you name in ascending order (i.e., smallest values first).

msleep |>
  count(vore) |>
  arrange(n)
# A tibble: 5 × 2
  vore        n
  <chr>   <int>
1 insecti     5
2 <NA>        7
3 carni      19
4 omni       20
5 herbi      32

To sort in descending order, use arrange(desc()).

msleep |>
  count(vore) |>
  arrange(desc(n))
# A tibble: 5 × 2
  vore        n
  <chr>   <int>
1 herbi      32
2 omni       20
3 carni      19
4 <NA>        7
5 insecti     5

The value in the first row of this table is the mode.

Which measures for which variable types

Mode Median Mean
Nominal (unordered categorical) ✔ ✘ ✘
Ordinal (ordered categorical) ✔ ✔ ?
(you may see it for certain types of ordinal data; people disagree)
Numeric Continuous ✔ ✔ ✔