read_station()read export files
→
prep_visits()standard visit table
→
clean_weight()weight QC
→
calc_adg()fill weights + ADG
→
calc_adfi()correct, fill feed
→
calc_fcr()FCR + confidence
→
plot_* / write_results() / write_report()plots, export, HTML report
All in one: run_pipeline(); all thresholds: qc_config()
Install and run everything
# install.packages("pak")
pak::pak("tony2015116/tidypptsda")
library(tidypptsda)
raw <- read_station("export/", station = "nedap")
res <- run_pipeline(raw) # or run_pipeline(nedap)
res$fcr$per_pig # final results
res$removed # removed pigs, with reasons
write_results(res, dir = "results", farm = "A01")
write_report(res, "results/report") # HTML: a page per station, arrow keys
Example data: nedap, fire (raw station exports).
Read data read_station() / station_format()
# a whole folder; without station the type is detected
read_station("export/", station = "nedap")
read_station(c("101.xlsx", "102.xlsx"), station = "fire")
# other column names: write a template, edit column
station_format("fire", file = "fire_format.txt")
read_station("export/", station = "fire",
format = "fire_format.txt")
- CSV, TXT (separator detected) and Excel (needs readxl).
- No format file is needed when the columns match the built-in format; otherwise an error lists the missing columns.
- Format file, one line per field:
field, column (name or position; Date,Entry joins two columns; - if absent), unit (kg / g / auto, s / min).
- Result is one standard table: IDs and stations as text; times as POSIXct; feed and trough weights in g, body weight in kg, duration in s.
| Type | Required fields |
| NEDAP | responder, location, entry_time, feed_intake, weight |
| FIRE | same + exit_time, trough_in, trough_out |
Visits and breed prep_visits() / add_breed()
visits <- prep_visits(raw)
visits <- add_breed(visits, read.csv("breeds.csv"),
id = "tag", breed = "breed")
- Visits of unidentified transponders are kept as
identified = FALSE (needed for the feeder error rules).
- Pigs at several stations: all stays kept (also back to a former station); runs of ≤ 2 visits inside another station's visits are misreads, kept as unidentified; gaps > 3 d or weight jumps > 10 kg flag the pig. See
attr(visits, "stations").
- With a breed column, the correction model gets a breed effect and
fcr$summary is split by breed.
QC settings qc_config()
qc <- qc_config(stage_range = c(60, 120),
curve_model = "poly1")
qc # all 43 parameters, by group
run_pipeline(raw, qc = qc)
| Parameter | Default | Meaning |
stage_range | 30–120 | weight stage of ADG / ADFI / FCR |
weight_range | 15–150 | valid single weight |
adapt_days | 7 | adaptation after entry, weights unused |
weight_outlier | rlm, loess | outlier methods after tracking |
min_test_days | 35 | shortest test (removes) |
curve_model | poly2 | curve that fills the stage ends |
impute_method | loess_pop | feed filling: population curve × pig level; or loess_lm, linear |
curve_extrap | start | beyond the records: tangent at the start, curve at the end; or curve, tangent |
max_edge_extrap_days | 15 | more filling at the ends: low confidence |
duration_max | 3600 | longest visit (s) |
Misspelt names get a suggestion; $settings of every result keeps the settings used.
Weight cleaning clean_weight()
In order: weight range → adaptation → tracking back from the end of the test (keep readings that connect) → quadratic robust regression rlm (weight < 0.5) + LOESS (> 3 MAD off).
qc_flag | Meaning |
"" | valid |
weight_range | outside 15–150 kg |
adaptation | first 7 days after entry |
track | does not connect (mostly small pigs on the scale together) |
rlm / loess | flagged by that method |
status | When |
| removed | < 20 valid weights, test < 35 d, > 30% days missing |
| low_confidence | entry > 65 kg, exit < 85 kg, tracking removed > 40%, LOESS R² < 0.99 |
| keep | passed |
Results: w$per_pig (per pig), w$records (per record).
Daily gain calc_adg()
- The growth curve sets the stage: end = first time at the upper limit, start = last rise through the lower limit before it.
- Every stage day gets a weight,
weight_filled:
source | From |
observed | median of the day's valid weights |
interpolated | between recorded days: linear interpolation |
curve | before the first record: tangent; after the last: growth curve (curve_extrap) |
3. ADG = slope of the daily weights on the day over the stage (g/d), with r_squared.
adg_type | Meaning |
observed | both stage limits inside the test |
extrapolated | extrapolated, at most 30 days |
partial | a limit is never reached: covered part only |
none | less than 7 days covered, no ADG |
Feed intake flag_feed_errors() / calc_adfi()
- Errors: the 16 rules of Casey et al. (2005) (feed per visit, duration, feeding rate, trough weight differences…); run inside
calc_adfi().
- Correction: mixed model of Jiao et al. (2014), removes the effect of the error covariates; days without errors unchanged.
- Filling: on the ADG stage days only, with the filled daily weights. Long gaps and the stage start: population (or breed) curve of intake on body weight × the pig's intake level (
adfi$pop_curve); the stage end: the pig's own regression on weight.
state | The day's intake is |
org | recorded, no error visit that day |
corr | corrected by the model |
iii | gap between records: ≤ 3 d LOESS, > 3 d population curve × pig level |
elrp | stage start: population curve × pig level; stage end: the pig's own regression |
missing | cannot be estimated |
ADFI = mean daily intake over the stage; coverage = share of days recorded (incl. corrected).
Feed conversion calc_fcr()
FCR = ADFI ÷ ADG, gf = ADG ÷ ADFI. fcr_flag is ok or low_confidence; why is in fcr_note:
- weights or feed filled for more than 15 days at a stage end;
- feed recorded on less than 70% of the stage;
- an inner 10 kg class covered by less than 6 kg of recorded weights;
- ADG on part of the stage, or weight data flagged;
- optional: class FCR outside
bin_fcr_limits.
Per class: fcr$by_bin; summary: fcr$summary (all / ok / per breed). For breeding values prefer pigs with fcr_flag == "ok".
Growth plot plot_adg(adg, weight = w)
| light grey dots | valid raw weight records |
| ×dark grey crosses | removed records (see qc_flag) |
| blue | observed daily weight |
| orange | interpolated daily weight |
| reddish purple | daily weight from the growth curve |
| green line + band | growth curve, about 95% range |
| black long dashes | ADG regression line (slope = ADG) |
| grey horizontal dashes | stage limits |
Feed intake plot plot_adfi(adfi)
| light grey | recorded daily intake (uncorrected) |
| blue | error-free, used as recorded (org) |
| orange | corrected (corr) |
| green | filled between records (iii) |
| reddish purple | filled at the stage ends (elrp) |
| grey horizontal dashes | the pig's ADFI |
g <- plot_adg(res$adg, weight = res$weight,
locations = "101")
g$plot[[1]] # first station
h <- plot_adfi(res$adfi)
save_plots(g, "plots", suffix = "growth")
Export write_results()
Files are farm_table_date.csv, UTF-8 with BOM (opens in Excel without garbled Chinese).
| File | Content |
fcr | ADG, ADFI, FCR and flags per pig |
by_bin | feed, gain, FCR per weight class |
daily_weight | daily weights (observed, filled, curve) |
daily_feed | daily intake (recorded, corrected, filled) |
weight_pigs | weight QC per pig |
feed_model / summary | correction model / trait summary |
removed / settings | removed pigs and reasons / settings used |
Validation test the methods on your data
| Function | Tests |
validate_outliers() | artificial errors: detection, false removals and ADG error of outlier methods; clean records by consensus |
validate_adg() | growth curves: blocked cross-validation (block_days) and truncation (late entry, early exit); extrap compares curve and tangent |
validate_weight_fill() | hide daily weights: linear interpolation vs each curve |
validate_adfi() | hide daily intake: loess_pop vs loess_lm vs linear; with weight the body weight is computed again |
validate_truncation() | whole pipeline: drop all visits of some pigs, rerun, compare ADG / ADFI / FCR of several settings (no leakage) |
vw <- validate_weight_fill(w, max_pigs = 300, cores = 4)
vw$summary
# scenarios: random30 / blocks3 / late20 / early15
# hidden days are removed before cleaning (no leakage, 1.5.0)
vf <- validate_adfi(f, weight = w)
Common settings
# late entry (45-60 kg)
qc_config(stage_range = c(60, 120), curve_model = "poly1")
# slaughter at about 115 kg
qc_config(stage_range = c(30, 110))
# planned test of 50 days
qc_config(min_test_days = 30)
# FIV limit by body weight + class FCR check
qc_config(fiv_max_by_weight = fiv_max_example(),
bin_fcr_limits = bin_fcr_example())
# thousands of pigs: parallel
run_pipeline(raw, cores = 4)
# one station, a few pigs
plot_adg(res$adg, locations = "101", responders = c("13913"))
- Lower stage limit 5–10 kg above typical entry weight, upper limit about 5 kg below typical exit weight.
- Keep one set of settings for a breeding herd, so that years stay comparable.