| murmuration | R Documentation |
**Bird note**: A murmuration is one of nature's most arresting phenomena: tens
of thousands of starlings moving as a single fluid shape across the sky, with
no conductor and no central instruction — each bird responding only to its
nearest neighbours until a coherent, shifting pattern emerges from the whole
flock. murmuration() works the same way: it takes two separate,
uncoordinated datasets and lets pairwise local comparisons between records
resolve, through the Fellegi-Sunter EM algorithm, into one coherent linked
result. No single record "knows" about the others — the shape emerges from
the scoring.
Probabilistic record linkage of two surveillance datasets using the Fellegi-Sunter framework. Links diagnostic case linelists, hospital admission records, outbreak linelists, and event manifests to vaccination history (Australian Immunisation Register) or to each other. Wraps the full reclin2 pipeline — blocking, comparison, EM scoring, threshold selection, and post-linkage window filtering — in a single practitioner- facing call.
murmuration(
df1,
df2,
linkage_type = NULL,
event_type = NULL,
method = "probabilistic",
event_date = NULL,
id_var,
blocking_var,
compare_vars,
threshold_value = 17,
perch_before_linking = FALSE,
vax_window = list(days_before = 14, days_after = 0, lookback_days = Inf),
cohort_window = NULL,
days_allowed_before_event = 7,
days_allowed_after_event = 14,
one_row_per_person = TRUE,
clean_eggs = TRUE,
days_between_onset_death = 30,
last_follow_up = NULL
)
df1 |
This is a dataframe object, cleaned using clean_the_nest, and would often represent the base, or "x" dataset (when doing left joins). Typically this would be a dataset of cases, have enough data to create linkages, and have event dates (e.g., onset_date). |
df2 |
This is a dataframe object, cleaned using clean_the_nest, and would often represent the admissions or vaccination dataset ("y" dataset when doing left joins). Typically this would have enough data to create linkages, and include either admission data or vaccination event data (e.g. Australian Immunization Register). |
linkage_type |
The linkage to perform. As of starling 1.1.0 the preferred
value is Legacy codes (deprecated, still functional): the historical
|
event_type |
Required when |
method |
Linkage engine. |
event_date |
The anchor date used to define the linkage window and determine valid vaccinations or related admissions.
This parameter is critical for determining valid vaccinations (must occur before |
id_var |
Variable name (e.g. "id"). This is critical for data-linkage and the base dataset is the dataset you would left join onto (e.g. the "x" dataset). Cannot have missing data, or the observation will be lost in the linking process. |
blocking_var |
Variable name (e.g. "block2"). Choice of blocking variable.
Use |
compare_vars |
Vector of variables. Used to compare variables between each dataset and calculate the string score differences. Typically names, dates of births and medicare/social security numbers. |
threshold_value |
Numeric (e.g. 17), default is 17. This is the Fellegi-Sunter
log-likelihood ratio score above which a pair is classified as a match. The score is
dataset-specific — there is no universal correct value.
Use |
perch_before_linking |
Logical. If |
vax_window |
A named list defining the vaccination validity window relative
to
Example: Overridden by |
cohort_window |
An optional named list defining a calendar-based
observation window that replaces
When |
days_allowed_before_event |
Numeric. For |
days_allowed_after_event |
Numeric. For |
one_row_per_person |
Logical (TRUE or FALSE) with the default being TRUE. It will take multiple admissions per person, and create a series of variables prefixed with "first_", such as "first_admission_date", and put into a single row all admission events, and create a series of variables suffixed with "s", such as "admission_dates". Will work with single admissions per person. |
clean_eggs |
Logical (TRUE or FALSE) with the default being TRUE. Drops all the .y variables that are duplicates of the second dataset (df2), and keeps the variables and removes the .x from df1. If you leave this on, many, if not most variables will have ".x" or ".y" attached to them (e.g. gender) and thus keep this as TRUE for default, and FALSE if you want to check the linkages are true and working. |
days_between_onset_death |
Numeric (e.g. "30"). If you have put a date of death into the clean_the_nest command (which will rename it to dod), then the command will find disease related dates of death. This is chosen number of days between event_date and death for a disease-related death. Often this may be 30 days for SARS-CoV-2 or can be much longer for HIV. If you don't want an upper limit, use "9999". |
last_follow_up |
Represents a date (input as ymd(2024-11-22)) that represents last follow-up. This could be the latest admission date of a dataset. Used for calculating survival time. |
Make sure that you do not have the same variables (other than linkage
variables e.g. letternames, DOB, gender) in both datasets. Always make sure
your date columns are properly formatted using as.Date(). For example,
if both datasets have a date of death, choose the dataset with the highest
confidence and drop the date of death from the other before linking. If
linking to a hospitalisation dataset, the difference between
event_date and admission_date is used to identify
disease-related admissions; unrelated hospitalisations can be filtered
separately using ICD-10 codes or AR-DRG codes prior to linkage.
The recommended pre-linkage workflow is:
mudnester::clean_the_nest() to clean and prep data for linkage. Pay close attention to your linkage variables (letternames, date of birth, medicare number, gender and/or postcode), and ensure all dates are formatted as dates.
linkage_quality() to run a structured battery of pre-linkage quality checks across both datasets (completeness, duplicates, Medicare validity, date plausibility, gender and DOB year distribution).
check_medicare to validate Medicare check digits and flag invalid numbers before they enter comparison scoring.
flock() to create up to three blocking variables at different specificity levels (coarse, medium, fine) — pass one to the blocking_var argument below.
murmuration with linkage_type="v2c" to link cases to vaccination data.
murmuration with linkage_type="v2h" to link a v2c dataset to hospitalization data. Or skip linking to case data, and just build a v2h dataset for test-negative case-control studies.
murmuration with linkage_type="v2e" to link event linelists (flight manifests, outbreak investigations) to vaccination history.
murmuration_plot() to visualise the full linkage score distribution and confirm the threshold before accepting the linked dataset.
mudnester::preening() to prettify the dataframe prepping it for exploration, analysis and presentation. Great to use with gtsummary::tbl_summary().
## On threshold selection
The threshold_value is a Fellegi-Sunter log-likelihood ratio score and is
dataset-specific — there is no universal correct value. The default of 17 was
chosen empirically against SCPHU datasets with 4-5 comparison variables (names, DOB,
Medicare, gender). Use flock_plot() to inspect the bimodal score distribution
from your specific dataset and identify the natural valley between the match and
non-match peaks. Typical working ranges: conservative (high specificity) ~20-25;
balanced (default) ~15-20; sensitive (high recall) ~10-14.
A linked dataset with some new variables.
Ensure there are no missing vaccination dates in vaccination dataset prior to murmuration. Murmuration requires complete vaccination data (equal date and type columns per observation) to achieve correct matching of vaccination columns. If there are too few variables to match on, then matching will not work well. For example, if you have first name, last name and date of birth, and a very large dataset (Immunization Register), then the scoring will not differentiate true from false matches. Consider deterministic linkage when there is a paucity of information to use to derive linkage scores.
## Not run:
# Example 1: Link cases to vaccination history (onset_date as anchor)
dx_clean <- clean_the_nest(dx_data,
data_type = "cases",
id_var = "identity",
lettername1 = "first_name",
lettername2 = "surname",
dob = "date_of_birth",
gender = "gender",
postcode = "postcode",
medicare = "medicare_no",
diagnosis = "disease_name",
onset_date = "date_of_onset")
vax_clean <- clean_the_nest(vax_data,
data_type = "vaccination",
id_var = "patient_id",
lettername1 = "firstname",
lettername2 = "last_name",
dob = "birth_date",
gender = "gender",
postcode = "postcode",
medicare = "medicare_number",
vax_type = "vaccine_delivered",
vax_date = "service_date")
df1 <- murmuration(dx_clean, vax_clean,
linkage_type = "v2c",
event_date = "onset_date",
id_var = "identity",
blocking_var = "gender",
compare_vars = c("lettername1", "lettername2", "dob"),
clean_eggs = FALSE)
# Example 2: Link hospitalization data to vaccination history (admission_date as anchor)
hosp_clean <- clean_the_nest(hosp_data,
data_type = "hospital",
id_var = "patient_id",
lettername1 = "firstname",
lettername2 = "last_name",
dob = "birth_date",
gender = "sex",
postcode = "zip_codes",
medicare = "medicare_number",
admission_date = "date_of_admission",
discharge_date = "date_of_discharge")
df2 <- murmuration(hosp_clean, vax_clean,
linkage_type = "v2h",
event_date = "admission_date",
id_var = "patient_id",
blocking_var = "gender",
compare_vars = c("lettername1", "lettername2", "medicare10", "dob"),
clean_eggs = FALSE,
one_row_per_person = TRUE)
# Example 3: Link cases to hospitalisations (onset_date as anchor)
df3 <- murmuration(dx_clean, hosp_clean,
linkage_type = "c2h",
event_date = "onset_date",
id_var = "identity",
blocking_var = "postcode",
compare_vars = c("lettername1", "lettername2", "dob", "medicare10"),
days_allowed_before_event = 7,
days_allowed_after_event = 30,
clean_eggs = FALSE)
# Example 4: Birth-cohort study (e.g. RICOR nirsevimab) — cohort_window approach.
# Captures any vaccination administered during the defined follow-up period,
# regardless of individual event dates.
cohort_clean <- clean_the_nest(birth_cohort_data,
data_type = "cases",
id_var = "baby_id",
lettername1 = "first_name",
lettername2 = "last_name",
dob = "babys_date_of_birth",
gender = "sex")
df_cohort <- murmuration(cohort_clean, vax_clean,
linkage_type = "v2c",
event_date = "dob",
id_var = "baby_id",
blocking_var = "gender",
compare_vars = c("lettername1", "lettername2", "dob"),
cohort_window = list(
entry = as.Date("2023-01-01"),
exit = as.Date("2024-06-30")
),
clean_eggs = FALSE)
# Example 4b: Annual influenza VE study — 1-year lookback, 14-day buffer.
# Only vaccinations in the 12 months before onset, and >= 14 days before onset,
# are retained as valid prior exposure.
df_flu_ve <- murmuration(cases_clean, vax_clean,
linkage_type = "v2c",
event_date = "onset_date",
id_var = "identity",
blocking_var = "gender",
compare_vars = c("lettername1", "lettername2", "dob", "medicare10"),
vax_window = list(
days_before = 14,
days_after = 0,
lookback_days = 365
),
clean_eggs = FALSE)
# Example 4c: Post-diagnosis vaccination uptake study.
# Retains vaccinations up to 1 year AFTER diagnosis as well as valid prior doses.
# The vax_timing column flags each dose as "pre_event" or "post_event".
df_post_dx <- murmuration(cases_clean, vax_clean,
linkage_type = "v2c",
event_date = "onset_date",
id_var = "identity",
blocking_var = "gender",
compare_vars = c("lettername1", "lettername2", "dob", "medicare10"),
vax_window = list(
days_before = 14,
days_after = 365,
lookback_days = Inf
),
clean_eggs = FALSE)
# Example 5: Link flight manifest to vaccination history (fixed event Date object)
manifest_clean <- clean_the_nest(manifest_data,
data_type = "cases",
id_var = "passenger_id",
lettername1 = "first_name",
lettername2 = "surname",
dob = "date_of_birth",
gender = "gender")
df_flight <- murmuration(manifest_clean, vax_clean,
linkage_type = "v2e",
event_date = as.Date("2024-03-15"),
id_var = "passenger_id",
blocking_var = "gender",
compare_vars = c("lettername1", "lettername2", "dob"),
days_allowed_before_event = 14,
clean_eggs = FALSE)
# Example 6: Link outbreak linelist to vaccination history (fixed event Date object)
linelist_clean <- clean_the_nest(linelist_data,
data_type = "cases",
id_var = "case_id",
lettername1 = "first_name",
lettername2 = "surname",
dob = "date_of_birth",
gender = "gender",
postcode = "postcode",
medicare = "medicare_no",
onset_date = "onset_date")
df_outbreak <- murmuration(linelist_clean, vax_clean,
linkage_type = "v2e",
event_date = as.Date("2024-06-01"),
id_var = "case_id",
blocking_var = "postcode",
compare_vars = c("lettername1", "lettername2", "dob", "medicare10"),
days_allowed_before_event = 7,
clean_eggs = FALSE)
## End(Not run)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.