---
title: "Inferential Tests and Assumptions"
description: >
  Understand the default tests selected by gtstats, their indications,
  automatic checks, and assumptions that require study-design judgement.
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Inferential Tests and Assumptions}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>", eval = TRUE)
library(gtstats)
```

`gtstats` uses conservative, beginner-friendly defaults. Automatic selection
can inspect the data, but it cannot determine whether observations are
independent or whether the design and denominator answer the intended clinical
question. Those decisions remain the analyst's responsibility.

## Quantify the magnitude separately

Use `effect_size()` when the question is how large a difference or association
is. Its default output is deliberately smaller than `compare_groups()`:

```{r effect-size}
to_flextable(effect_size(mtcars, variable = mpg, group = am))
```

The automatic measure follows the comparison structure:

- two continuous groups: Hedges' g, with a confidence interval;
- two-group rank comparison: rank-biserial correlation;
- more than two continuous groups: omega-squared;
- multi-group rank comparison: epsilon-squared;
- categorical association: Cramer's V.

For a two-group effect, the Contrast column explicitly names the grouping
variable and uses its displayed order: first group minus second group. Positive
and negative standardized or rank effects therefore have an unambiguous
direction. Cramer's V and omnibus measures describe association or overall
variation and have no direction. Interval method information is retained in
the notes; Hedges' g intervals are labelled as approximate large-sample
intervals.

An explicit method remains available when the scientific question requires it:

```{r effect-size-rank}
to_flextable(effect_size(
  mtcars,
  variable = mpg,
  group = am,
  method = "rank_biserial"
))
```

Generic magnitude labels are excluded by default. Set
`interpretation = TRUE` only when a conventional teaching label is useful; the
table then states that this is not a threshold for clinical importance. For
risk ratios, odds ratios, and risk differences, use `crosstabs()` so that
the exposure and event direction remain explicit.

## Default selection policy

`compare_groups(test = "auto")` follows these fixed rules. The selected test
is never hidden: it is printed in the result and recorded with its rule and
inputs in `$method`, `$diagnostics`, and `$notes`.

| Comparison | What auto checks | Test selected |
|---|---|---|
| Continuous, two independent groups | Marked skewness within each group; `var_equal` | Welch t-test by default; Student's t-test when `var_equal = TRUE`; Wilcoxon rank-sum only if one or more groups have marked skewness |
| Continuous, three or more independent groups | Marked skewness within each group; `var_equal` | Welch ANOVA by default; classical ANOVA when `var_equal = TRUE`; Kruskal-Wallis if one or more groups have marked skewness |
| Continuous, paired (two occasions) | Marked skewness of within-pair differences | Paired t-test if not flagged; Wilcoxon signed-rank if flagged |
| Continuous, paired (3+ occasions) | Marked skewness at each occasion | Repeated-measures ANOVA with Greenhouse-Geisser-corrected degrees of freedom if not flagged; Friedman test if flagged |
| Ordinal, independent | Expected cell counts | Pearson chi-square when no expected count is below 1 and no more than 20% are below 5; Fisher's exact otherwise |
| Ordinal, paired | Outcome is ordered | Wilcoxon signed-rank (two occasions) or Friedman (3+ occasions) |
| Binary or nominal categorical, independent | Expected cell counts | Pearson chi-square when no expected count is below 1 and no more than 20% are below 5; Fisher's exact otherwise |
| Binary, paired | Paired design and binary outcome | McNemar test (two occasions) or Cochran's Q test (3+ occasions) |

The continuous-variable switch means **marked** absolute sample skewness
(default cut-off 1), not any asymmetry and not a normality-test p-value.
Shapiro-Wilk is supporting information only and does not alone switch the
test. `add_p()` uses the same rules.

## Ordinal values: make the meaning explicit

`compare_groups()` retains an `ordered` factor's ordinal classification, but for
an **independent Table 1 comparison** it uses chi-square/Fisher to compare the
distribution of all levels. Request `test = "wilcox"` or `test = "kruskal"` if
the clinical question is specifically about the ordered ranks. A numeric variable
with a few values (for example `0`, `1`, `2`, `3`
visits or cancer stages coded `1`--`4`) is deliberately treated as a
categorical/count-coded variable unless its order is explicitly declared. This
avoids silently treating a clinical code as a numerical scale. Convert a true
ordered variable before comparing it:

```r
data$stage <- ordered(data$stage, levels = c(1, 2, 3, 4))
compare_groups(data, variable = stage, group = arm) # categorical distribution
compare_groups(data, variable = stage, group = arm, test = "wilcox") # rank shift
```

`describe_data()` makes this distinction visible: explicit ordered factors are
shown as `ordinal`; small integer-coded variables receive a possible
ordinal/count-coded flag for review against the data dictionary. It does not
change the analysis type automatically.

Other automatic defaults are:

| Question | Default |
|---|---|
| Estimate one proportion | Exact binomial confidence interval |
| Correlate two continuous variables | Pearson for approximately symmetric variables; otherwise Spearman |
| Estimate an event rate | Exact Poisson confidence interval |

## Proportions are estimates, not automatically tests

`proportion_stats()` estimates a proportion and Wilson score confidence
interval. It does not test whether groups differ.

```{r proportion}
to_flextable(proportion_stats(mtcars, var = vs, by = am))
```

To compare categorical distributions, use `compare_groups()`, `add_p()`, or
`crosstabs()`.

```{r categorical}
to_flextable(compare_groups(mtcars, variable = vs, group = am))
to_flextable(crosstabs(mtcars, row = am, col = vs))
```

In automatic mode, expected cell counts are calculated. Fisher's exact test is
selected when an expected count is below 1 or more than 20% of expected cells
are below 5; otherwise chi-square is used. Larger sparse tables use Fisher's
test with a Monte Carlo p-value.
Returned objects expose the expected counts and the minimum expected count.

The analyst must still confirm:

- observations are independent;
- each observation contributes to one cell;
- categories are mutually exclusive;
- row and column levels have been defined in the intended direction.

For paired binary observations, supply an identifier and use McNemar's test:

```{r mcnemar}
to_flextable(compare_groups(
  paired_data,
  variable = symptom_present,
  group = visit,
  paired = TRUE,
  id = id
))
```

## Continuous outcomes

Welch's t-test is the two-group parametric default because it does not require
equal variances. Welch ANOVA is the corresponding default for three or more
groups. When equal variances are justified in a prespecified analysis plan,
`var_equal = TRUE` changes the non-skewed independent automatic route to
Student's t-test or classical ANOVA. It does not run, infer, or prove an
equal-variance hypothesis test.

Use `assess_variance()` to make the observed group spread visible before
interpreting a comparison. It reports SDs, variances, and largest/smallest
spread ratios and displays the median-centred Levene test by default. Bartlett
is available as optional supporting information. These tests are never
gatekeepers and do not change the automatic choice.

```{r variance-diagnostics}
to_flextable(assess_variance(mtcars, vars = mpg, by = am))
to_flextable(assess_variance(mtcars, vars = mpg, by = am, test = "none"))
to_flextable(assess_variance(mtcars, vars = mpg, by = am, test = "bartlett"))
```

The same observed-spread diagnostic is retained in an independent continuous
`compare_groups()` result. It is descriptive context, not a test-selection
rule: Welch t-tests and Welch ANOVA do not require equal variances. The value
of `var_equal` is a transparent user choice, not a data-driven variance test.

```{r continuous}
to_flextable(compare_groups(
  mtcars,
  variable = mpg,
  group = am,
  test = "auto"
))

