---
title: "Running plausibility checks"
author: Tomás Zaba
bibliography: references.bib
csl: harvard-cite-them-right-11th-edition.csl
knitr:
  opts_chunk: 
    collapse: true
    comment: "#>"
vignette: >
  %\VignetteIndexEntry{Running plausibility checks}
  %\VignetteEngine{quarto::html}
  %\VignetteEncoding{UTF-8}
---

```{r}
#| label: setup
#| collapse: true
#| echo: false
#| message: false

library(mwana)
library(dplyr)
```

# Introduction

Plausibility check is a tool that evaluates the overall quality and acceptability of anthropometric data to ensure its suitability for informing decision-making process.  

`mwana` provides a set of handy functions to facilitate this evaluation. These functions allow users to assess the acceptability of weight-for-height z-score (WFHZ) and mid upper-arm circumference (MUAC) data. The evaluation of the latter can be done on the basis of MUAC-for-age z-score (MFAZ) or raw MUAC values.  

In this vignette, we will learn how to use these functions and when to consider using MFAZ plausibility check over the one based on raw MUAC values. For demonstration, we will use a `mwana` built-in sample dataset named `anthro.01`. This dataset contains district level SMART surveys from anonymised locations. Do `?anthro.01` in `R` console to read more about it.

We will begin the demonstration with the plausibility check that you are most familiar with and then proceed to the ones you are less familiar with. 

## Plausibility check of WFHZ data

We check the plausibility of WFHZ data by calling the `mw_plausibility_check_wfhz()` function. Before doing that, we need ensure the data is in the right "shape and format" that is accepted and understood by the function. Don't worry, you will soon learn how to get there. But first, let's take a moment to walk you through some key features about this function. 

`mw_plausibility_check_wfhz()` is a replica of the plausibility check in ENA for SMART software of the SMART Methodology [@smart2017]. Under the hood, it runs the same test suite you already know from SMART. It also applies the same rating and scoring criteria. Beware though that there are some small differences to have in mind: 

  (i) `mw_plausibility_check_wfhz()` does not include MUAC in its test suite. This is simply due the fact that now you can run a more comprehensive test suite for MUAC.
  
  (ii) `mw_plausibility_check_wfhz()` allows user to run checks on a multiple-area dataset at once, without having to repeat the same workflow over and over again for the number of areas the data holds. 

That is it! Now we can begin delving into the "how to". 

It is always a good practice to start off by inspecting our dataset. Let's check the first 6 rows of our dataset:


```{r}
#| label: data
#| echo: true

head(anthro.01)
```

We can see that the dataset has eleven variables, and the way how their respective values are presented. This is useful to inform the data wrangling workflow. 

### Data wrangling

As mentioned somewhere above, before we supply a data object to `mw_plausibility_check_wfhz()`, we need to wrangle it first. This task is executed by `mw_wrangle_age()` and `mw_wrangle_wfhz()`. Read more about the technical documentation by doing  `help("mw_wrangle_age")` or `help("mw_wrangle_wfhz")` in `R` console. 

#### Wrangling age {#sec-age}

We use `mw_wrangle_age()` to calculate child's age in months based on the date of data collection and child's date of birth. The function takes `df`, the `anthro.01` object which contains variables related to age that will be used for the wrangling process; `dos`, the unquoted variable name in `df` that contains the date when the data collection was performed (`dos` in `anthro.01`); `dob`, the unquoted variable name in `df` that contains the date when the child was born (`dob` in `anthro.01`); `age`, the unquoted variable name in `df` that contains the age of the child in months (`age` in `anthro.01`); and `.decimals`, which allows the user to specify the number of decimal places to which the output age values will be rounded off to (by default, `.decimals` is set to 2, so even without specifying this argument, the resulting output will be rounded off to 2). This is done as follows:


```{r}
#| label: wrangle_age
#| echo: true
#| eval: false

age_mo <- mw_wrangle_age(
  df = anthro.01,
  dos = dos,
  dob = dob,
  age = age,
  .decimals = 2
)
```

This will return: 


```{r}
#| label: view_age
#| echo: false
#| eval: true

age_mo <- anthro.01 |>
  mw_wrangle_age(
    dos = dos,
    dob = dob,
    age = age,
    .decimals = 2
  )
head(age_mo)
```

