10 Descriptive Analysis in R

🎯 Learning goals

After working through Tutorial 10, you’ll be able to…

  • understand basic descriptive statistics (e.g., mean, standard deviation)
  • apply functions for descriptive analysis

Descriptive statistics

Let’s start with simple descriptive statistics on our data. Descriptive statistics include measures of frequency, central tendency, and spread — we’ll look at each in turn. For descriptive statistics, we will mainly use three functions from the tidycomm package:

  • tab_frequencies(): absolute values, frequencies (for variables scaled on at least a nominal level)
  • describe_cat(): mode (for variables scaled on at least an ordinal level)
  • describe(): mean, median, standard deviation (for variables scaled on a metric level)

We will once again use the WoJ dataset. It contains a quantitative survey of N = 1,200 journalists from five countries, collected via the World of Journalism study. The data is provided via the tidycomm package developed by Unkel et al.

First, we retrieve the data and save it as an object named data_woj. Next, we use the as_tibble() command which essentially prints our data in a nicer format. The data does not change, we just get additional information (such as the type of data it contains).

Make sure to have the tidycomm and the tidyverse package installed before running this command!

# we load the necessary packages
library(tidycomm)
library(tidyverse)

# loads the WoJ dataset shipped with tidycomm
data_woj <- tidycomm::WoJ

# we inspect the data
data_woj |>
  as_tibble()
# A tibble: 1,200 × 15
   country   reach employment temp_contract autonomy_selection autonomy_emphasis
   <fct>     <fct> <chr>      <fct>                      <dbl>             <dbl>
 1 Germany   Nati… Full-time  Permanent                      5                 4
 2 Germany   Nati… Full-time  Permanent                      3                 4
 3 Switzerl… Regi… Full-time  Permanent                      4                 4
 4 Switzerl… Local Part-time  Permanent                      4                 5
 5 Austria   Nati… Part-time  Permanent                      4                 4
 6 Switzerl… Local Freelancer <NA>                           4                 4
 7 Germany   Local Full-time  Permanent                      4                 4
 8 Denmark   Nati… Full-time  Permanent                      3                 3
 9 Switzerl… Local Full-time  Permanent                      5                 5
10 Denmark   Nati… Full-time  Permanent                      2                 4
# ℹ 1,190 more rows
# ℹ 9 more variables: ethics_1 <dbl>, ethics_2 <dbl>, ethics_3 <dbl>,
#   ethics_4 <dbl>, work_experience <dbl>, trust_parliament <dbl>,
#   trust_government <dbl>, trust_parties <dbl>, trust_politicians <dbl>

Frequency measures

Frequency measures tell us how often values occur in our data. They do not describe the center of a distribution, but give us a sense of how values are distributed across categories.

Absolute values/counts

For many variables - especially those with nominal or ordinal scale levels - you may want to count values. For instance, you may want to know how many participants are included in our data using the tab_frequencies() function. In the output below, the column n shows that N = 1,200 participants were part of the study.

data_woj |>
  tab_frequencies()
# A tibble: 1 × 4
      n percent cum_n cum_percent
* <int>   <dbl> <int>       <dbl>
1  1200       1  1200           1

Or you may want to know how many participants from each country took part in this study - i.e., descriptive statistics for a specific variable rather than the whole data set. In the output below, the column n shows that N = 207 journalists from Austria participated in this study.

data_woj |>
  tab_frequencies(country)
# A tibble: 5 × 5
  country         n percent cum_n cum_percent
* <fct>       <int>   <dbl> <int>       <dbl>
1 Austria       207   0.172   207       0.172
2 Denmark       376   0.313   583       0.486
3 Germany       173   0.144   756       0.63 
4 Switzerland   233   0.194   989       0.824
5 UK            211   0.176  1200       1    

Percentages

Sometimes, it may be more helpful to not know how often a specific value occurs in absolute, but in relative terms, for example in percentages. To calculate this, we can use the same command before, but focus on the column percent - for example, to understand how often participants from different countries participated in our survey. We can, for example, see that 17.2% of participants were from Austria.

