tidypptsda 把整个分析流程中的全部阈值都集中在 qc_config() 返回的一个对象里。各分析函数通过 qc 参数接收这个对象,结果中的 $settings 也会原样保存这份设置,方便复现。本文逐一说明全部 43 个参数;每一步用的是什么方法、方法出自哪里,见《计算方法说明》。

1. 基本用法

qc <- qc_config()                                 # 默认设置
qc <- qc_config(stage_range = c(30, 115))         # 覆盖个别参数
qc$stage_range
#> [1]  30 115
  • 参数必须带名字,例如 duration_max = 1800。没有提到的参数保持默认值。
  • 可选规则的默认值为 NULL,表示关闭;给它赋一个值就打开。默认打开的可选规则(如 smooth_r2_min),传 NULL 可以关掉。
  • 1.0.0 版起不再有预设(casey、national、legacy),qc_config("national") 会报错并提示改法。

查看全部参数:

qc_config()
#> 
#> ── QC settings ──
#> 
#> Station transfer
#>   misread_max_visits: 2
#>   max_gap_days: 3
#>   max_jump_kg: 10
#> Body weight records
#>   weight_range: 15, 150
#>   adapt_days: 7
#>   weight_track: TRUE
#>   track_tol: 0.08
#>   weight_outlier: rlm , loess
#>   outlier_combine: any
#>   rlm_cutoff: 0.5
#>   sd_max: 3
#>   loess_span: 0.75
#> Pig-level checks
#>   min_records: 20
#>   min_test_days: 35
#>   max_missing_rate: 0.3
#>   entry_weight_max: 65
#>   exit_weight_min: 85
#>   track_flag_share: 0.4
#>   smooth_r2_min: 0.99
#> Growth and ADG
#>   stage_range: 30, 120
#>   curve_model: poly2
#>   max_extrap_days: 30
#>   curve_extrap: start
#> Feeder errors
#>   fiv_range: -20, 2000
#>   fiv0_abs_max: 20
#>   duration_max: 3600
#>   speed_fiv_lo_max: 500
#>   speed_strict_max: 110
#>   speed_range: 2, 170
#>   idle_duration_max: 500
#>   trough_diff_range: -20, 1800
#>   max_unidentified_feed_kg: 90
#>   fiv_max_by_weight: NULL (off)
#> Daily feed intake
#>   dfi_range: 0, 6
#>   dfi_quantile: NULL (off)
#>   dfi_correct: lmm
#>   impute_method: loess_pop
#>   long_gap_days: 3
#> Confidence flags
#>   max_edge_extrap_days: 15
#>   min_coverage: 0.7
#>   bin_width: 10
#>   min_bin_coverage_kg: 6
#>   bin_fcr_limits: NULL (off)

参数检查

qc_config() 会逐项检查参数的类型和取值范围,也会检查参数之间是否矛盾,出错时立即报错并指出原因:

qc_config(duration = 1800)               # 参数名写错,会提示正确的名称
#> Error in `qc_config()`:
#> ! Unknown QC parameter: "duration".
#> ℹ did you mean "duration_max"?
qc_config(stage_range = c(10, 120))      # 计算区间超出了有效体重范围
#> Error in `qc_validate()`:
#> ! stage_range (10-120 kg) must lie inside weight_range (15-150 kg).
qc_config(entry_weight_max = 90)         # 进站体重上限不小于出栏体重下限
#> Error in `qc_validate()`:
#> ! entry_weight_max must be smaller than exit_weight_min.

需要同时满足的约束:

  • stage_range 必须落在 weight_range 之内;
  • entry_weight_max 必须小于 exit_weight_min;
  • outlier_combine = "majority" 时,weight_outlier 中至少要有两种方法。

2. 参数总览