#### Wrangling all other remaining variables 

For this, we call `mw_wrangle_wfhz()` as follows: 


```{r}
#| label: wrangle_wfhz_data
#| echo: true
#| eval: false

wrangled_df <- anthro.01 |>
  mw_wrangle_wfhz(
    sex = sex,
    weight = weight,
    height = height,
    .recode_sex = TRUE
  )
```

In this example, the argument `.recode_sex` was set to `TRUE`. That is because under the hood, to compute the z-scores, a task made possible thanks to the {`zscorer`} package [@zscorer], it uses sex coded into 1 and 2 for male and female,  respectively. This means that if our sex variable is already in 1 and 2's, we would set it to `FALSE`. 

:::{.callout-note}
If by any chance your sex variable is coded in any other different way than aforementioned, then you will have to recode it outside `mwana` utilities and then set `.recode_sex` accordingly.
:::

Under the hood, after recoding (or not) the sex variables, `mw_wrangle_wfhz()` computes the z-scores, then identifies outliers and adds them to the dataset. Two new variables (`wfhz` and `flag_wfhz`) are created and added to the dataset. We can see this below: 


```{r}
#| label: view_df
#| echo: false
#| eval: true

wrangled_df <- anthro.01 |>
  mw_wrangle_wfhz(
    sex = sex,
    weight = weight,
    height = height,
    .recode_sex = TRUE
  )

x <- wrangled_df |>
  dplyr::select(area, wfhz, flag_wfhz)

head(x)
```

### On to *de facto* plausibility check of WFHZ data

We can check the plausibility of our data by calling `mw_plausibility_check_wfhz()` function as demonstrated below: 


```{r}
#| label: pl_wfhz
#| echo: true
#| eval: false

x <- wrangled_df |>
  mw_plausibility_check_wfhz(
    sex = sex,
    age = age,
    weight = weight,
    height = height,
    flags = flag_wfhz
  )
```

Or we can chain all previous functions in this way:


```{r}
#| label: pipe_workflow
#| echo: true
#| eval: false

x <- anthro.01 |>
  mw_wrangle_age(
    dos = dos,
    dob = dob,
    age = age,
    .decimals = 2
  ) |>
  mw_wrangle_wfhz(
    sex = sex,
    weight = weight,
    height = height,
    .recode_sex = TRUE
  ) |>
  mw_plausibility_check_wfhz(
    sex = sex,
    age = age,
    weight = weight,
    height = height,
    flags = flag_wfhz
  )
```

The returned output is: 

```{r}
#| label: view_pl_wfhz
#| echo: false
#| eval: true

anthro.01 |>
  mw_wrangle_age(
    dos = dos,
    dob = dob,
    age = age,
    .decimals = 2
  ) |>
  mw_wrangle_wfhz(
    sex = sex,
    weight = weight,
    height = height,
    .recode_sex = TRUE
  ) |>
  mw_plausibility_check_wfhz(
    sex = sex,
    age = age,
    weight = weight,
    height = height,
    flags = flag_wfhz
  )
```

As we can see, the returned output is a summary table of statistics and ratings. 
We can neat it for more clarity and readability. We can achieve this by chaining `mw_neat_output_wfhz()` to the previous pipeline: 


```{r}
#| label: neat_table
#| echo: true
#| eval: false

anthro.01 |>
  mw_wrangle_age(
    dos = dos,
    dob = dob,
    age = age,
    .decimals = 2
  ) |>
  mw_wrangle_wfhz(
    sex = sex,
    weight = weight,
    height = height,
    .recode_sex = TRUE
  ) |>
  mw_plausibility_check_wfhz(
    sex = sex,
    age = age,
    weight = weight,
    height = height,
    flags = flag_wfhz
  ) |>
  mw_neat_output_wfhz()
```

This will give us: 

```{r}
#| label: view_neat_table
#| echo: false
#| eval: true

anthro.01 |>
  mw_wrangle_age(
    dos = dos,
    dob = dob,
    age = age,
    .decimals = 2
  ) |>
  mw_wrangle_wfhz(
    sex = sex,
    weight = weight,
    height = height,
    .recode_sex = TRUE
  ) |>
  mw_plausibility_check_wfhz(
    sex = sex,
    age = age,
    weight = weight,
    height = height,
    flags = flag_wfhz
  ) |>
  mw_neat_output_wfhz()
```