data_woj |>
  tab_frequencies(country)
# A tibble: 5 × 5
  country         n percent cum_n cum_percent
* <fct>       <int>   <dbl> <int>       <dbl>
1 Austria       207   0.172   207       0.172
2 Denmark       376   0.313   583       0.486
3 Germany       173   0.144   756       0.63 
4 Switzerland   233   0.194   989       0.824
5 UK            211   0.176  1200       1    

Central tendencies

Measures of central tendency describe the “typical” or most representative value in a distribution. The three most common measures are the mode, the median, and the mean.

Mode

The mode is the value that appears most frequently in your data. It is the only measure of central tendency that can be used with nominal-level variables. To identify the mode, for example for the variable country, we can use the describe_cat() function and focus on the column Mode. In the output below, the column Mode shows that the most participants in the survey were from Denmark. According to the column Mode_N, N = 376 participants from Denmark participated.

data_woj |>
  describe_cat(country)
# A tibble: 1 × 6
  Variable     N Missing Unique Mode    Mode_N
* <chr>    <int>   <int>  <dbl> <chr>    <int>
1 country   1200       0      5 Denmark    376

Median

The median is the value that divides a distribution exactly in half: 50% of values fall below it and 50% above. It is particularly useful because, unlike the mean, it is robust against extreme values (outliers).

To calculate the median, we use the describe() function and focus on the column Mdn. In the output below, we apply it to the variable trust_government, which measures how much trust journalists place in the government on a scale from 1 (no trust at all) to 5 (complete trust).

data_woj |>
  describe(trust_government)
# A tibble: 1 × 15
  Variable             N Missing     M    SD   Min   Q25   Mdn   Q75   Max Range
* <chr>            <int>   <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 trust_government  1200       0  2.82 0.854     1     2     3     3     5     4
# ℹ 4 more variables: CI_95_LL <dbl>, CI_95_UL <dbl>, Skewness <dbl>,
#   Kurtosis <dbl>

We can see in the column Mdn that the median value for trust in government is 3. This means that at least half of the journalists in our survey rated their trust in the government at 3 or below on the scale.

Mean

The mean (or arithmetic mean) is the most commonly used measure of central tendency for metric variables. It is calculated by summing all values and dividing by the number of observations. We again use the describe() function, this time focusing on the column M.

data_woj |>
  describe(trust_government)
# A tibble: 1 × 15
  Variable             N Missing     M    SD   Min   Q25   Mdn   Q75   Max Range
* <chr>            <int>   <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 trust_government  1200       0  2.82 0.854     1     2     3     3     5     4
# ℹ 4 more variables: CI_95_LL <dbl>, CI_95_UL <dbl>, Skewness <dbl>,
#   Kurtosis <dbl>

The column M tells us that journalists’ average trust in government is 2.82 — slightly below the midpoint of the scale. Keep in mind that the mean is sensitive to outliers — a few very high or very low values can pull it noticeably in one direction. This is why comparing the mean and the median is often a useful first step in understanding a variable’s distribution — something we will discuss next.

Measures of dispersion

While measures of central tendency tell us about the typical value in a distribution, measures of dispersion tell us how much values vary around that center. Two of the most common measures of dispersion are the variance and the standard deviation.

Variance

The variance describes how much the individual values in a distribution spread around the mean. A high variance indicates that values are spread widely; a low variance indicates that they cluster closely around the mean. While variance is an important theoretical concept, it is expressed in squared units of the original variable, which makes it harder to interpret directly.

The tidycomm package does not directly depict the variance - we have to create it using the standard deviation (see next section):

data_woj |>
  describe(trust_government) |>
  mutate(variance = SD^2) |>
  select(variance)
# A tibble: 1 × 1
  variance
     <dbl>
1    0.730

