Getting started with HLCtools

Overview

HLCtools calculates Herd Lying Concordance (HLC) metrics from individual animal lying-behaviour data.

HLC is a framework for quantifying group-level behavioural cohesion. Instead of classifying an interval as synchronous using a fixed threshold, HLC uses the distribution of individual animal lying behaviour within each interval.

The package currently supports four HLC implementations:

  • HLC_SD: standard-deviation-based HLC
  • HLC_MAD: mean-absolute-deviation-based HLC
  • HLC_IQR: interquartile-range-based HLC
  • HLC_ENT: entropy-based HLC

The package also calculates lying-weighted HLC, which combines group cohesion with the proportion of the interval spent lying.

Load package and example data

library(HLCtools)

data(example_lies)

example_lies
#>    group day week  time  cow lying
#> 1      A   1    1 00:00 cow1    15
#> 2      A   1    1 00:15 cow2    15
#> 3      A   1    1 00:00 cow3    15
#> 4      A   1    1 00:15 cow4    15
#> 5      A   1    1 00:00 cow5    15
#> 6      A   1    1 00:15 cow1     0
#> 7      A   1    1 00:00 cow2     0
#> 8      A   1    1 00:15 cow3     0
#> 9      A   1    1 00:00 cow4     0
#> 10     A   1    1 00:15 cow5     0
#> 11     A   2    1 00:00 cow1    15
#> 12     A   2    1 00:15 cow2    15
#> 13     A   2    1 00:00 cow3    15
#> 14     A   2    1 00:15 cow4     0
#> 15     A   2    1 00:00 cow5     0
#> 16     A   2    1 00:15 cow1    15
#> 17     A   2    1 00:00 cow2     0
#> 18     A   2    1 00:15 cow3    15
#> 19     A   2    1 00:00 cow4     0
#> 20     A   2    1 00:15 cow5    15
#> 21     B   1    1 00:00 cow1    15
#> 22     B   1    1 00:15 cow2    15
#> 23     B   1    1 00:00 cow3    10
#> 24     B   1    1 00:15 cow4    10
#> 25     B   1    1 00:00 cow5    15
#> 26     B   1    1 00:15 cow1    15
#> 27     B   1    1 00:00 cow2    12
#> 28     B   1    1 00:15 cow3    15
#> 29     B   1    1 00:00 cow4     8
#> 30     B   1    1 00:15 cow5    15
#> 31     B   2    1 00:00 cow1     0
#> 32     B   2    1 00:15 cow2     0
#> 33     B   2    1 00:00 cow3     5
#> 34     B   2    1 00:15 cow4     0
#> 35     B   2    1 00:00 cow5     0
#> 36     B   2    1 00:15 cow1     0
#> 37     B   2    1 00:00 cow2    15
#> 38     B   2    1 00:15 cow3     0
#> 39     B   2    1 00:00 cow4    15
#> 40     B   2    1 00:15 cow5     0

Required data format

The input data should contain one row per animal per time interval.

At minimum, the data should contain:

  • a group identifier;
  • an animal identifier;
  • a time interval identifier;
  • lying time within the interval.

Optional but usually useful columns include:

  • day or date;
  • week or experimental period.

In example_lies, the relevant columns are:

str(example_lies)
#> 'data.frame':    40 obs. of  6 variables:
#>  $ group: chr  "A" "A" "A" "A" ...
#>  $ day  : int  1 1 1 1 1 1 1 1 1 1 ...
#>  $ week : num  1 1 1 1 1 1 1 1 1 1 ...
#>  $ time : chr  "00:00" "00:15" "00:00" "00:15" ...
#>  $ cow  : chr  "cow1" "cow2" "cow3" "cow4" ...
#>  $ lying: num  15 15 15 15 15 0 0 0 0 0 ...

Calculate interval-level HLC

hlc_intervals <- calculate_hlc(
  data = example_lies,
  group = group,
  animal = cow,
  day = day,
  period = week,
  interval = time,
  lying = lying,
  interval_min = 15,
  methods = c("sd", "mad", "iqr", "entropy"),
  sync_thresholds = c(0.6, 0.7, 0.8, 0.9),
  add_lying_weighted = TRUE
)