An already formatted table, with scientific notations converted to standard notations, etc.

When working on a multiple-area dataset, for instance districts, we can check the plausibility of all districts in the dataset at once by specifying a vector (or a list of vectors) to the function as follows. Here we pass both `area` and `team`, a list of vectors specifying the categories for which the analysis should be summarised (more than one vector can be specified, separated by `,`); in this case, the analysis will be summarised at each survey team in `District E` and `District G`:


```{r}
#| label: pl_group_by
#| echo: true
#| eval: false

anthro.01 |>
  mw_wrangle_age(
    dos = dos,
    dob = dob,
    age = age,
    .decimals = 2
  ) |>
  mw_wrangle_wfhz(
    sex = sex,
    weight = weight,
    height = height,
    .recode_sex = TRUE
  ) |>
  mw_plausibility_check_wfhz(
    sex = sex,
    age = age,
    weight = weight,
    height = height,
    flags = flag_wfhz,
    area,
    team
  ) |>
  mw_neat_output_wfhz()
```

This will return the following: 


```{r}
#| label: pl_group_by-view
#| echo: false
#| eval: true

anthro.01 |>
  mw_wrangle_age(
    dos = dos,
    dob = dob,
    age = age,
    .decimals = 2
  ) |>
  mw_wrangle_wfhz(
    sex = sex,
    weight = weight,
    height = height,
    .recode_sex = TRUE
  ) |>
  mw_plausibility_check_wfhz(
    sex = sex,
    age = age,
    weight = weight,
    height = height,
    flags = flag_wfhz,
    area,
    team
  ) |>
  mw_neat_output_wfhz()
```

At this point, you have reached the end of your workflow 🎉 .

## Plausibility check of MFAZ data

We will assess the plausibility of MUAC data through MFAZ if we have age variable available in our dataset.

:::{.callout-note}
The plausibility check for MFAZ data was built based on the insights gotten from @bilukha research presented at the 2023 High-Level Technical Assessment Workshop held in Nairobi, Kenya [@smarthighlevel]. Results from this research suggested a feasibility of applying the similar plausibility check as that of WFHZ for MFAZ, with a maximum acceptability of percent of flagged 
records of 2.0%.
:::

We can run MFAZ plausibility check by calling `mw_plausibility_check_mfaz()`. As in WFHZ, we first need to ensure that the data is in the right shape and format that is accepted and understood by the function. The workflow starts with wrangling age; for this, we approach the same way as in @sec-age.

:::{.callout-important}
## Age ratio test in MFAZ

As you know, the age ratio test in WFHZ is done on children aged 6 to 29 months old over those aged 30 to 59 months old. 
This is different in MFAZ. The test is done on children aged 6 to 23 months over those aged 24 to 59 months old. This is as in the SMART MUAC Tool [@smartmuactool]. The test results is also used in the prevalence analysis to implement what the SMART MUAC tool does. This is further demonstrated in the vignette about prevalence.
:::

### Wrangling MFAZ data {#sec-wrangle_mfaz}

This is the job of `mw_wrangle_muac()` function. We use it as follows:


```{r}
#| label: wrangle_mfaz_data
#| echo: true
#| eval: false

anthro.01 |>
  mw_wrangle_age(
    dos = dos,
    dob = dob,
    age = age,
    .decimals = 2
  ) |>
  mw_wrangle_muac(
    sex = sex,
    muac = muac,
    age = age,
    .recode_sex = TRUE,
    .recode_muac = TRUE,
    .to = "cm"
  )
```

Just as in WFHZ wrangler, under the hood, `mw_wrangle_muac()` computes the z-scores then identifies outliers and flags them. These are stored in the `mfaz` and `flag_mfaz` variables that are created and added to the dataset. 

The above code returns: 


```{r}
#| label: wrangle_mfaz_data-view
#| echo: false
#| eval: true

anthro.01 |>
  mw_wrangle_age(
    dos = dos,
    dob = dob,
    age = age,
    .decimals = 2
  ) |>
  mw_wrangle_muac(
    sex = sex,
    muac = muac,
    age = age,
    .recode_sex = TRUE,
    .recode_muac = TRUE,
    .to = "cm"
  )
```