分组 参数 默认值 作用于
跨站与测定中断 misread_max_visits、max_gap_days、max_jump_kg 2、3、10 prep_visits()、clean_weight()
体重记录 weight_range、adapt_days、weight_track、track_tol、weight_outlier、outlier_combine、rlm_cutoff、sd_max、loess_span 15–150、7、TRUE、0.08、rlm + loess、any、0.5、3、0.75 clean_weight()
个体判定 min_records、min_test_days、max_missing_rate、entry_weight_max、exit_weight_min、track_flag_share、smooth_r2_min 20、35、0.30、65、85、0.4、0.99 clean_weight()
生长曲线与体重填充 stage_range、curve_model、max_extrap_days、curve_extrap 30–120、poly2、30、start calc_adg()
采食错误 fiv_range、fiv0_abs_max、duration_max、speed_fiv_lo_max、speed_strict_max、speed_range、idle_duration_max、trough_diff_range、max_unidentified_feed_kg、fiv_max_by_weight −20–2000、20、3600、500、110、2–170、500、−20–1800、90、NULL flag_feed_errors()
日采食 dfi_range、dfi_quantile、dfi_correct、impute_method、long_gap_days 0–6、NULL、lmm、loess_pop、3 calc_adfi()
可信度 max_edge_extrap_days、min_coverage、bin_width、min_bin_coverage_kg、bin_fcr_limits 15、0.7、10、6、NULL calc_fcr()

stage_range 只是默认的分析区间,可以改成任意体重段,例如 qc_config(stage_range = c(40, 110))。所有用到区间的地方都会跟着变:区间的起止时间、要填充的日子、ADG 的回归、ADFI 计入哪些天、适应期的采食是否计入、10 kg 分段(从区间下限开始划分),以及图中的虚线。

单位约定:体重用 kg,单次访问的采食量和料槽重用 g,日采食量(dfi_range)用 kg,时间用秒(s)或天(d)。

3. 跨站与测定中断参数

一头猪出现在多个测定站,通常是猪真的被挪了位置:跑到另一栏后一直没被发现;被发现后放回原栏;或者因病隔离,治好后放错了栏,之后可能又调回原栏。这些记录都是真实的,属于同一头猪。读卡误读则不同:猪还在自己的站上连续采食,另一个站上零星冒出一两次它的记录。

所以 prep_visits() 把每头猪的访问按时间排好,切成”同一个站上的连续访问段”:

  • 只有 misread_max_visits 次(默认 2 次)以内的短段,判为误读。这几次访问保留为未识别访问(identified = FALSE),因为它们确实发生在那个料槽上,Casey 规则计算前后访问的料重差、时间差时要用到;
  • 其余各段都是这头猪真实的停留,全部保留。猪可以转任意多次,也可以转回原来的站(location_path 如 101>102>101);
  • 中间没有访问的空档(例如隔离治疗)不会把猪拆成两个个体,空档天数按缺失处理。

结果见 attr(visits, "stations")。

参数 含义 单位 默认值 取值范围
misread_max_visits 夹在另一站连续访问之间、不超过这么多次的连续访问判为误读,转为未识别访问 次 2 ≥ 0
max_gap_days 一头猪最长有多少天没有任何访问(无论在同一站还是两站之间)。超过时,clean_weight() 把它标为低可信度,原因写”测定中断”:病中和病后的生长、采食往往不代表这头猪的正常水平 天 3 ≥ 0
max_jump_kg 转栏前后体重差(取衔接处前后各 20 条有效体重的中位数,扣除空档期间按日增重应长的体重)超过此值时发出警告,并把猪标为低可信度,可能是耳标装错或放错了猪 kg 10 ≥ 0

调整建议

  • 示例数据中,每头猪最长的无访问时间不超过 2.2 天,所以默认的 3 天不会误标正常的猪。测定站故障停机几天时,这个站上所有的猪都会被标出,这时可以把 max_gap_days 临时调大。
  • 本包假设每个测定站在单独的栏里。如果一栏装有两台测定站、猪可以随意来回,同一天在两站都有大量访问是正常的,会被当成频繁转栏(转栏超过 3 次时会给出提示)。

4. 体重记录参数

这组参数作用于 clean_weight() 的前两层:单条记录规则和逐头猪的异常值检测。处理顺序是:体重范围 → 适应期 → 逐日回溯追踪 → weight_outlier 中的方法。