hlc_intervals
#> # A tibble: 8 × 24
#>   group   day  week time  n_animals mean_lying lying_prop sd_lying mad_lying
#>   <chr> <int> <dbl> <chr>     <int>      <dbl>      <dbl>    <dbl>     <dbl>
#> 1 A         1     1 00:00         5          9      0.6       7.35       7.2
#> 2 A         1     1 00:15         5          6      0.4       7.35       7.2
#> 3 A         2     1 00:00         5          6      0.4       7.35       7.2
#> 4 A         2     1 00:15         5         12      0.8       6          4.8
#> 5 B         1     1 00:00         5         12      0.8       2.76       2.4
#> 6 B         1     1 00:15         5         14      0.933     2          1.6
#> 7 B         2     1 00:00         5          7      0.467     6.78       6.4
#> 8 B         2     1 00:15         5          0      0         0          0  
#> # ℹ 15 more variables: iqr_lying <dbl>, p_lying <dbl>, HLC_SD <dbl>,
#> #   HLC_MAD <dbl>, HLC_IQR <dbl>, entropy_raw <dbl>, HLC_ENT <dbl>,
#> #   sync60 <int>, sync70 <int>, sync80 <int>, sync90 <int>, HLC_SD_LYING <dbl>,
#> #   HLC_MAD_LYING <dbl>, HLC_IQR_LYING <dbl>, HLC_ENT_LYING <dbl>

The output contains one row per group-time interval.

Important columns include:

  • mean_lying: mean lying minutes in the interval;
  • lying_prop: mean lying proportion in the interval;
  • HLC_SD, HLC_MAD, HLC_IQR, HLC_ENT: unweighted HLC metrics;
  • HLC_SD_LYING, HLC_MAD_LYING, HLC_IQR_LYING, HLC_ENT_LYING: lying-weighted HLC metrics;
  • sync60, sync70, sync80, sync90: threshold synchrony indicators.

Summarise HLC by day

hlc_daily <- summarise_hlc_daily(
  data = hlc_intervals,
  group = group,
  day = day,
  period = week,
  interval_min = 15
)

hlc_daily
#> # A tibble: 4 × 19
#>   group   day  week mean_HLC_SD mean_HLC_MAD mean_HLC_IQR mean_HLC_ENT
#>   <chr> <int> <dbl>       <dbl>        <dbl>        <dbl>        <dbl>
#> 1 A         1     1      0.0202       0.0400        0           0.0290
#> 2 A         2     1      0.110        0.2           0.5         0.154 
#> 3 B         1     1      0.683        0.733         0.833       1     
#> 4 B         2     1      0.548        0.573         0.5         0.515 
#> # ℹ 12 more variables: mean_HLC_SD_LYING <dbl>, mean_HLC_MAD_LYING <dbl>,
#> #   mean_HLC_IQR_LYING <dbl>, mean_HLC_ENT_LYING <dbl>, sync60_time_min <dbl>,
#> #   sync70_time_min <dbl>, sync80_time_min <dbl>, sync90_time_min <dbl>,
#> #   mean_lying_min_interval <dbl>, mean_lying_prop <dbl>, n_intervals <int>,
#> #   mean_n_animals <dbl>

The daily summary contains one row per group-day.

Daily HLC columns are means of interval-level HLC values. Synchrony threshold columns are summarised as minutes per day.

Rank HLC methods for a dataset

Different experiments may favour different HLC implementations. For example, one dataset may favour SD-based HLC, whereas another may favour MAD-, IQR-, or entropy-based HLC.

rank_hlc_methods() provides a descriptive ranking of available HLC implementations.

