tidypptsda 要解决的问题很具体:把测定站导出的一次次访问记录,变成每头猪可信、可比的日增重(ADG)、日采食量(ADFI)和料肉比(FCR)。本文说明这个包为什么这样设计:每一步背后的考虑、做过的取舍,以及刻意没有做的事。具体方法见《计算方法说明》,参数见《质控参数详解》。
测定站的数据有它自己的”脾气”,方法要顺着它来设计,而不是套用通用的统计规则。
这几条直接决定了体重清洗的顺序:先去掉 15–150 kg 以外的读数和 7 天适应期,再从最可靠的测定末期往前逐日追踪,只保留与推算体重衔接的读数,最后才用二次稳健回归和 LOESS 去掉零散的异常值。通用的异常值方法把整条曲线当作参照,进站初期一半读数都偏重时,曲线本身就被拉高了,所以不能只靠它们。
追踪剔除的记录很多(超过 40%)时,问题通常不在猪,而在秤:比如一头猪到 50–100 kg 时仍长期出现两条平行的体重带,这时秤上只容得下一头猪,只能是体重传感器出了故障。这样的猪会被标出来,原因写明”可能是称重异常”。
FCR = ADFI ÷ ADG,只有当分子和分母来自同一段体重、同一批日子时,它才有意义。如果 ADG 按 30–120 kg 算,而 ADFI 按整个测定期的平均采食算,两头进站体重不同的猪就无法比较。
所以全流程只有一个区间 stage_range(默认 30–120
kg)。生长曲线确定每头猪进入和离开这个区间的日期,之后
ADG、ADFI、分段检查用的都是这批日子。改区间时,所有地方一起改:起止日期、要补齐的日子、适应期的采食是否计入、10
kg 分段,以及图中的虚线。
缺记录是测定站的常态:猪某天没进站、耳标没读到、设备故障,或者进站晚、出栏早。与其在计算时绕开缺失,不如先把区间内每一天都补齐,补的方法随缺失的位置而不同:
| 缺失位置 | 体重 | 采食 |
|---|---|---|
| 两个有记录的日子之间 | 前后两天线性插值 | ≤ 3 天:LOESS 平滑;> 3 天:群体曲线 × 个体比例 |
| 区间开头(进站晚) | 切线外推 | 群体曲线 × 个体比例 |
| 区间末端(出栏早) | 生长曲线 | 这头猪自己的”采食 ~ 体重”回归 |
背后的考虑是:中间缺失时,前后两天的实测最能说明这头猪当时的状态;两端缺失时没有实测可依,只能靠模型。晚进站的猪缺的是前期,它自己的数据里没有前期的信息,所以借用全群的曲线形状,每头猪只提供自己的采食水平;早出栏的猪缺的是末期,末期的上升趋势它自己的数据里已经有了,而全群曲线在高体重段变平,会低估它,所以末端用它自己的回归。这两个选择都来自无泄露的整体验证(validate_truncation()),而不是凭直觉。逐步示意见《填充方法》。用自己的数据验证过:中间缺失时,线性插值的日体重误差约
0.8 kg,用生长曲线约 1.1–1.6 kg。
补齐之后,ADG 就是区间内每天体重对日期回归的斜率。这个定义直观,和”每天长多少”的说法一致;有一两天的读数偏高或偏低,对斜率的影响也很小;R² 还能说明这头猪长得是否平稳。每一天的体重和它的来源(实测、插值、曲线)都保留在结果里,图中也用不同颜色标出,补了多少一目了然。
育种评估需要尽可能多的个体,而”不完美”不等于”不能用”。所以本包的原则是能算就算,算不准就标出来:
low_confidence,原因写进
reason 或
fcr_note:进站太重、出栏太轻、两端填充超过 15
天、采食实测不足 70%、某个 10 kg 段记录断档等;qc_flag,每头被剔除的猪都在 $removed
中写明在哪一步、因为什么。这样,用的人可以自己决定:育种评估只用 fcr_flag = "ok"
的个体,描述性统计用全部个体,或者在模型中把低可信度的个体区分开。
国家测定规程中的累计采食法曾作为可选方法实现过,后来删去了,原因正在于此。在示例数据上它会直接剔除大约一半的猪;分段料肉比还会因 n/(n−1) 的偏差系统性偏高,又引出更多的剔除;累计采食对体重的关系是向上弯的,用直线外推会低估 FCR。
所有阈值都集中在 qc_config()
返回的一个对象里,各函数通过 qc 参数接收,结果的
$settings 原样保存。这样做有三个好处:
print(qc_config())
一次列出全部参数,不用到各个函数里找;$settings;早期版本提供过几套预设(casey、national、legacy),实际使用中反而让人困惑:预设之间差的是几十个参数的组合,很难说清楚差别来自哪里。1.0.0 起只保留一套默认方法,需要时逐个覆盖参数,每一处改动都看得见。
每一步尽量用有文献依据的方法:采食错误判定用 Casey 等(2005)的 16 条规则,体重异常值和采食校正用 Jiao 等(2014)的稳健回归和混合模型,平滑用 Cleveland(1979)的稳健 LOESS。逐日回溯追踪是本包根据测定站的称重方式设计的,它的作用同样可以检验。
但没有一种方法在所有批次上都最好:晚进站的批次,二次曲线外推不稳,直线反而更好;成段缺失时 LOESS 略好于线性插值,两端缺失时两者一样。与其凭经验选择,本包提供了四个验证函数,在你自己的数据上故意加入误差或隐藏一部分记录,看哪种方法恢复得最好:
| 函数 | 检验什么 |
|---|---|
validate_outliers() |
体重异常值方法 |
validate_adg() |
生长曲线模型 |
validate_weight_fill() |
体重填充方法 |
validate_adfi() |
采食填充方法 |
验证的结论也反过来影响了默认设置。例如几项验证都说明:保证区间两端有记录,比选择哪种方法更重要,所以两端填充超过 15 天的猪会被标为低可信度。
NEDAP 和 FIRE 的导出格式完全不同:列名、时间格式、单位都不一样,同一种设备不同软件版本也会有差别。如果每个分析函数都去适应这些差异,代码会越来越乱,也容易出错。
所以本包只在入口处理差异:read_station()
按”站点格式”把各种导出对应到同一张标准表,之后的分析只认这张表。列名对不上时,把格式写成一个小文本文件,同一种导出只需写一次。耳标号一律按文本读入,前导零不会丢失;单位统一为
g 和 kg,时间统一为时间型。
write_results() 导出的
csv 带 BOM,Excel 打开中文不乱码;adg_type = "partial"),并标为低可信度。本包不会为它编造一段”本该有”的生长。