参数 含义 单位 默认值 取值范围
weight_range 单条体重的有效范围,超出的记录标记为 weight_range kg 15–150 两个递增的非负数
adapt_days 进站适应期:每头猪首次访问后这么多天内的体重不参与分析(qc_flag = "adaptation")。这几天的采食照常统计:若落在 stage_range 内(如 45 kg 进站、区间 30–120 kg),计入 ADFI 和 FCR;若还在区间下限以下,则不计入。设为 0 关闭 天 7 ≥ 0
weight_track 从测定末期逐日往回追踪体重,剔除与之不衔接的读数,见下文”逐日回溯追踪” — TRUE TRUE / FALSE
track_tol 追踪时读数与当天预测体重之差的容许比例(至少 2 kg;某天没有读数可保留时,每天再放宽 0.5 kg) — 0.08 0–1
weight_outlier 追踪之后,对剩下的记录再用哪些方法检测异常值,可多选:"rlm"、"loess"、"stl"、"sd" — c("rlm", "loess") 见下文
outlier_combine 多种方法的合并方式:"any" 表示任一方法判为异常即为异常;"majority" 表示超过半数方法判为异常才算 — "any" any / majority
rlm_cutoff rlm 法:稳健回归权重低于此值的记录判为异常 — 0.5 0–1
sd_max loess、stl、sd 法:残差超过多少倍标准差判为异常(loess 和 stl 用稳健标准差 MAD,sd 法用普通标准差) 倍 3 ≥ 0
loess_span LOESS 的平滑窗口占数据的比例,越大越平滑。也用于个体判定中的 LOESS 平滑曲线和采食插补 — 0.75 0.1–1

逐日回溯追踪

测定站只有猪四条腿都站上秤才称重,所以读数偏轻的情况很少。偏重的读数则很常见:进站初期猪小,测定站的挡板空隙即使调到最小,也能挤进去好几头小猪,读数是几头猪的体重之和或其中一部分。进站初期,这类读数往往占到一半左右,使日中位体重和拟合曲线整体偏高,看起来像”进站后长期不长”,算出的日增重偏低。到测定后期,猪大了,秤上只容得下一头,读数才准确。

所以 clean_weight() 在异常值检测之前,先从最可靠的测定末期往回追踪每头猪的体重:

  1. 起点:最后 3 个有记录日子的体重中位数;日增重取最后 14 天的稳健回归斜率;
  2. 逐日往前推:按当前日增重预测前一天的体重,只保留与预测值相差不超过 track_tol(至少 2 kg)的读数,其余剔除(qc_flag = "track");
  3. 日增重随时更新:用其后 10 天内已保留的日体重重新估计,所以进站初期长得慢、甚至停滞,也能跟得上;
  4. 某天没有读数可保留时,按预测值继续往前推,容差每天放宽 0.5 kg,不会跳到另一群读数上;
  5. 追踪保留下来的读数,再交给 weight_outlier 中的方法(默认 rlm 和 loess)复核,去掉追踪容差以内、但仍明显偏离曲线的零散读数。没有追踪的猪(有记录的日子少于 7 天、或测定期短于 14 天),以及设置 weight_track = FALSE 时,只用这些方法;
  6. 个体判定:追踪剔除的记录超过 track_flag_share(默认 40%)的猪,降级为 low_confidence,原因注明”可能是称重异常,如体重传感器故障”。例如一头猪在 50–100 kg 时仍长期出现两条相差约 20 kg 的平行体重带,这时秤上只容得下一头猪,只能是称重本身出了问题。

每头猪被追踪剔除的记录比例记录在 per_pig$track_removed 中。在示例数据上,去掉 7 天适应期之后,NEDAP 有 5% 的记录被追踪剔除,rlm 和 loess 又标出约 2%;FIRE 分别为 0.3% 和 2%。追踪之后再复核,对 ADG 的影响很小:与只追踪相比,平均差 1–2 g/d。

四种检测方法

方法 做法 适用情况
rlm(默认) 每头猪拟合二次稳健回归(MASS::rlm,bisquare 权重),权重小于 rlm_cutoff 的记录为异常。方法来自 Jiao 等(2014) 通用的方法;对成段的离群值很稳健
loess(默认) 每头猪拟合稳健 LOESS 平滑曲线(family = "symmetric"),偏离曲线超过 sd_max 倍 MAD 的记录为异常 能贴住不规则的生长(如中途停滞、生病),弥补二次曲线的不足
stl 对日中位体重做 STL 分解(周期 7 天,稳健模式),用”趋势 + 周期”作为参照;不足 14 天时改用 loess 怀疑存在周期性干扰时;生长曲线本身没有周期,效果通常与 loess 接近
sd 每头猪拟合二次最小二乘曲线,残差超过 sd_max 倍标准差为异常 传统做法;离群值多时,标准差会被拉大,检出率偏低

示例:rlm_cutoff 对异常值比例的影响