:::{.callout-note}
`mw_wrangle_muac()` accepts MUAC values in centimetres. This is why it takes the arguments `.recode_muac` and `.to` to control whether there is need to transform the variable `muac` or not. Read the function documentation to learn about how to control these two arguments.
:::

### On to *de facto* plausibility check of MFAZ data

We achieve this by calling the `mw_plausibility_check_mfaz()` function: 


```{r}
#| label: pl_mfaz
#| echo: true
#| eval: false

anthro.01 |>
  mw_wrangle_age(
    dos = dos,
    dob = dob,
    age = age,
    .decimals = 2
  ) |>
  mw_wrangle_muac(
    sex = sex,
    muac = muac,
    age = age,
    .recode_sex = TRUE,
    .recode_muac = TRUE,
    .to = "cm"
  ) |>
  mw_plausibility_check_mfaz(
    sex = sex,
    muac = muac,
    age = age,
    flags = flag_mfaz
  )
```

And this will return: 


```{r}
#| label: pl_mfaz-view
#| echo: false
#| eval: true

anthro.01 |>
  mw_wrangle_age(
    dos = dos,
    dob = dob,
    age = age,
    .decimals = 2
  ) |>
  mw_wrangle_muac(
    sex = sex,
    muac = muac,
    age = age,
    .recode_sex = TRUE,
    .recode_muac = TRUE,
    .to = "cm"
  ) |>
  mw_plausibility_check_mfaz(
    sex = sex,
    muac = muac,
    age = age,
    flags = flag_mfaz
  )
```

We can also neat this output. We just need to call `mw_neat_output_mfaz()` and chain it to the pipeline:


```{r}
#| label: pretty_mfaz
#| echo: true
#| eval: false

anthro.01 |>
  mw_wrangle_age(
    dos = dos,
    dob = dob,
    age = age,
    .decimals = 2
  ) |>
  mw_wrangle_muac(
    sex = sex,
    muac = muac,
    age = age,
    .recode_sex = TRUE,
    .recode_muac = TRUE,
    .to = "cm"
  ) |>
  mw_plausibility_check_mfaz(
    sex = sex,
    muac = muac,
    age = age,
    flags = flag_mfaz
  ) |>
  mw_neat_output_mfaz()
```

This will return: 


```{r}
#| label: pretty_mfaz-view
#| echo: false
#| eval: true

anthro.01 |>
  mw_wrangle_age(
    dos = dos,
    dob = dob,
    age = age,
    .decimals = 2
  ) |>
  mw_wrangle_muac(
    sex = sex,
    muac = muac,
    age = age,
    .recode_sex = TRUE,
    .recode_muac = TRUE,
    .to = "cm"
  ) |>
  mw_plausibility_check_mfaz(
    sex = sex,
    muac = muac,
    age = age,
    flags = flag_mfaz
  ) |>
  mw_neat_output_mfaz()
```

We can also run checks on a multiple-area dataset as follows: 


```{r}
#| label: grouped_mfaz
#| echo: true
#| eval: false

anthro.01 |>
  mw_wrangle_age(
    dos = dos,
    dob = dob,
    age = age,
    .decimals = 2
  ) |>
  mw_wrangle_muac(
    sex = sex,
    muac = muac,
    age = age,
    .recode_sex = TRUE,
    .recode_muac = TRUE,
    .to = "cm"
  ) |>
  mw_plausibility_check_mfaz(
    sex = sex,
    muac = muac,
    age = age,
    flags = flag_mfaz,
    area
  ) |>
  mw_neat_output_mfaz()
```

This will return: 


```{r}
#| label: grouped_mfaz-view
#| echo: false
#| eval: true

anthro.01 |>
  mw_wrangle_age(
    dos = dos,
    dob = dob,
    age = age,
    .decimals = 2
  ) |>
  mw_wrangle_muac(
    sex = sex,
    muac = muac,
    age = age,
    .recode_sex = TRUE,
    .recode_muac = TRUE,
    .to = "cm"
  ) |>
  mw_plausibility_check_mfaz(
    sex = sex,
    muac = muac,
    age = age,
    flags = flag_mfaz,
    area
  ) |>
  mw_neat_output_mfaz()
```

At this point, you have reached the end of your workflow ✨.

## Plausibility check of raw MUAC data

