## ----include = FALSE----------------------------------------------------------
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)

## ----setup--------------------------------------------------------------------
Sys.setenv(OMP_THREAD_LIMIT = 1) # Reducing core use, to avoid accidental use of too many cores
library(Colossus)
library(data.table)
library(parallel)

## ----eval=TRUE----------------------------------------------------------------
apples <- c(0, 1, 2, 3, 4, 5, 6, 2, 2, 3, 4, 2, 1, 5, 6, 4, 2)
oranges <- c(1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1, 3, 2, 2, 1)
rip <- c(0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1)
hands <- c(1, 1, 2, 3, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2)
table <- data.table::data.table(
  apples = apples,
  oranges = oranges,
  rip = rip,
  hands = hands
)

## ----eval=TRUE----------------------------------------------------------------
# Suppose we want the categories to change by two:
categ <- "0/2/4/6/8"
# This would form bins like:
# [0,2), [2,4), etc.
# An entry with a value of 2 would be assigned to the second bin

# Suppose we wanted the first bin to be fully inclusive
categ <- "0]2/4/6/8"
# Now the first bin is: [0,2]
# An entry with a value of 2 would be assigned to the first bin only

# A named version might look like
categ <- "0 / low 2 / middle 4 / high 6 / extreme 8"
# This names the bins: low, middle, high, and extreme
# The default is a string representation of the bin

## ----eval=TRUE----------------------------------------------------------------
# Suppose we want the categories to change by two:
categ <- list(
  upper = c(2, 4, 6, 8),
  lower = c(0, 2, 4, 6)
)
# The version with an inclusive upper bound would be:
categ <- list(
  upper = c("2]", 4, 6, 8),
  lower = c(0, 2, 4, 6)
)

# We can also name categories
categ <- list(
  upper = c(2, 4, 6, 8),
  lower = c(0, 2, 4, 6),
  name = c("low", "middle", "high", "extreme")
)

## ----eval=TRUE----------------------------------------------------------------
apple_category <- "0/3/5]7"

orange_category <- list(
  lower = c(-1, 3, 6),
  upper = c(3, 6, 10),
  name = c("few", "good", "excessive")
)

# Finally we combine them into a list. The list names should be column
# names that the categories will be applied to.
categ <- list(
  apples = apple_category,
  oranges = orange_category
)
# We could also rename a category using `column AS new_name` in the list names.
# This is demonstrated later in the vignette.

## ----eval=TRUE----------------------------------------------------------------
# We might want two events to be summarized, the 'rip' and 'hands' columns.
# The first we can take the sum of, and name the summary 'dropped'
# The second we can just take a mean of
# This creates the event list, once again with list names
# matching columns in the data.
event <- list(rip = "count AS dropped", hands = "mean")

## ----eval=TRUE----------------------------------------------------------------
# We take our table, and apply the categorizations and event summaries
# The result has two values: 'df' and 'bounds'
# df is the final grouped table, with the categories and summaries
# bounds is a description of the category levels applied
Event_Count_Gen(table, categ, event)

## ----eval=TRUE----------------------------------------------------------------
# We can start by making some fake data
# a and b are arbitrary factors
# c might be the event status we are interested in
a <- c(0, 1, 2, 3, 4, 5, 6, 2, 2, 3, 4, 2, 1, 5, 6, 4, 2)
b <- c(1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1, 3, 2, 2, 1)
c <- c(0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1)

# Next we define columns for the calendar dates of each interval
# In this case we are defining day, month, and year
d <- c(1, 1, 2, 2, 1, 1, 2, 2, 3, 3, 3, 4, 4, 2, 1, 1, 2)
e <- c(1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1)
f <- c(
  1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
  1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900
)
g <- c(4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 5, 5, 5, 4, 4, 4, 4)
h <- c(6, 4, 4, 6, 6, 6, 4, 4, 4, 6, 6, 6, 6, 4, 4, 4, 4)
i <- c(
  1901, 1902, 1903, 1904, 1905, 1906, 1907, 1903, 1904,
  1903, 1904, 1910, 1903, 1904, 1903, 1904, 1910
)

# Finally we have our table that we want to group.
table <- data.table::data.table(
  a = a, b = b, c = c,
  d = d, e = e, f = f,
  g = g, h = h, i = i
)

## ----eval=TRUE----------------------------------------------------------------
# Our person-years are described by calendar dates
# We have entry and exit lists, each with the columns that
# correspond to the day/month/year.
# We also include a unit, to say we want our final person-years
# in terms of years, instead of days or months.
pyr <- list(
  entry = list(year = "f", month = "e", day = "d"),
  exit = list(year = "i", month = "h", day = "g"),
  unit = "years"
)