to_flextable(compare_groups(mtcars, variable = mpg, group = cyl))
to_flextable(compare_groups(mtcars, variable = mpg, group = cyl, test = "anova"))
```

Distribution guidance primarily uses skewness. Shapiro-Wilk results are
supporting information and are not used alone to select a test. Analysts should
also inspect outliers and plots. To see the exact automatic decision for one
analysis, inspect the saved result:

```{r auto-audit}
result <- compare_groups(mtcars, variable = mpg, group = am)
result$method$selection_rule
result$method$selection_inputs
diagnostics_stats(result)
```

Wilcoxon rank-sum and Kruskal-Wallis tests compare ranks. Interpreting them
specifically as median comparisons requires broadly similar distribution
shapes across groups.

For paired continuous analyses, distribution guidance is applied to the
within-pair differences rather than each measurement occasion separately.

## Summary-table p-values

`add_p()` uses the same automatic selection policy as `compare_groups()`.
Distribution guidance is enabled by default.

```{r add-p}
summary_table(mtcars, by = am, include = c(mpg, wt, vs), overall = TRUE) |>
  add_p() |>
  to_flextable()
```

Tests can be prespecified per variable:

```{r add-p-explicit}
summary_table(mtcars, by = am, include = c(mpg, wt, vs)) |>
  add_p(
    test = c(
      mpg = "welch_t",
      wt = "wilcox",
      vs = "fisher"
    ),
    distribution_check = FALSE
  ) |>
  to_flextable()