We will assess the plausibility of raw MUAC data through it's raw values when the variable age is not available in the dataset. This is a job assigned to `mw_plausibility_check_muac()`. The workflow for this check is the shortest one.

### Data wrangling

As you can tell, z-scores cannot be computed in the absence of age. In this way, the data wrangling workflow would be quite minimal. You still set the arguments inside `mw_wrangle_muac()` as learned in @sec-wrangle_mfaz. The only difference is that here we will set `age` to `NULL`. Fundamentally, under the hood the function detects MUAC values that are outliers and flags them and stores them in `flag_muac` variable that is added to the dataset. 
  
We will continue using the same dataset:


```{r}
#| label: wrangle_muac
#| echo: true
#| eval: false

anthro.01 |>
  mw_wrangle_muac(
    sex = sex,
    muac = muac,
    age = NULL,
    .recode_sex = TRUE,
    .recode_muac = FALSE,
    .to = "none"
  )
```

This returns: 


```{r}
#| label: wrangle_muac-view
#| echo: false
#| eval: true

anthro.01 |>
  mw_wrangle_muac(
    sex = sex,
    muac = muac,
    age = NULL,
    .recode_sex = TRUE,
    .recode_muac = FALSE,
    .to = "none"
  )
```

### On to *de facto* plausibility check

We just have to add `mw_plausibility_check_muac()` to the above pipeline:


```{r}
#| label: pl_muac
#| echo: true
#| eval: false

anthro.01 |>
  mw_wrangle_muac(
    sex = sex,
    muac = muac,
    age = NULL,
    .recode_sex = TRUE,
    .recode_muac = FALSE,
    .to = "none"
  ) |>
  mw_plausibility_check_muac(
    sex = sex,
    flags = flag_muac,
    muac = muac
  )
```

And this will return: 


```{r}
#| label: pl_muac-view
#| echo: false
#| eval: true

anthro.01 |>
  mw_wrangle_muac(
    sex = sex,
    muac = muac,
    age = NULL,
    .recode_sex = TRUE,
    .recode_muac = FALSE,
    .to = "none"
  ) |>
  mw_plausibility_check_muac(
    sex = sex,
    flags = flag_muac,
    muac = muac
  )
```

We can also return a formatted table with `mw_neat_output_muac()`:


```{r}
#| label: neat_table_muac
#| echo: true
#| eval: false

anthro.01 |>
  mw_wrangle_muac(
    sex = sex,
    muac = muac,
    age = NULL,
    .recode_sex = TRUE,
    .recode_muac = FALSE,
    .to = "none"
  ) |>
  mw_plausibility_check_muac(
    sex = sex,
    flags = flag_muac,
    muac = muac
  ) |>
  mw_neat_output_muac()
```

And we get:


```{r}
#| label: neat_table_muac-view
#| echo: false
#| eval: true

anthro.01 |>
  mw_wrangle_muac(
    sex = sex,
    muac = muac,
    age = NULL,
    .recode_sex = TRUE,
    .recode_muac = FALSE,
    .to = "none"
  ) |>
  mw_plausibility_check_muac(
    sex = sex,
    flags = flag_muac,
    muac = muac
  ) |>
  mw_neat_output_muac()
```


When working on multiple-area data, we approach the task the same way as demonstrated above:


```{r}
#| label: by_area
#| echo: true
#| eval: false

## Check plausibility ----
anthro.01 |>
  mw_wrangle_muac(
    sex = sex,
    muac = muac,
    age = NULL,
    .recode_sex = TRUE,
    .recode_muac = FALSE,
    .to = "none"
  ) |>
  mw_plausibility_check_muac(
    sex = sex,
    flags = flag_muac,
    muac = muac,
    area
  ) |>
  mw_neat_output_muac()
```

And we get:


```{r}
#| label: by_area-view
#| echo: false
#| eval: true

## Check plausibility ----
anthro.01 |>
  mw_wrangle_muac(
    sex = sex,
    muac = muac,
    age = NULL,
    .recode_sex = TRUE,
    .recode_muac = FALSE,
    .to = "none"
  ) |>
  mw_plausibility_check_muac(
    sex = sex,
    flags = flag_muac,
    muac = muac,
    area
  ) |>
  mw_neat_output_muac()
```

# References