visits_n <- prep_visits(nedap, verbose = 0)
rbindlist(lapply(c(0.3, 0.5, 0.7), function(k) {
  w <- clean_weight(visits_n, qc_config(rlm_cutoff = k), verbose = 0)
  data.table(rlm_cutoff = k,
             outlier_pct = round(100 * mean(w$records$outlier), 2),
             pigs_removed = w$per_pig[status == "removed", .N])
}))
#>    rlm_cutoff outlier_pct pigs_removed
#>         <num>       <num>        <int>
#> 1:        0.3       17.22            1
#> 2:        0.5       18.01            1
#> 3:        0.7       21.66            1

rlm_cutoff 越大,判定越严格,被标为异常的记录越多。默认值 0.5 来自 Jiao 等(2014)。如果检查 w$records 后发现大量正常体重被标为异常,可以尝试调低到 0.3–0.4。

调整建议

  • 测定站的称量下限较高,或者小猪数据不可靠时,把 weight_range 的下限调高,例如 c(20, 150)。
  • 各方法的检出率和误删率可以用 validate_outliers() 在自己的数据上比较,见《方法验证》。

5. 个体判定参数

体重异常值剔除之后,clean_weight() 逐头猪判断能否用于生长分析。下表中前三个参数不满足时剔除该猪,后四个不满足时只降级为 low_confidence,该猪仍参与后续计算。

参数 含义 单位 默认值 不满足时
min_records 最少有效体重记录数 条 20 剔除
min_test_days 最短测定期:首条到末条有效体重之间的天数 天 35 剔除
max_missing_rate 最大缺失率:测定期内没有有效体重的天数占比 — 0.30 剔除
entry_weight_max 进站体重上限,取有效体重的 LOESS 平滑曲线在首条记录处的值 kg 65 降级
exit_weight_min 出栏体重下限,取 LOESS 平滑曲线在末条记录处的值 kg 85 降级
track_flag_share 逐日回溯追踪剔除的记录比例超过此值时降级(可能是称重异常,如体重传感器故障),见上文”逐日回溯追踪” — 0.4 降级
smooth_r2_min 有效体重对其 LOESS 平滑曲线的 R² 低于此值时降级;NULL 关闭 — 0.99 降级

进站和出栏体重不达标的猪只降级、不剔除,因为它们的 ADG 还可以在 calc_adg() 中靠生长曲线填充两端得到,并会带上相应的标记。

LOESS 平滑曲线的 R²:smooth_r2_min

LOESS 能贴住生长曲线的起伏,所以有效体重对它的 R² 反映的是读数本身的噪声,而不是生长是否”标准”。在示例数据和用户提供的 NEDAP 数据中,保留的猪 R² 都在 0.993 以上(中位数约 0.998),只有测定期 9 天的那头 FIRE 猪为 0.96。默认的 0.99 只会标出读数明显杂乱的猪。注意 R² 受体重跨度影响:测定期越短、跨度越小,R² 天然越低。

w_n <- clean_weight(prep_visits(nedap, verbose = 0), verbose = 0)
summary(w_n$per_pig$r2)
#>    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.     NAs 
#>  0.9946  0.9977  0.9983  0.9980  0.9986  0.9990       1

调整建议

  • min_test_days 应短于计划测定期:计划测 60 天的批次,设为 40–45 天比较合适。
  • 如果某批次有很多猪因 smooth_r2_min 被降级,先用 plot_adg(adg, weight = w) 看图:是秤的问题还是阈值太严。

6. 生长曲线与体重填充参数

作用于 calc_adg()。

参数 含义 单位 默认值 取值范围
stage_range 计算 ADG、ADFI、FCR 的体重区间 kg 30–120 必须落在 weight_range 之内
curve_model 生长曲线:"poly2"(二次)、"poly1"(直线)、"poly3"(三次)、"gompertz"。用来确定区间的起止时间,并填充首条记录之前、末条记录之后的体重 — "poly2" 见左
max_extrap_days 曲线在首条记录之前、末条记录之后最多外推的天数 天 30 ≥ 0
curve_extrap 记录范围之外怎么外推。"start":首条记录之前从曲线在首条记录处的值出发画直线,斜率取首 14 天记录的稳健回归斜率(限制在 0.2–1.5 kg/d),末条记录之后沿生长曲线;"tangent":两端都用直线;"curve":两端都沿生长曲线 — "start" start / curve / tangent

