% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/direct_adjusting.R
\name{directly_adjusted_estimates}
\alias{directly_adjusted_estimates}
\title{Directly Adjusted Estimates}
\usage{
directly_adjusted_estimates(
  stats_dt,
  stat_col_nms,
  var_col_nms,
  stratum_col_nms = NULL,
  adjust_col_nms = NULL,
  conf_lvls = 0.95,
  conf_methods = "identity",
  weights = NULL
)
}
\arguments{
\item{stats_dt}{\verb{[data.frame]} (no default)

a \code{data.frame} containing estimates and variance estimates of statistics}

\item{stat_col_nms}{\verb{[character]} (no default)

names of columns in \code{stats_dt} containing estimates (statistics);
\code{NA} statistics values cause also \code{NA} confidence intervals}

\item{var_col_nms}{\verb{[character]} (default \code{NULL})
\itemize{
\item if \code{NULL}, no confidence intervals can (will) be computed
\item if \code{character} vector, names of columns in \code{stats_dt} containing variance
estimates of the statistics specified in \code{stat_col_nms} with one-to-one
correspondence; \code{NA} elements in \code{var_col_nms} cause no confidence
intervals to computed for those statistics;
\code{NA} variance estimates in \code{stats_dt} cause \code{NA} confidence intervals;
negative values cause an error; \code{Inf} values cause \code{c(-Inf, Inf)}
intervals with confidence interval method \code{"identity"}, etc.
}}

\item{stratum_col_nms}{\verb{[NULL, character]} (default \code{NULL})

names of columns in \code{stats_dt} by which statistics are stratified (and they
should be stratified by these columns after direct adjusting)}

\item{adjust_col_nms}{\verb{[NULL, character]} (default \code{NULL})

Names of columns in \code{stats_dt} by which statistics are currently stratified
and by which the statistics should be adjusted (e.g. \code{"agegroup"}).
\itemize{
\item \code{NULL}: If \code{weights} is a \code{data.table}, use its stratifying columns. Else
no adjusting is performed.
\item \code{character}: Adjust by these columns.
}}

\item{conf_lvls}{\verb{[numeric]} (default \code{0.95})

confidence levels for confidence intervals; you may specify each statistic
(see \code{stat_col_nms}) its own level by supplying a vector of values;
values other than between \verb{(0, 1)} cause an error}

\item{conf_methods}{\verb{[character, list]} (default \code{"identity"})

Method(s) to compute confidence intervals. Either one method for all stats
(\code{stat_col_nms}) or otherwise this must be of length
(\code{length(stat_col_nms)}). Each element is passed to
\verb{[delta_method_confidence_intervals]} separately.

Can also be \code{"none"}: This causes no confidence intervals to be calculated
for the respective \code{stat_col_nms} element(s).}

\item{weights}{\verb{[double, data.table, character]}

The weights need not sum to one as this is ensured internally. You may
supply weights in one of the following ways:
\itemize{
\item \code{double}: A vector of weights, the length of which must match the number
of strata defined by adjusting variables.
\item \code{data.table}: With one or more columns with names matching to those
variables that are used to adjust estimates, and one column named
\code{weight}. E.g. \code{data.table(agegroup = 1:3, weight = c(100, 500, 400))}.
}}
}
\value{
Returns a \code{data.table}. Returned columns are those given via
\code{stratum_col_nms}, \code{stat_col_nms}, and \code{var_col_nms} and additional
confidence interval columns. If \code{weights} was a
\code{data.table}, the names of the stats, variances, and confidence bounds
columns are identified by the respective suffix of the weight column,
e.g. \code{stat_col_nms = c("s", "r")} and
\code{weights = data.table(age_group = 1:4, weight_1 = 1:4, weight2 = 4:1)}
will result in output columns \code{s_1}, \code{s2}, \code{r_1}, and \code{r2} etc.
}
\description{
Compute direct adjusted estimates from a table of statistics.
}
\details{
\code{directadjusting::directly_adjusted_estimates} computes weighted
averages and their confidence intervals. Performs the following steps:
\itemize{
\item Makes a new \code{data.table} with data from \code{stats_dt} without copying any
column data to avoid modifying \code{stats_dt} itself.
\item Handle argument \code{weights} in order to produce a \code{data.table} of weights
if it wasn't one already.
\item Insert the weights into \code{stats_dt}.
\itemize{
\item Weights are merged into \code{stats_dt} in-place by making a left join
of \code{stats_dt} and \code{weights_dt}.
\item Re-scale weights to sum to one within each stratum defined by
\code{stratum_col_nms}.
}
\item Compute weighted averages of \code{stat_col_nms} and \code{var_col_nms}
(the latter with squared weights because they are variances)
over \code{adjust_col_nms}. This results in a \code{data.table} without column(s)
\code{adjust_col_nms}.
\item For each statistic:
\itemize{
\item If the corresponding \code{conf_methods} element is \code{"none"}, skip confidence
intervals computation.
\item Otherwise call \verb{[delta_method_confidence_intervals]}.
}
\item Set attribute \code{directly_adjusted_estimates_meta}. It is a list
containing:
\itemize{
\item \code{call}: The call to \code{directadjusting::directly_adjusted_estimates}.
\item \code{stat_col_nms}: The argument as given by the user.
\item \code{var_col_nms}: The argument as given by the user.
\item \code{stratum_col_nms}: The argument as given by the user.
\item \code{adjust_col_nms}: The argument as given by the user.
\item \code{conf_lvls}: The argument, but always of length \code{length(stat_col_nms)}.
\item \code{conf_methods}: The argument, but always of length
\code{length(stat_col_nms)}.
\item \code{meta_dt}: Contains columns
\itemize{
\item \code{stat_col_nm}: Elements of argument \code{stat_col_nms}.
\item \code{stat_col_nm_w}: Corresponding name of column containing weighted
statistics. These columns names are in the output of
\code{directadjusting::directly_adjusted_estimates}.
\item \code{var_col_nm}: Elements of argument \code{var_col_nms}.
\item \code{var_col_nm_w}: Like \code{stat_col_nm_w} but for variance column names.
\item \code{conf_method}: Correspoding \code{conf_methods} elements.
\item \code{conf_lvl}: Correspoding \code{conf_lvls} elements.
\item \code{ci_lo_col_nm_w}: Name of confidence interval lower bound of the
weighted statistic.
\item \code{ci_hi_col_nm_w}: Name of confidence interval upper bound of the
weighted statistic.
}
}
\item Return a \code{data.table}. Returned columns are those given via
\code{stratum_col_nms}, \code{stat_col_nms}, and \code{var_col_nms} and additional
confidence interval columns. If \code{weights} was a
\code{data.table}, the names of the stats, variances, and confidence bounds
columns are identified by the respective suffix of the weight column,
e.g. \code{stat_col_nms = c("s", "r")} and
\code{weights = data.table(age_group = 1:4, weight_1 = 1:4, weight2 = 4:1)}
will result in output columns \code{s_1}, \code{s2}, \code{r_1}, and \code{r2} etc.
}
}
\section{News for version 0.7.0}{


\code{directadjusting::directly_adjusted_estimates} argument \code{adjust_col_nms} is
now automatically
determined based on \code{weights} if \code{weights} is a \code{data.frame} /
\code{data.table}.

\code{directadjusting::directly_adjusted_estimates} can now handle \code{weights}
\code{data.table} with more than one column containing weights, e.g.
\code{weight_europe}, \code{weight_world}.
}