```

To use the equal-variance parametric route deliberately:

```{r equal-variance-auto}
to_flextable(compare_groups(trial_data, change_score, group = arm, var_equal = TRUE))
```

The table footnote records tests used and reminds readers that independence
must be confirmed from the study design.

## Correlation

Automatic correlation selection uses marginal distribution shape, but this
cannot confirm the shape of the relationship. Inspect a scatterplot:

- Pearson requires an approximately linear relationship.
- Spearman requires a monotonic relationship.

With `method = "auto"`, `correlation()` uses Pearson only when both marginal
absolute sample skewness values are below 1; otherwise it uses Spearman. This
is a transparent default, not proof that the relationship is linear or
monotonic. Inspect `plot_correlation()` before reporting the coefficient.
`diagnostics_stats()` records the two skewness values, selected rule, and the
number of complete finite pairs used.
- Both require independent observation pairs without dominating influential
  observations.

For exploratory work with several continuous variables, supply `vars` instead
of `x` and `y`. One method is deliberately used throughout the matrix, avoiding
a confusing mixture of Pearson and Spearman coefficients. Each pair may have a
different denominator when values are missing, so inspect `$summary` before
reporting selected results.

```{r correlation-matrix}
matrix_result <- correlation(
  mtcars,
  vars = c(mpg, disp, hp, wt),
  display = "estimate_p",
  adjust = "holm"
)

to_flextable(matrix_result)
plot_correlation(matrix_result)
```

The heatmap shows direction and magnitude, not importance or causality.
Multiplicity adjustment is available for exploratory p-values, but a matrix
does not replace a prespecified research question.

## Rates

`rate_stats()` estimates rates with exact Poisson confidence intervals. Confirm
that:

- events are valid counts;
- person-time or exposure time is positive and correctly accumulated;
- observations or event processes are suitably independent;
- a Poisson process is a reasonable approximation.

Counts per 100 people at a single time point are proportions, not incidence
rates, unless genuine observation time is represented.

## Inspect what was checked

Inferential objects retain transparent metadata:

```{r inspect}
result <- compare_groups(mtcars, variable = vs, group = am)

result$inferential
result$method
result$assumptions
result$diagnostics
result$denominators
result$notes
```

`$inferential` records the selected test and reason. `$method` contains detected
variable types and method metadata. `$assumptions` distinguishes automatic
checks from requirements that must be confirmed from the study design.
`$diagnostics` records check results, values, thresholds and interpretation.
`$denominators` records total, non-missing and missing observations together
with the numerator, denominator, group and rule used. `$notes` remains a short
human-readable explanation.

Use the inspection helpers for a consistent tibble or formatted table:

```{r inspect-helpers}
assumptions_stats(result)
diagnostics_stats(result)
denominators_stats(result)

denominators_stats(result, format = "tibble")
```

These audit helpers are intentionally separate from the publication table:

- `assumptions_stats()` records what the method assumes, including items that
  require design or clinical judgement rather than a software check.
- `diagnostics_stats()` shows numerical checks and automatic decisions in
  plain language; use `view = "audit"` for the underlying technical codes.
- `denominators_stats()` shows the analysed observations, missing values,
  numerators and denominators behind reported percentages, rates and risks;
  `view = "audit"` returns the underlying field names.

Use them to review an analysis before reporting it; they are not normally
included in a manuscript table.
