You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何R语言unique()函数无法处理lm()对象提取的拟合值?

这是个典型的浮点数精度坑!我来给你拆解清楚问题根源和解决办法:

先复现你遇到的异常场景

首先用你的测试数据和模型拟合来重现问题:

# 你的测试数据集
test_data <- data.frame(
  x = c(rep(1.00050239485720394857,4), 1.00050239485720394854,
        rep(2.0002230948570293845,5), rep(3.0005903847502398475,5)),
  y = c(rep(4.00423409872345,5), rep(2.034532039485722,5),
        rep(1.1234152304957,5))
)

# 拟合线性模型
model <- lm(y ~ x, data = test_data)

# 尝试获取拟合值的唯一值,会得到远超预期的结果
unique(fitted(model))

问题根源:浮点数的精度误差

为什么直接处理数据框时unique()正常,处理拟合值就出问题?

  • 你输入的原始数据虽然是高精度小数,但R存储时会按浮点数规则做近似,这些近似后的数值刚好被unique()识别为相等的分组。
  • 但拟合lm()/aov()时,模型会进行一系列浮点运算(系数计算、矩阵乘法等),这些运算会引入极其微小的精度偏差——两个拟合值可能只在小数点后10多位有差异,但unique()是严格基于二进制存储值判断相等的,所以会把这些几乎一样的值当成不同的个体。

你可以用print(fitted(model), digits = 15)查看高精度的拟合值,就能看到那些肉眼几乎不可见的差异了。

解决办法:基于容忍度的近似去重

我们需要把“严格相等”改成“近似相等”,常用两种方法:

方法1:用dplyr的便捷函数(推荐)

dplyr::n_distinct()支持设置容忍度,或者直接对拟合值做四舍五入后去重:

library(dplyr)

# 统计去重后的数量(设置容忍度为1e-8)
n_distinct(fitted(model), tolerance = 1e-8)

# 获取去重后的具体数值
unique_fitted <- unique(round(fitted(model), digits = 8))

方法2:自定义容忍度去重函数

如果你不想加载额外包,可以自己写一个基于差值判断的去重函数:

# 自定义函数:按容忍度判断近似相等
unique_tol <- function(x, tol = 1e-8) {
  x_sorted <- sort(x)
  # 计算相邻值的差值,保留差值大于容忍度的位置
  diffs <- diff(x_sorted)
  keep_positions <- c(TRUE, diffs > tol)
  x_sorted[keep_positions]
}

# 应用到拟合值
unique_tol(fitted(model))

内容的提问来源于stack exchange,提问作者Jerome Dineen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 07:03:12