计算分三步:

  1. 区间的起止时间由生长曲线确定。终点:曲线第一次到达 stage_range 上限的时间;起点:在终点之前,曲线最后一次从下方越过下限的时间(前期数据波动使曲线先越过 30 kg、又掉回去时,起点取之后真正进入区间的那一次)。搜索范围是首条记录前、末条记录后各 max_extrap_days 天。
  2. 把区间内每一天的体重补齐:有有效体重的日子用当天中位数(source = "observed");两个有记录的日子之间缺失的日子,用前后两天线性插值("interpolated");首条记录之前、末条记录之后的日子,用生长曲线的值("curve")。结果在 adg$daily$weight_filled。
  3. 日增重 = 区间内全部日体重(实测 + 填充)对日期做直线回归的斜率(adg,g/d),可靠性看 r_squared。各来源的天数在 n_observed_days、n_interpolated_days、n_curve_days 中。

切线外推:二次、三次曲线往记录范围外推几周时容易弯折,例如末期增重稍慢时,曲线外推后会提前”封顶”。切线外推时,记录范围内仍用原来的曲线,范围之外改为直线。在 457 头 NEDAP 猪的无泄露检验中(《方法验证》中的 validate_truncation()),开头用切线使 ADG 误差在开头缺 20 天时从 81 降到 66 g/d、FCR 排名相关从 0.82 升到 0.86;末端用切线虽然 ADG 也更准,但末端的采食是按外推的体重填充的,FCR 排名反而变差(结尾缺 30 天时,前 20% 一致率从 0.70 降到 0.44)。所以默认 "start":只在首条记录之前用切线。示意图见《填充方法》。

adg_curve 是生长曲线在区间两端的体重差 ÷ 天数,只用来对照。r_squared 受体重跨度影响,只在同一批次、同一区间内比较才有意义。gompertz 用 nls(SSgompertz) 拟合,不收敛时自动改用二次曲线,实际使用的曲线记录在 curve_used 列中。

哪种曲线填充两端更准,可以用 validate_weight_fill() 在自己的数据上比较(见《方法验证》):

w_n <- clean_weight(prep_visits(nedap, verbose = 0), verbose = 0)
rbindlist(lapply(c("poly1", "poly2", "poly3", "gompertz"), function(m) {
  a <- calc_adg(w_n, qc = qc_config(curve_model = m), verbose = 0)$per_pig
  data.table(curve_model = m, mean_adg = round(mean(a$adg, na.rm = TRUE)),
             curve_days = sum(a$n_curve_days))
}))
#>    curve_model mean_adg curve_days
#>         <char>    <num>      <int>
#> 1:       poly1     1206         43
#> 2:       poly2     1205         37
#> 3:       poly3     1199         65
#> 4:    gompertz     1200         62

示例:stage_range 对 FIRE 数据的影响

FIRE 示例数据中的猪在 45–60 kg 才进站,若仍按 30–120 kg 计算,前段只能靠外推:

visits_f <- prep_visits(fire, verbose = 0)
rbindlist(lapply(list(c(30, 120), c(60, 120)), function(st) {
  q <- qc_config(stage_range = st)
  a <- calc_adg(clean_weight(visits_f, q, verbose = 0), verbose = 0)
  f <- calc_fcr(a, calc_adfi(visits_f, a, verbose = 0), verbose = 0)
  data.table(stage = paste(st, collapse = "-"),
             observed = a$per_pig[adg_type == "observed", .N],
             extrapolated = a$per_pig[adg_type == "extrapolated", .N],
             fcr_ok = f$per_pig[fcr_flag %in% "ok", .N],
             fcr_low = f$per_pig[fcr_flag %in% "low_confidence", .N])
}))
#>     stage observed extrapolated fcr_ok fcr_low
#>    <char>    <int>        <int>  <int>   <int>
#> 1: 30-120        0           24      3      22
#> 2: 60-120       13           12     21       4

调整建议:stage_range 的两端都应落在大多数猪的实测体重范围之内。区间下限宜比典型进站体重高 5–10 kg,上限宜比典型出栏体重低约 5 kg。

7. 采食错误参数(Casey 等,2005)

作用于 flag_feed_errors()。每次访问按 16 条规则逐条判断;以下参数是这些规则的阈值,默认值全部取自 Casey 等(2005)表 3。