\examples{

# directadjusting::directly_adjusted_estimates
library("data.table")
set.seed(1337)

offsets <- rnorm(8, mean = 1000, sd = 100)
baseline <- 100
hrs_by_sex <- rep(1:2, each = 4)
hrs_by_ag <- rep(c(0.75, 0.90, 1.10, 1.25), times = 2)
counts <- rpois(8, baseline * hrs_by_sex * hrs_by_ag)

# raw estimates
my_stats <- data.table::data.table(
  sex = rep(1:2, each = 4),
  ag = rep(1:4, times = 2),
  e = counts / offsets,
  v = counts / (offsets**2)
)

# adjusted by age group
my_adj_stats <- directly_adjusted_estimates(
  stats_dt = my_stats,
  stat_col_nms = "e",
  var_col_nms = "v",
  conf_lvls = 0.95,
  conf_methods = "log",
  stratum_col_nms = "sex",
  adjust_col_nms = "ag",
  weights = c(200, 300, 400, 100)
)

# adjusted by smaller age groups, stratified by larger age groups
my_stats[, "ag2" := c(1, 1, 2, 2, 1, 1, 2, 2)]
my_adj_stats <- directly_adjusted_estimates(
  stats_dt = my_stats,
  stat_col_nms = "e",
  var_col_nms = "v",
  conf_lvls = 0.95,
  conf_methods = "log",
  stratum_col_nms = c("sex", "ag2"),
  adjust_col_nms = "ag",
  weights = c(200, 300, 400, 100)
)

# with no adjusting columns defined you get the same table as input
# but with confidence intervals. this for the sake of
# convenience for programming cases where sometimes you want to adjust,
# sometimes not.
stats_dt_2 <- data.table::data.table(
  sex = 0:1,
  e = 0.0,
  v = 0.1
)
dt_2 <- directadjusting::directly_adjusted_estimates(
  stats_dt = stats_dt_2,
  stat_col_nms = "e",
  var_col_nms = "v",
  conf_lvls = 0.95,
  conf_methods = "identity",
  stratum_col_nms = "sex"
)
stopifnot(
  dt_2[["e"]] == stats_dt_2[["e"]],
  dt_2[["v"]] == stats_dt_2[["v"]],
  dt_2[["sex"]] == stats_dt_2[["sex"]]
)

# sometimes when adjusting rates or counts, there can be strata where the
# statistic is zero. these should be included in your statistics dataset
# if you still want the weighted average be influenced by the zero.
# otherwise you will get the wrong result. sometimes when naively tabulating
# a dataset with e.g. dt[, .N, keyby = "stratum"] one does not get a result
# row for a stratum that does not appear in the dataset even if we know that
# the stratum exists, for instance only the age groups 1-17 are present in
# the dataset.
stats_dt_3 <- data.table::data.table(
  age_group = 1:18,
  count = 17:0,
  var = 17:0
)

# this goes as intended
dt_3 <- directadjusting::directly_adjusted_estimates(
  stats_dt = stats_dt_3,
  stat_col_nms = "count",
  var_col_nms = "var",
  stratum_col_nms = NULL,
  adjust_col_nms = "age_group",
  weights = data.table::data.table(
    age_group = 1:18,
    weight = 18:1
  )
)

# this does not
dt_4 <- directadjusting::directly_adjusted_estimates(
  stats_dt = stats_dt_3[1:17, ],
  stat_col_nms = "count",
  var_col_nms = "var",
  stratum_col_nms = NULL,
  adjust_col_nms = "age_group",
  weights = data.table::data.table(
    age_group = 1:18,
    weight = 18:1
  )
)

# the weighted average that included the zero is smaller
stopifnot(
  dt_3[["count"]] < dt_4[["count"]]
)

# NAs are allowed and produce in turn NAs silently.
stats_dt_5 <- data.table::data.table(
  age_group = 1:18,
  count = c(NA, 16:0),
  var = c(NA, 16:0)
)
dt_5 <- directadjusting::directly_adjusted_estimates(
  stats_dt = stats_dt_5,
  stat_col_nms = "count",
  var_col_nms = "var",
  adjust_col_nms = "age_group",
  weights = data.table::data.table(
    age_group = 1:18,
    weight = 18:1
  )
)
stopifnot(
  is.na(dt_5)
)

stats_dt_6 <- data.table::data.table(
  age_group = 1:4,
  survival = c(0.20, 0.40, 0.60, 0.80),
  survival_var = 0.05^2
)
# you can use conf_methods to pass whatever to
# `delta_method_confidence_intervals`.
dt_6 <- directadjusting::directly_adjusted_estimates(
  stats_dt = stats_dt_6,
  stat_col_nms = "survival",
  var_col_nms = "survival_var",
  adjust_col_nms = "age_group",
  weights = data.table::data.table(
    age_group = 1:4,
    weight = 1:4
  ),
  conf_methods = list(
    list(
      g = quote(stats::qnorm(theta)),
      g_inv = quote(stats::pnorm(g))
    )
  )
)

# the wame weights data.table can contain more than one weight column
dt_7 <- directadjusting::directly_adjusted_estimates(
  stats_dt = stats_dt_6,
  stat_col_nms = "survival",
  var_col_nms = "survival_var",
  adjust_col_nms = "age_group",
  weights = data.table::data.table(
    age_group = 1:4,
    weight_1 = 1:4,
    weight2 = 4:1
  )
)
stopifnot(
  c("survival_1", "survival2") \%in\% names(dt_7)
)

# ... and multiple statistics columns as well
data.table::set(
  x = stats_dt_6,
  j = c("risk", "risk_var"),
  value = list(
    1 - stats_dt_6[["survival"]],
    stats_dt_6[["survival_var"]]
  )
)
dt_8 <- directadjusting::directly_adjusted_estimates(
  stats_dt = stats_dt_6,
  stat_col_nms = c("survival", "risk"),
  var_col_nms = c("survival_var", "risk_var"),
  adjust_col_nms = "age_group",
  weights = data.table::data.table(
    age_group = 1:4,
    weight_1 = 1:4,
    weight2 = 4:1
  )
)
stopifnot(
  c("survival_1", "survival2", "risk_1", "risk2") \%in\% names(dt_8)
)

}
