compute_matrix() gains a by argument
that accepts any combination of participant/contact groupings, not just
age. Each entry is either the string "age" (matching the
columns produced by assign_age_groups()), a stem
"<name>" (resolving to part_<name>
and cnt_<name>), or an explicit
c(part = "X", cnt = "Y") override. The result is a
rank-2K array where the first K axes index
participants and the last K index contacts. The default
by = "age" reproduces the single-grouping behaviour of
previous releases. split_matrix() currently still requires
a single-grouping matrix (#143).
symmetrise() and per_capita() now
accept multi-grouping matrices, with a single survey_pop
format across all groupings. survey_pop is a data frame
with one column per grouping, named after the grouping
(e.g. age, gender) and holding that grouping’s
levels as they appear in the matrix, plus a population
column, with one row per combination. Levels are matched exactly: there
is no interpolation. symmetrise() additionally requires the
participant- and contact-side dims to share the same levels, otherwise
reciprocity is undefined and it aborts (#319).
New rebin_ages() rebins a population table to a
coarser set of age groups by summing. It operates on an age
column of age-group labels (as produced by
limits_to_age_groups() or assign_age_groups())
and returns the same form, so it composes directly with the
post-processing functions. It only coarsens: requesting age groups finer
than the population data is an error, since splitting a band would
require assuming a within-band age distribution.
New align_ages() aligns a population table to a
contact matrix’s groupings, returning the survey_pop data
frame that symmetrise(), split_matrix() and
per_capita() expect. Supply population with an
age column of age-group label, plus a column per other
grouping; align_ages() coarsens age to the matrix’s age
groups within each combination of the other groupings (via
rebin_ages()) and aggregates categorical groupings by exact
name. The population must be at least as fine as the matrix’s age
groups. A typical workflow is
result |> symmetrise(survey_pop = align_ages(population, result))
(#319).
The contact_matrix S3 object now carries a
groupings field — the list of grouping triples that
produced its matrix. Used internally by the multi-grouping
post-processing functions; users can read it to introspect the matrix’s
structure (#319).
New flatten() returns a T x T matrix
view of a multi-grouping contact matrix — Manna et al.’s generalised
representation, with colon-joined dim labels
(e.g. "[0,5):F"). For single-grouping matrices it returns
the matrix unchanged (#319).
plot() and as.matrix() now work on
multi-grouping contact matrices, operating on the flattened
T x T view. matrix_plot() no longer assumes a
square matrix, so non-square flattened matrices plot correctly
(#321).
New vignette, Contact matrices across more than one grouping, with recipes for building, flattening, plotting and post-processing matrices over several groupings (#322).
weigh() gains a new canonical target shape: a
two-column data frame whose key column matches by is joined
and multiplied into weight. This makes recipes like
weigh(survey, "country", target = ...) natural. The
previous silent dispatch on a population data frame (a
target data frame with
lower.age.limit/population and no column
matching by) is soft-deprecated; use the new
weigh_by_age() for the same effect with an explicit name.
weigh_by_age() takes a reference population with an
age column of age-group labels and a
population column. New weigh_by_dayofweek() is
a thin wrapper around the existing 5/2 split. weigh()’s
named vector and groups paths are unchanged
(#314).
Exported function names now spell “age groups” consistently as
age_groups (snake_case), matching
assign_age_groups(). reduce_agegroups(),
limits_to_agegroups() and
agegroups_to_limits() are renamed to
reduce_age_groups(), limits_to_age_groups()
and age_groups_to_limits(); the old names remain as
deprecated aliases that warn (#331).
Interpolating population data to age groups finer than the data
itself is deprecated. contact_matrix() (when it adjusts
demographic data to the requested age groups) and pop_age()
still do it but now warn, and it will error in a future release. Supply
population data at least as fine as the requested age groups. The new
rebin_ages() and align_ages() never
interpolate: they error on finer requests.
pop_age() is deprecated in favour of
rebin_ages() and warns; it will be removed in a future
release (#328).
Advance deprecation cycle (#312). wpp_age(),
wpp_countries(), and
survey_country_population() are deprecated (warn) — all
three are thin layers over wpp2017, which is on its way
out. Construct a data.frame with columns
lower.age.limit and population from a current
source (e.g. the wpp2024 package from GitHub) and pass it
to contact_matrix() via survey_pop instead.
The implicit population lookup in contact_matrix() (when
survey_pop is not given but symmetric,
split, per_capita, weigh_age, or
return_demography is set) keeps the warning introduced in
0.6.0 with a sharper “will error in a future release” message.
wpp2017 remains in Imports for now, so this
lookup keeps working; it will move to Suggests in a later
release once reverse dependencies have migrated. The following are now
defunct (deprecate_stop): survey(),
check(), get_survey(),
download_survey(), list_surveys(),
survey_countries(), get_citation(), and the
missing_contact_age = "sample" option on
assign_age_groups() and contact_matrix(). The
dotted argument names (age.limits, survey.pop,
country.column, etc.) on contact_matrix(),
pop_age(), clean(), and
as_contact_survey() remain deprecated and warn, rather than
becoming defunct, so downstream packages still using them keep working
while they migrate. Bogus "1.0.0" versions on the
survey() and check() deprecation messages have
been corrected.
load_survey() now errors clearly when given no files
(e.g. an empty vector or NULL from a failed download)
instead of raising an opaque invalid 'file' argument.air.toml, the
style.yaml format-suggestion workflow, and the VS Code
formatter settings. lintr continues to run on changed files, and
indentation_linter is re-enabled (with a hanging-indent
style) to keep linting indentation now that air no longer handles
it.This release adds a pipeline of composable functions for building
contact matrices ([, assign_age_groups(),
weigh(), compute_matrix(),
symmetrise(), split_matrix(),
per_capita()) and a contact_matrix S3 class.
The vignette and README are rewritten around the pipeline (#288).
Minimum R version bumped to 4.1.0 (from 3.5.0). Examples in the
pipeline functions use the native |> pipe, introduced in
4.1.0.
Terminal age group labels now use [N,Inf) notation
instead of N+ when bracket notation is used
(e.g. [0,5), [5,15), [15,Inf)).
This matches the contactmatrix package and gives parseable interval
notation across all age groups. It affects matrix dimnames and the
age.group column in $participants; code that
matches on strings like "15+" will need updating to
"[15,Inf)". Dash notation (e.g. "15+") is
unchanged.
New [.contact_survey method allows filtering survey
objects with expressions,
e.g. polymod[country == "United Kingdom"] (#161).
New weigh() function for composable participant
weighting: supports day-of-week groups, named target vectors, direct
numeric columns, and population post-stratification (#161).
New compute_matrix() function computes a contact
matrix from a prepared survey. It is the final step of the pipeline
after assign_age_groups() and (optionally)
weigh() (#161).
New post-processing functions symmetrise(),
split_matrix(), and per_capita() operate on
compute_matrix() output. symmetrise() enforces
reciprocity, split_matrix() decomposes into mean contacts,
normalisation, and an assortativity matrix, and
per_capita() converts to per-capita rates. Example workflow
(#161):
uk_pop <- data.frame(
lower.age.limit = c(0, 5, 15),
population = c(3500000, 6000000, 50000000)
)
polymod[country == "United Kingdom"] |>
assign_age_groups(age_limits = c(0, 5, 15)) |>
compute_matrix() |>
symmetrise(survey_pop = uk_pop)Pipeline functions (compute_matrix(),
symmetrise(), split_matrix(),
per_capita()) return a contact_matrix S3 class
with print(), plot(), and
as.matrix() methods. The class inherits from
list, so existing code using $matrix or
$participants continues to work.
New contact_age_distribution() function extracts the
empirical age distribution of contacts from a survey. Pass it to
assign_age_groups(estimated_contact_age = ...) to impute
ages from ranges by sampling from the reference distribution instead of
uniformly. This matters for surveys where many contacts have broad age
bands, since uniform sampling would flatten age-assortativity.
New agegroups_to_limits() function converts age
group labels back to lower age limits, the inverse of
limits_to_agegroups().
compute_matrix() gains a
weight_threshold parameter to cap extreme weights before
normalisation, matching the contact_matrix() option
(#131).
Fixed bug where participants with NA dayofweek were
incorrectly weighted as weekend days. They now receive an average weight
across all days (#131).
Fixed unmatched-merge warning count when merging files with duplicate keys; previously, the count could be wrong (or negative) due to counting join pairs rather than distinct matched rows (#289).
matrix_plot() now restores all graphical parameters
(par()) on exit, including when the function errors
mid-plot. Previously the legend parameters (new,
pty) and the error handler (err) were left
modified in the user’s session (#307).
load_survey() now attaches contact-level files
(those keyed at the contact level, e.g. a contact-attributes file
sharing only part_id with participants) to the contact
table instead of inflating the participant table to one row per contact.
Previously such files were merged into participants, squaring contact
counts in the resulting matrix (#326).
wpp_age() and wpp_countries() are now
soft-deprecated. Pass population data directly via the
survey_pop argument instead. The underlying
wpp2017 data is also outdated; the wpp2024
package from GitHub provides more recent data (#258).
contact_matrix() now warns when it would look up
population data automatically via wpp_age(). This automatic
lookup happens when symmetric, split,
per_capita, weigh_age, or
return_demography is set and countries is
given (or the participant data has a country column)
without an explicit survey_pop. The implicit lookup will be
removed in a future release; pass survey_pop directly
(e.g. from survey_country_population() or the
wpp2024 package) to silence the warning and make the code
forwards-compatible.
get_survey(), download_survey(),
list_surveys(), get_citation(), and
survey_countries() now warn unconditionally when called.
These functions were soft-deprecated in 0.5.0 and users should switch to
the contactsurveys
package (#269).
contact_matrix() now uses
assign_age_groups() internally, removing duplicated code
(#227).
contact_matrix() now uses weigh()
internally for all weighting (day-of-week, age, and user-defined). The
helpers warn_multiple_observations() and
normalise_weights() were extracted so
compute_matrix() can share them (#131).
The vignette and README are rewritten around the pipeline (#288).
Enabled cyclocomp_linter,
line_length_linter, and object_usage_linter.
Disabled indentation_linter (air handles indentation).
Reduced cyclomatic complexity of check.contact_survey(),
[.contact_survey(), find_unique_key(), and
try_merge_additional_files() by extracting helper functions
(#289).
This is a patch release with a bug fix and documentation updates.
load_survey() no longer fails when merging contact
files that lack a cont_id column (#278).
The vignette now points to the contactsurveys package for downloading surveys from Zenodo, and no longer uses deprecated functions (#269).
Added Nicholas Tierney (@njtierney) as package author (#277).
This release focuses on improved modularity and flexibility for contact matrix workflows. Key highlights include new standalone functions for age group assignment and population data retrieval, more intuitive handling of age limits, and the beginning of a transition to the contactsurveys package for survey downloads.
contact_matrix() now preserves all user-specified
age_limits, even when no participants exist in some age
groups. Previously, age groups beyond the maximum participant age were
silently dropped. Empty age groups now show 0 participants and NA values
in the matrix. This may change matrix dimensions for existing code
(@Bisaloo, #144,
#231).
contact_matrix(counts = TRUE)$matrix now returns an
array rather than an xtabs object. This matches the existing output
format of contact_matrix(counts = FALSE)$matrix (@Bisaloo, #118).
When age_limits is not specified, it is now inferred
from both participant and contact ages, not just participant ages. This
may result in more age groups if contacts include ages beyond the
participant age range (#230).
as_contact_survey() no longer requires
country and year columns. These columns are
now auto-detected if present, but surveys without them can be loaded
successfully (#193, #199).
New assign_age_groups() and
survey_country_population() functions allow modular
pre-processing of survey data (#131, #226).
Reduced verbosity by removing messages about removing participants/contacts with missing ages (#228).
clean() now correctly processes age values with
units (e.g., “6 months”, “52 weeks”) (@LloydChapman, #250, #256).
contact_matrix() now warns when a survey contains
multiple observations per participant, as results will aggregate across
all observations (#260).
load_survey() now correctly loads longitudinal
surveys with repeated observations per participant (e.g., sday files
with wave/studyDay columns). Previously, these columns were silently
dropped (@njtierney, #192, #194).
Fixed a bug leading to excess contacts with NA age
if the lowest age group did not start at 0 (@lwillem, #170).
Argument names with dots (e.g., age.limits) have
been deprecated in favour of underscores (e.g., age_limits)
in contact_matrix(), as_contact_survey(),
pop_age(), and clean(). The old argument names
still work but will produce deprecation warnings (#160).
get_survey(), download_survey(),
get_citation(), list_surveys(), and
survey_countries() have been soft-deprecated and moved to
contactsurveys.
This is part of decoupling these features from socialmixr to reduce
dependencies (@njtierney, #179, #207). These will
continue to work until version 1.0.0.
The missing_contact_age = "sample" option in
contact_matrix() and assign_age_groups() has
been soft-deprecated. Use "remove" to exclude contacts with
missing ages, "keep" to retain them as a separate age
group, or "ignore" to drop only those contacts
(#273).
limits_to_agegroups has been changed to return
bracket notated age ranges by defaultAn error in list_surveys() was fixed which stopped
this working.
contact_matrix() was updated to only accept
survey objects, not DOIs and matches the documentation. It
is still possible to get a contact matrix from a DOI but it is necessary
to go through the get_survey() function.
```r # No longer works! contact_matrix(“10.5281/zenodo.1095664”)
get_survey(“10.5281/zenodo.1095664”) |> contact_matrix()
The efficiency of the contact_matrix() was
improved.
cite function has been deprecated and replaced with
get_citation (#84).columns argument has been removed from
check.survey() (#81).download_survey() has been reduced by
externalising the find_common_prefix() function and failing
early instead of relying on unnecessary if/else sequenceserror argument has been removed from
check() and always return warnings. If you want to turn
these warnings into errors, please have a look at
options(warn = 2)quiet argument has been removed from
check(), cite(),
contact_matrix(), and get_survey(). If you
want to silence diagnostic messages, you should use R idiomatic
mechanisms, such as suppressMessages()n and bootstrap options of
contact_matrix() have been deprecated and replaced with a
sample.participants argument; bootstrapping is now
explained in the vignette insteadmatrix_plot() function to plot contact matrixchkDots() is now used to ensure no argument is silently
ignored by S3 methodsget_survey() has been split into separate functions for
downloading and processing survey datareduce_agegroups