参数 对应规则 含义 单位 默认值
fiv_range 1 FIV-lo、2 FIV-hi 单次采食量的合理范围,低于下限或高于上限判为错误 g −20、2000
fiv0_abs_max 3 FIV-0 停留时间为 0 秒的访问,采食量绝对值超过此值判为错误 g 20
duration_max 5 OTV-hi 单次访问停留时间的上限(规则 4 OTV-lo 固定为 < 0 秒) s 3600
speed_fiv_lo_max 6 FRV-hi-FIV-lo 0 < 采食量 < 50 g 的访问,采食速度超过此值判为错误 g/min 500
speed_strict_max 7 FRV-hi-strict 采食量 ≥ 50 g、且前一次或后一次访问采食量 < −20 g 的访问,采食速度上限 g/min 110
speed_range 10 FRV-lo、8 FRV-hi 下限:速度不为 0 但绝对值 ≤ 此值判为 FRV-lo;上限:采食量 ≥ 50 g 且前后访问都正常时的速度上限 g/min 2、170
idle_duration_max 9 FRV-0 采食速度为 0(没吃料)但停留时间超过此值,判为错误 s 500
trough_diff_range 11–14 LWD/FWD 相邻两次访问之间料槽重的变化范围(仅 FIRE) g −20、1800
max_unidentified_feed_kg 料槽级 单个料槽在整个测定期内”未识别访问”的耗料量超过此值时给出警告 kg 90
fiv_max_by_weight 2 FIV-hi 可选:按体重段(可再按品种)设定单次采食上限,代替 fiv_range 的上限 g NULL(关闭)

规则 15、16(LTD-lo、FTD-lo:相邻访问在时间上重叠)没有参数。“前一次 / 后一次访问”指同一料槽上按进站时间排序的相邻访问,包括未识别耳标的访问。

按体重和品种设定单次采食上限:fiv_max_by_weight

固定的 2000 g 上限对小猪偏宽、对大猪偏严:25 kg 的猪一次吃不了 2 kg,而 120 kg 的猪一次吃 2.2 kg 也属正常。fiv_max_by_weight 是一张表,每行给出一个体重段的上限:

  • weight_from:体重段的下限(kg),一行的上限对”体重 ≥ 该值、且小于下一行”的访问生效;
  • fiv_max:单次采食上限(g);
  • breed(可选):品种。有这一列时按品种查表,没有出现在表中的品种仍使用 2000 g;breed 为 NA 的行作为其他品种的默认值。

每次访问时猪的体重:在 calc_adfi() 中,自动使用 calc_adg() 补齐后的日体重(weight_filled);单独调用 flag_feed_errors() 时,可以用 bw 参数传入同样的日体重表,否则使用当天原始体重的中位数(测定初期常被异常值抬高,查到的体重段会偏重)。没有体重的日子用前后两天插值。未识别耳标的访问没有体重,仍使用 fiv_range 的上限。实际使用的上限保存在结果的 fiv_max 列中。

包里附带一张示例表 fiv_max_example(),来自测定站内部的质控脚本(不是文献值),包括 YY、LL、DD 三个品种和 20–140 kg 的体重段:

head(fiv_max_example(), 4)
#>     breed weight_from fiv_max
#>    <char>       <num>   <num>
#> 1:     YY          20   747.0
#> 2:     YY          30   936.0
#> 3:     YY          40  1125.1
#> 4:     YY          50  1314.1
tab <- data.frame(weight_from = seq(20, 130, 10),
                  fiv_max = fiv_max_example()[breed == "DD", fiv_max])     # 不分品种
visits_n <- prep_visits(nedap, verbose = 0)
adg_n <- calc_adg(clean_weight(visits_n, verbose = 0), verbose = 0)
bw_fit <- adg_n$daily[, .(responder, date, bw = weight_filled)]    # 补齐后的日体重
fixed <- flag_feed_errors(visits_n, verbose = 0)
raw_bw <- flag_feed_errors(visits_n, qc_config(fiv_max_by_weight = tab), verbose = 0)
fit_bw <- flag_feed_errors(visits_n, qc_config(fiv_max_by_weight = tab), bw = bw_fit, verbose = 0)
c(fixed_2000g = sum(fixed$fiv_hi), by_weight_raw_bw = sum(raw_bw$fiv_hi),
  by_weight_fitted_bw = sum(fit_bw$fiv_hi))
