tidypptsda 把整个分析流程中的全部阈值都集中在
qc_config() 返回的一个对象里。各分析函数通过
qc 参数接收这个对象,结果中的 $settings
也会原样保存这份设置,方便复现。本文逐一说明全部 43
个参数;每一步用的是什么方法、方法出自哪里,见《计算方法说明》。
qc <- qc_config() # 默认设置
qc <- qc_config(stage_range = c(30, 115)) # 覆盖个别参数
qc$stage_range
#> [1] 30 115duration_max = 1800。没有提到的参数保持默认值。NULL,表示关闭;给它赋一个值就打开。默认打开的可选规则(如
smooth_r2_min),传 NULL 可以关掉。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 中至少要有两种方法。| 分组 | 参数 | 默认值 | 作用于 |
|---|---|---|---|
| 跨站与测定中断 |
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)。
一头猪出现在多个测定站,通常是猪真的被挪了位置:跑到另一栏后一直没被发现;被发现后放回原栏;或者因病隔离,治好后放错了栏,之后可能又调回原栏。这些记录都是真实的,属于同一头猪。读卡误读则不同:猪还在自己的站上连续采食,另一个站上零星冒出一两次它的记录。
所以 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 |
调整建议
max_gap_days 临时调大。这组参数作用于 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()
在异常值检测之前,先从最可靠的测定末期往回追踪每头猪的体重:
track_tol(至少 2
kg)的读数,其余剔除(qc_flag = "track");weight_outlier
中的方法(默认 rlm 和
loess)复核,去掉追踪容差以内、但仍明显偏离曲线的零散读数。没有追踪的猪(有记录的日子少于
7 天、或测定期短于 14 天),以及设置 weight_track = FALSE
时,只用这些方法;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 1rlm_cutoff
越大,判定越严格,被标为异常的记录越多。默认值 0.5 来自 Jiao
等(2014)。如果检查 w$records
后发现大量正常体重被标为异常,可以尝试调低到 0.3–0.4。
调整建议
weight_range 的下限调高,例如
c(20, 150)。validate_outliers()
在自己的数据上比较,见《方法验证》。体重异常值剔除之后,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()
中靠生长曲线填充两端得到,并会带上相应的标记。
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)
看图:是秤的问题还是阈值太严。作用于 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 |
计算分三步:
stage_range
上限的时间;起点:在终点之前,曲线最后一次从下方越过下限的时间(前期数据波动使曲线先越过
30
kg、又掉回去时,起点取之后真正进入区间的那一次)。搜索范围是首条记录前、末条记录后各
max_extrap_days 天。source = "observed");两个有记录的日子之间缺失的日子,用前后两天线性插值("interpolated");首条记录之前、末条记录之后的日子,用生长曲线的值("curve")。结果在
adg$daily$weight_filled。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 62stage_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。
作用于 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
时几乎没有。改小之前,先确认你的猪确实不会单次采食半小时以上。作用于 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 列、且不止一个品种时加入),校正值 = 无错误日采食 −
Σ(系数 × 错误协变量)。没有错误的日子不受影响。
调整建议
dfi_range 的上限不宜低于
5 kg。loess_pop 的 ADFI 误差比 loess_lm
小约三分之一(457 头猪的无泄露检验:7.5% →
4.9%);末端两者相同。比较整条流程时请用
validate_truncation();validate_adfi()
只看插补这一步(见《方法验证》)。loess_pop
的群体曲线来自本批次的猪,批次里的猪太少(少于约 10
头)或体重跨度太窄时,曲线不可靠,可以改用
loess_lm。各曲线的猪数、天数和系数见
adfi$pop_curve。作用于 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
中。每天归入哪一段、每段增重多少,都按生长曲线上的体重计算:每天的实测体重有波动,段边界附近的日子会被随机分到相邻的段,使段内体重的极差偏大。有两项检查:
min_bin_coverage_kg(默认 6
kg),说明这一段体重记录不足,例如耳标脱落、不会进站或设备故障,该猪降级。首尾段不做这项检查,它们由
max_edge_extrap_days 管理。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 月下旬采食骤降、体重停止增长,很可能生过病,分段检查正好把它找了出来。
# 晚进站批次(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")