rank_hlc_methods(
  data = hlc_daily,
  group = group,
  period = week,
  lying_prop = mean_lying_prop
)
#>    method metric_column n_total n_non_missing pct_missing      mean        sd
#> 1  HLC_SD   mean_HLC_SD       4             4           0 0.3402575 0.3244934
#> 2 HLC_MAD  mean_HLC_MAD       4             4           0 0.3866667 0.3214781
#> 3 HLC_ENT  mean_HLC_ENT       4             4           0 0.4242837 0.4355433
#> 4 HLC_IQR  mean_HLC_IQR       4             4           0 0.4583333 0.3435921
#>      median        min       max n_unique pct_boundary zero_variance
#> 1 0.3289734 0.02020410 0.6828793        4            0         FALSE
#> 2 0.3866667 0.04000000 0.7333333        4            0         FALSE
#> 3 0.3340427 0.02904941 1.0000000        4           25         FALSE
#> 4 0.5000000 0.00000000 0.8333333        3           25         FALSE
#>   high_boundary_collapse degeneracy_score detectability_F detectability_p
#> 1                  FALSE                0       46.014560      0.02104854
#> 2                  FALSE                0       22.222222      0.04217371
#> 3                  FALSE                0        7.062389      0.11721597
#> 4                  FALSE                0        1.923077      0.29985996
#>    delta_AIC temporal_sd outlier_sensitivity outlier_distance_from_1
#> 1 10.7134285         NaN           0.8296094               0.1703906
#> 2  7.9764932         NaN           0.8131274               0.1868726
#> 3  4.0439423         NaN           1.2102363               0.2102363
#> 4  0.6949164         NaN           1.3904983               0.3904983
#>   lying_prop_spearman rank_detectability rank_temporal_stability
#> 1           0.4000000                  1                      NA
#> 2           0.4000000                  2                      NA
#> 3           0.4000000                  3                      NA
#> 4           0.6324555                  4                      NA
#>   rank_outlier_robustness rank_boundary rank_missingness rank_degeneracy
#> 1                       1           1.5              2.5             2.5
#> 2                       2           1.5              2.5             2.5
#> 3                       3           3.5              2.5             2.5
#> 4                       4           3.5              2.5             2.5
#>   n_ranked_criteria weighted_rank_score selected
#> 1                 5                 1.7     TRUE
#> 2                 5                 2.1    FALSE
#> 3                 5                 2.9    FALSE
#> 4                 5                 3.3    FALSE
#>                         recommendation_note
#> 1 Selected/ranked under available criteria.
#> 2 Selected/ranked under available criteria.
#> 3 Selected/ranked under available criteria.
#> 4 Selected/ranked under available criteria.

The ranking does not prove that one method is universally best. It provides a transparent dataset-specific summary to support method selection.

Interpretation

Unweighted HLC describes group-level behavioural cohesion.

A high unweighted HLC value means that animals behaved similarly within the interval. This can occur when animals are uniformly lying or uniformly standing.

Lying-weighted HLC describes cohesive lying specifically.

A high lying-weighted HLC value means that animals were both behaviourally cohesive and lying.

Using HLC and lying-weighted HLC together

The two metrics can be interpreted together:

  • high HLC and high lying-weighted HLC: cohesive collective lying;
  • high HLC and low lying-weighted HLC: cohesive behaviour, but not mainly lying;
  • low HLC: fragmented group behaviour.

Available HLC methods

hlc_methods()
#> [1] "sd"      "mad"     "iqr"     "entropy"

Notes on method choice

HLCtools does not assume that one dispersion basis is universally best.

The choice of SD, MAD, IQR, entropy, or another implementation should depend on:

  • the biological question;
  • group size;
  • sampling interval;
  • behaviour type;
  • data quality;
  • intended monitoring application.

Researchers are encouraged to calculate multiple HLC variants and report the dispersion basis used.

Citation

If you use HLCtools, please cite the package:

citation("HLCtools")
#> To cite package 'HLCtools' in publications use:
#> 
#>   Amorim Franchi G (2026). _HLCtools: Calculate Herd Lying Concordance
#>   Metrics_. R package version 0.1.0. Developed at Aarhus University.,
#>   <https://github.com/guilhermefranchi/HLCtools>.
#> 
#> A BibTeX entry for LaTeX users is
#> 
#>   @Manual{,
#>     title = {HLCtools: Calculate Herd Lying Concordance Metrics},
#>     author = {Guilherme {Amorim Franchi}},
#>     year = {2026},
#>     note = {R package version 0.1.0. Developed at Aarhus University.},
#>     institution = {Aarhus University},
#>     url = {https://github.com/guilhermefranchi/HLCtools},
#>   }

HLCtools was developed at Aarhus University as research software for calculating Herd Lying Concordance metrics from individual animal lying-behaviour data.