#>         fixed_2000g    by_weight_raw_bw by_weight_fitted_bw 
#>                   3                   1                   2

按品种使用时,先用 add_breed() 把品种列加进访问表(见《快速入门》)。

示例:duration_max 对 FIRE 错误率的影响

rbindlist(lapply(c(1800, 3600), function(d) {
  f <- flag_feed_errors(visits_f, qc_config(duration_max = d), verbose = 0)
  r <- attr(f, "error_rates")
  data.table(duration_max = d,
             otv_hi_pct = round(100 * r[error == "otv_hi", rate], 2),
             any_error_pct = round(100 * f[identified == TRUE, mean(n_errors > 0)], 2))
}))
#>    duration_max otv_hi_pct any_error_pct
#>           <num>      <num>         <num>
#> 1:         1800       5.56          7.57
#> 2:         3600       0.00          2.62

调整建议

  • trough_diff_range 的上限 1800 g 是按 FIRE 料槽的下料方式推算的(每次下料约 450 g,最多 4 次)。如果你的设备每次下料量不同,按”单次下料量 × 4”调整。
  • duration_max 设为 1800 s 时,FIRE 示例数据中有约 5.6% 的访问会被判为错误,而 3600 s 时几乎没有。改小之前,先确认你的猪确实不会单次采食半小时以上。
  • 其余阈值都是根据文献中的直方图定出来的,没有特别理由不建议改动。

8. 日采食参数

作用于 calc_adfi()。

参数 含义 单位 默认值 取值范围
dfi_range 校正后日采食量的合理范围,超出的日子视为缺失、交给插补 kg 0–6 两个递增的非负数
dfi_quantile 可选规则:按全部猪日的分位数截断,例如 c(0.025, 0.99) 表示低于 2.5% 分位或高于 99% 分位的日子视为缺失 — NULL(关闭) 0–1
dfi_correct "lmm":按 Jiao 等(2014)用混合模型校正;"none":不校正,直接用原始记录 — "lmm" lmm / none
impute_method 两个有记录的日子之间,连续缺失不超过 long_gap_days 天时用 LOESS 平滑插补("loess_pop"、"loess_lm")。"loess_pop":更长的缺失和首个有记录日之前用全群(有品种时按品种)“日采食 ~ 体重”二次曲线 × 这头猪的采食水平,末个有记录日之后用这头猪自己的”日采食 ~ 体重”线性回归;"loess_lm":这些位置都用这头猪自己的回归;"linear":中间一律线性插值,两端用这头猪自己的回归 — "loess_pop" loess_pop / loess_lm / linear
long_gap_days 区分短缺失和长缺失的天数 天 3 ≥ 1

回归中的体重是 calc_adg() 补齐后的日体重(weight_filled)。校正模型的形式是 无错误日采食 ~ 站 + 品种 + 当天体重 + ADG + 31 个错误协变量 + (1|猪)(品种只在数据中有 breed 列、且不止一个品种时加入),校正值 = 无错误日采食 − Σ(系数 × 错误协变量)。没有错误的日子不受影响。

调整建议

  • 公猪后期日采食量可能超过 4 kg,dfi_range 的上限不宜低于 5 kg。
  • 三种插补方法在随机缺失时结果几乎相同,差别主要在区间开头和成段缺失:开头缺 20 天时,loess_pop 的 ADFI 误差比 loess_lm 小约三分之一(457 头猪的无泄露检验:7.5% → 4.9%);末端两者相同。比较整条流程时请用 validate_truncation();validate_adfi() 只看插补这一步(见《方法验证》)。
  • loess_pop 的群体曲线来自本批次的猪,批次里的猪太少(少于约 10 头)或体重跨度太窄时,曲线不可靠,可以改用 loess_lm。各曲线的猪数、天数和系数见 adfi$pop_curve。

9. 可信度参数

作用于 calc_fcr(),决定 fcr_flag 是 "ok" 还是 "low_confidence"。

参数 含义 单位 默认值 取值范围
max_edge_extrap_days 区间开头或结尾,生长曲线或采食量连续外推超过此天数时降级 天 15 ≥ 0
min_coverage 区间内有实测(或校正)采食的天数占比低于此值时降级 — 0.7 0–1
bin_width 分段检查的体重段宽度 kg 10 ≥ 1
min_bin_coverage_kg 中间体重段内,实测体重覆盖的范围小于此值时降级 kg 6 0 至 bin_width
bin_fcr_limits 可选:每个体重段料肉比的合理范围,超出时降级 — NULL(关闭) 表:weight_from、fcr_min、fcr_max