## ----eval=TRUE----------------------------------------------------------------
# A calendar category assumes we have a list with days, months, and years
# Yearly categories might look like:
calendar_categ <- list(year = c(2000, 2001, 2002))
# This will define categories going from (1/1/2000 - 12/31/2000), (1/1/2001 - 12/31/2001), etc.

# Alternatively we might want to categorize by duration since a reference date
# In this case our list has an additional value for categories, or upper/lower limits
# For an age based calendar time category, our day/month/year are reference columns not vectors of dates
# Suppose we wanted to categorize by above/below 50 years since entry
age_categ <- list(year = "f", categories = "0 / 50 / 100")


# We add this to our time categories by assigning it a name
# We can use the standard "column AS new_name" notation, new_name defaults to column_category
# How the name is used depends on the categorization
# Both will use 'new_name' as the category name
# Age based categories will use 'column' to define an average duration in the interval
time_categ <- list("calendar" = calendar_categ, "age" = age_categ)
# This will create three new columns in the data

## ----eval=TRUE----------------------------------------------------------------
# The non-time categories are defined as previously shown.
categ <- list(
  a = "-1/3/5]7",
  b = list(
    lower = c(-1, 3, 6), upper = c(3, 6, 10),
    name = c("low", "medium", "high")
  )
)

# The time categories follow a similar structure.
# We have a list with names that correspond to columns,
# and entries that give category limits.
# Our calendar categories are defined between each of these dates,
# upper bound exclusive.

# Time categories make a new column for the category, which should not be in the data.
time_scale <- list(`time_bin` = list(
  day = c(1, 1, 1),
  month = c(1, 1, 1),
  year = c(1899, 1903, 1910)
))

## ----eval=TRUE----------------------------------------------------------------
# Summaries follow the person-count table notation for events.
# We apply some summary to an existing column.
# The name should be the column, and we can use 'AS'
# to rename the summary as needed.
summary <- list(b = "weighted_mean AS b_weighted")

## ----eval=TRUE----------------------------------------------------------------
# Events in a person-time table are assumed to occur at the end
# of the interval.
# Events are automatically added to the summary list as a sum.
events <- list("c AS cases")

## ----eval=TRUE----------------------------------------------------------------
# We run the analysis just like the event_count data
# Here we are also setting fcount to true, to return the first at risk in each group
# We get the same returned value, the table and summary of category boundaries
print(Event_Time_Gen(table, pyr, time_scale, categ, summary, events, fcount = T))

# We can also change the units in our person-years
pyr <- list(
  entry = list(year = "f", month = "e", day = "d"),
  exit = list(year = "i", month = "h", day = "g"),
  unit = "days"
)
print(Event_Time_Gen(table, pyr, time_scale, categ, summary, events))

## ----eval=TRUE----------------------------------------------------------------
# Repeating the same non-time categories and event statuses
a <- c(0, 1, 2, 3, 4, 5, 6, 2, 2, 3, 4, 2, 1, 5, 6, 4, 2)
b <- c(1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1, 3, 2, 2, 1)
c <- c(0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1)

# Instead of calendar dates, we may have entry and exit duration
d <- c(1, 1, 2, 2, 10, 10, 15, 15, 20, 20, 30, 30, 40, 40, 50, 50, 60)
e <- c(11, 11, 22, 22, 30, 30, 45, 45, 50, 50, 60, 60, 70, 70, 80, 80, 90)

table <- data.table::data.table(
  a = a, b = b, c = c,
  d = d, e = e
)

# When we have duration instead of calendar dates, our person-year
# list should only have a single entry, instead of lists of columns.
pyr <- list(entry = "d", exit = "e")

## ----eval=TRUE----------------------------------------------------------------
# Once again, our non-time categories are defined the same
categ <- list(
  "a" = "-1/-1/3/5]7",
  "b AS b_bin" = list(lower = c(-1, -1, 3, 6), upper = c(-1, 3, 6, "]10"))
)

# Here we are defining the duration categories to use.
# This will create two columns, 'time' and 'time_bin'.
# 'time' is the average duration between the entry and exit duration.
# 'time_bin' is the category value.
# We can use 'time' to find the average duration in each group.
time_scale <- list("time AS time_bin" = "0 / 10 / 50 / 100")

## ----eval=TRUE----------------------------------------------------------------
summary <- list("c" = "count AS cases", "a" = "mean", "b" = "weighted_mean")
events <- list("c")

# Everything else runs the same, and gives similar outputs.
# Except now the time category boundaries are not based on dates.
print(Event_Time_Gen(table, pyr, time_scale, categ, summary, events))