This gives us the variance of journalists’ trust in government scores. Because the unit is squared, we typically move on to the standard deviation (see below) for a more interpretable measure of spread.

Standard deviation

The standard deviation is simply the square root of the variance. This brings the measure of spread back into the same unit as the original variable, making it much easier to interpret. We use the describe() function and focus on the column SD.

data_woj |>
  describe(trust_government)
# A tibble: 1 × 15
  Variable             N Missing     M    SD   Min   Q25   Mdn   Q75   Max Range
* <chr>            <int>   <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 trust_government  1200       0  2.82 0.854     1     2     3     3     5     4
# ℹ 4 more variables: CI_95_LL <dbl>, CI_95_UL <dbl>, Skewness <dbl>,
#   Kurtosis <dbl>

For the variable trust_government, the standard deviation is 0.854, meaning that on average, journalists’ responses deviated from the mean by about 0.85 points on the 5-point scale.

The column SD tells us the average deviation of journalists’ trust in government scores from the mean. Together, the mean and standard deviation give a compact summary of both the typical value in the distribution and how much individual responses vary around it.

Descriptive statistics across groups

In some cases, you may also wish to get descriptive data for groups within our data. For instance, we may want to know how trust in government varies across different countries in our sample.

Using the dplyr package, we use the following code to get this information:

  • We define the object to which functions should be applied: data_woj
  • We group our data alongside the variable country
  • We calculate descriptive statistics for trust_government across values of country
data_woj %>%
  group_by(country) %>%
  describe(trust_government)
# A tibble: 5 × 16
# Groups:   country [5]
  country Variable     N Missing     M    SD   Min   Q25   Mdn   Q75   Max Range
* <fct>   <chr>    <int>   <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Austria trust_g…   207       0  2.72 0.743     1     2     3     3     4     3
2 Denmark trust_g…   376       0  2.55 0.788     1     2     3     3     4     3
3 Germany trust_g…   173       0  3.09 0.884     1     3     3     4     5     4
4 Switze… trust_g…   233       0  3.35 0.734     1     3     3     4     5     4
5 UK      trust_g…   211       0  2.59 0.843     1     2     3     3     5     4
# ℹ 4 more variables: CI_95_LL <dbl>, CI_95_UL <dbl>, Skewness <dbl>,
#   Kurtosis <dbl>

Results allow us to compare how journalists in different countries rate their trust in government. For example, we can see that journalists’ trust in their government is highest in Switzerland (M = 3.35, SD = 0.73) and lowest in Denmark (M = 2.55, SD = 0.79)

Keep in mind that these are descriptive differences — we will need multivariate statistics to determine whether any observed differences are statistically meaningful.

🤓 Smart Hacks

The report package, part of the easystats ecosystem, can automatically generate descriptive statistics — and even write them up as readable text — with just one function call. The knitr package enables us to nicely print the output.

The report() function reads your data and produces a formatted, human-readable description of the key statistics — including the mean, standard deviation, median, and the percentage of missing values. This is especially handy for quickly writing up a results section. Here, we convert the report into a readable and nicely formatted table using as.data.frame() and kable():

library(report)
library(knitr)

data_woj |>
  select(trust_government) |>
  report() |>
  as.data.frame() |>
  kable(caption = "Automated descriptive statistics via the report package",
        digits = 2)
Automated descriptive statistics via the report package
Variable n_Obs Mean SD Median MAD Min Max Skewness Kurtosis percentage_Missing
trust_government 1200 2.82 0.85 3 1.48 1 5 -0.23 -0.29 0

Important: The report package produces more columns than you may need (e.g., skewness, kurtosis, CI bounds). You can always add a select() step before kable() to keep only the most relevant ones.

💡 Take-Aways

🎲 Quiz

🎲 Question 1

Which of the following statements about measures of central tendency are correct?

🎲 Question 2

Which of the following statements about the tidycomm functions are correct?

📚 More tutorials on this

You still have questions? The following tutorials & papers can help you with that: