Download RMarkdown file

First, we load some necessary libraries

library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(tidyr)

Loading data from google drive.

# here we run bash
gdown -q 1GxG6hXZwQ1NC7OcPdArKNeDLZDFHx1DN
df = read.csv('Ferguson2017.csv')
df

where the columns with dates are of type “character”:

df |> select(contains('Date'))

so we will modify them to the type “Date”

df |> mutate(across(contains('Date'), ~as.Date(., format='%Y-%m-%d'))) -> df
df

Now, we want to calculate the number of deaths and survivors by country

df |> 
  # we group by country and final status (dead/alive/NA)
  group_by(Country, FinalStatus) |> 
  # and then count how many records we have per each grouping
  # I also write .groups = 'drop' in order to avoid warning message in R
  summarize(count = n(), .groups = 'drop') |> 
  # we transform long format to wide 
  # *please check what it means by commenting/uncommenting*
  pivot_wider(names_from = FinalStatus, values_from = count) |>
  # again grouping by country to calculate correctly Totals
  group_by(Country) |>
  # summing Alive/Dead/NAs which are of type "numeric"
  mutate(Total = sum(c_across(where(is.numeric))), 
         `CFR, %` = Dead / Total * 100)
  # note if I want to declare a new variable with non-traditional characters,
  # I need to use `...`
  # alternatively:
  #      CFR = Dead / Total * 100)

We could also write the last pipe in more obvious way:

df |> 
  group_by(Country, FinalStatus) |> 
  summarise(Count = n(), .groups = 'drop') |> 
  #drop_na() |>
  pivot_wider(names_from = FinalStatus, values_from = Count) |>
  mutate(`CFR, %` = round(Dead / (Alive + Dead) * 100, 2))

Calculating CFR for people who were hospitalized

df |> 
  # here we choose only people with *known* hospitalization status
  filter(HospitalizedEver=='Yes') |>
  group_by(Country, FinalStatus) |> 
  summarise(Count = n(), .groups = 'drop') |> #drop_na() |>
  pivot_wider(names_from = FinalStatus, values_from = Count) |>
  mutate(Total = sum(c_across(where(is.numeric))),
      CFR = Dead / Total,
     `CFR, %` = round(Dead / Total * 100, 2))

In more general way:

df |> 
  group_by(Country, FinalStatus, HospitalizedEver) |> 
  summarise(Count = n(), .groups = 'drop') |>
  pivot_wider(names_from = FinalStatus, values_from = Count) |>
  group_by(Country, HospitalizedEver) |>
  mutate(Total = sum(c_across(everything()), na.rm=TRUE),
      CFR = Dead / Total,
     `CFR, %` = round(Dead / Total * 100, 2)) -> df_CFR_hosp
df_CFR_hosp

Again, if we want we can pivot the obtained data frame to the wide format for CFR. However, we would also need to the id_cols:

df_CFR_hosp |> 
    pivot_wider(id_cols = Country, values_from = `CFR, %`, names_from = HospitalizedEver)

Otherwise, R would throw the error

df_CFR_hosp |> 
    pivot_wider(values_from = `CFR, %`, names_from = HospitalizedEver)
## Error in `pivot_wider()`:
## ! Names must be unique.
## ✖ These names are duplicated:
##   * "NA" at locations 4 and 9.
## ℹ Use argument `names_repair` to specify repair strategy.

Now, let’s try to work characterizing the CFR by age group. First, we would need to create those age groups. We do it by using the special command cut from dplyr package.

df |> 
  mutate(Age_group = cut(Age,
                         # break points
                         breaks=c(seq(0, 80, 5), 120),
                         # labels, otherwise it would be labeled [0,5), [5, 10), ...
                         labels=seq(0, 80, 5), 
                         # to include the left bound [5,10) 
                         # instead of the right bound (5, 10]
                         right = F)) |>
  # just rearanging the columns, so you would easily see Age and Age_groups
  select(Country, Age, Age_group, everything()) -> df_age_groups
df_age_groups

Here you see that we create breaks with the upper bound 120 (if someone is older than 120 years, which is impossible, they would be assigned to NA

c(seq(0, 80, 5), 120)
##  [1]   0   5  10  15  20  25  30  35  40  45  50  55  60  65  70  75  80 120

While labels are

seq(0, 80, 5)
##  [1]  0  5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80

Finally we check our labels

df_age_groups$Age_group |> unique()
##  [1] 45   40   0    30   10   70   5    25   <NA> 50   55   35   20   15   80  
## [16] 75   60   65  
## Levels: 0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80

Now we calculate similarly (your homework)

df_age_groups |> 
    pivot_wider(...) # please continue