示例:max_edge_extrap_days 对可信个体数的影响

rbindlist(lapply(c(10, 15, 30), function(k) {
  q <- qc_config(max_edge_extrap_days = k)
  a <- calc_adg(clean_weight(visits_f, q, verbose = 0), verbose = 0)
  f <- calc_fcr(a, calc_adfi(visits_f, a, verbose = 0), verbose = 0)
  data.table(max_edge_extrap_days = k, fcr_ok = f$per_pig[fcr_flag %in% "ok", .N])
}))
#>    max_edge_extrap_days fcr_ok
#>                   <num>  <int>
#> 1:                   10      0
#> 2:                   15      3
#> 3:                   30     20

缺失模拟显示:区间两端缺 10 天以内时,ADFI 误差约 2–4%;缺 20 天时约 7%;缺 30 天时为 9–14%。默认的 15 天是在”保留更多个体”和”保证精度”之间的折中。育种评估要求更高时可设为 10,只做描述性统计时可放宽到 20。

分段检查:$by_bin

calc_fcr() 把计算区间按 bin_width(默认 10 kg)分段,对每头猪的每一段计算采食量、增重和分段料肉比,结果保存在 $by_bin 中。每天归入哪一段、每段增重多少,都按生长曲线上的体重计算:每天的实测体重有波动,段边界附近的日子会被随机分到相邻的段,使段内体重的极差偏大。有两项检查:

  1. 体重记录是否断档:对首尾段之间的中间段,如果实测体重覆盖的范围小于 min_bin_coverage_kg(默认 6 kg),说明这一段体重记录不足,例如耳标脱落、不会进站或设备故障,该猪降级。首尾段不做这项检查,它们由 max_edge_extrap_days 管理。
  2. 分段料肉比是否合理(可选):设置 bin_fcr_limits 后,分段料肉比超出范围的段会被标出,该猪降级。包里附带的示例表 bin_fcr_example() 同样来自测定站内部脚本,不是文献值。
res_n <- run_pipeline(nedap, qc = qc_config(bin_fcr_limits = bin_fcr_example()), verbose = 0)
b <- res_n$fcr$by_bin
c(segments = nrow(b), low_coverage = sum(b$low_coverage), fcr_outside = sum(b$fcr_out))
#>     segments low_coverage  fcr_outside 
#>          258            5            1
b[fcr_out == TRUE, .(responder, weight_from, weight_to, fcr = round(fcr, 2), fcr_min, fcr_max)]
#> Key: <responder>
#>    responder weight_from weight_to   fcr fcr_min fcr_max
#>       <char>       <num>     <num> <num>   <num>   <num>
#> 1:     15967          60        70  3.59    1.28    3.41

在示例数据中,分段料肉比超出范围的只有 15967 号的 50–70 kg 段。这头猪在 4 月下旬采食骤降、体重停止增长,很可能生过病,分段检查正好把它找了出来。

10. 常用设置示例

# 晚进站批次(45–60 kg 进站)
qc_config(stage_range = c(60, 120))

# 115 kg 左右出栏
qc_config(stage_range = c(30, 110))

# 测定期较短的批次(计划 50 天)
qc_config(min_test_days = 30)

# FIRE 设备,下料量 600 g/次
qc_config(trough_diff_range = c(-20, 2400))

# 单次采食上限随体重变化,并检查分段料肉比
qc_config(fiv_max_by_weight = fiv_max_example(), bin_fcr_limits = bin_fcr_example())

# 两端用直线填充体重,采食中间用线性插值
qc_config(curve_model = "poly1", impute_method = "linear")

# 更宽松的体重清洗:两种方法都判为异常才算异常值
qc_config(weight_outlier = c("rlm", "loess"), outlier_combine = "majority")

参考文献

  • Casey, D. S., Stern, H. S., & Dekkers, J. C. M. (2005). Identification of errors and factors associated with errors in data from electronic swine feeders. Journal of Animal Science, 83, 969-982.
  • Jiao, S., Maltecca, C., Gray, K. A., & Cassady, J. P. (2014). Feed intake, average daily gain, feed efficiency, and real-time ultrasound traits in Duroc pigs: I. Journal of Animal Science, 92, 2377-2386.