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

基于Cohort对数据框多列做线性回归时遇NA/NaN/Inf错误求助

问题描述

我在StackOverflow搜过相关答案但还是搞不懂,若问题重复先说声抱歉。我有如下样例数据框:

df <- data.frame(Cohort = c('con', 'con', 'dis', 'dis', 'con', 'dis'),
                 Sex = c('M', 'F', 'M', 'F', 'M', 'M'),
                 P1 = c(50, 40, 70, 80, 45, 75),
                 P2 = c(10, 9, 15, 13, 10, 8))

我想以Cohort为预测变量,对所有数值列做线性回归(之后还要加Sex这类特征)。我先剔除无关列:

new_df <- df[,-c(Sex)]

再执行回归:

fit <- lapply(new_df[-1], function(y){summary(lm(y ~ Cohort, data=new_df))})

小数据集(约5列)测试没问题,但真实数据集(约7300列)报错:

Error in lm.fit(x, y, offset = offset, singular.ok = singular.ok, ...) :
NA/NaN/Inf in 'y'

我以为是缺失值,但sum(is.na(new_df))返回0,加na.action=na.omit也没用。我的目标是提取p值(anova(fit)$'Pr(>F)')和R平方(summary(fit)$r.squared)。请问怎么修正错误?有没有更优方法?另外后续加特征时,能不能不用子集化数据框就执行回归?

附真实数据框片段(dput输出):

structure(list(Cohort = c("Disease", "Disease", "Control", "Control"), 
    seq.10010.10 = c(8.33449676839042, 8.39959836912012, 8.34385193344212, 
    8.43546191447928), seq.10011.65 = c(11.5222872738433, 11.7652860987237, 
    11.1661630826461, 11.008848763327), seq.10012.5 = c(10.5414838640543, 
    10.6862378767518, 10.5408061105915, 10.726558779105)), class = c("soma_adat", 
"data.frame"), row.names = c("258633854330_1", "258633854330_3", 
"258633854330_5", "258633854330_6"))
解决方案

1. 修正「NA/NaN/Inf in 'y'」错误

sum(is.na(new_df))只能检测缺失值,但无法识别Inf或-Inf。可以检查数值列中是否存在无穷值:

# 检查所有数值列是否有Inf/-Inf
any_inf <- sapply(new_df[sapply(new_df, is.numeric)], function(col) any(is.infinite(col)))
# 输出有问题的列名
names(which(any_inf))

如果找到这类列,可按以下方式处理:

# 将Inf/-Inf替换为NA,再删除对应行(或根据需求替换为合理值)
new_df[sapply(new_df, is.numeric)] <- lapply(new_df[sapply(new_df, is.numeric)], function(col) {
  col[is.infinite(col)] <- NA
  col
})
# 删除含NA的行
new_df <- na.omit(new_df)

另外,原始剔除列的写法有误,Sex是列名,正确写法应为:

# 正确剔除Sex列的方式
new_df <- df[, !colnames(df) %in% c("Sex")]

2. 更高效的批量回归方法

针对7300列的大数据集,用purrr+broom组合比lapply更简洁,且方便结果整理:

library(purrr)
library(broom)

# 批量执行回归并提取所需统计量
results <- map(new_df[, -which(colnames(new_df) == "Cohort")], function(y_col) {
  fit <- lm(y_col ~ Cohort, data = new_df)
  # 一次性提取R平方和p值
  glance(fit) %>% 
    select(r.squared, p.value)
})

# 合并为结构化数据框
results_df <- bind_rows(results, .id = "Variable")

broom包的glance()函数可以直接提取关键统计量,避免手动从summary()或anova()中提取,大幅提升效率。

3. 无需子集化添加特征的方法

不用提前剔除无关列,直接动态构建回归公式即可加入特征。比如要加入Sex:

# 筛选出所有需要作为因变量的数值列
numeric_cols <- setdiff(colnames(df), c("Cohort", "Sex"))

results_with_sex <- map(numeric_cols, function(col) {
  # 动态生成公式:col ~ Cohort + Sex
  formula <- as.formula(paste(col, "~ Cohort + Sex"))
  fit <- lm(formula, data = df)
  glance(fit) %>% 
    select(r.squared, p.value) %>% 
    mutate(Variable = col)
})

# 合并结果
results_with_sex_df <- bind_rows(results_with_sex)

这种方法无需修改原始数据框,直接通过公式指定预测变量即可。

4. 额外优化建议

  • 针对7300列的数据集,批量回归会消耗较多内存,可分批次处理,或用furrr包实现并行计算加速。
  • 若Cohort是二分类变量,线性回归结果与t检验等价,用t.test()批量执行速度更快:
# 批量t检验示例(二分类Cohort)
t_results <- map(numeric_cols, function(col) {
  test <- t.test(df[[col]] ~ df$Cohort)
  tibble(Variable = col, p.value = test$p.value, mean_diff = test$estimate[1] - test$estimate[2])
})
t_results_df <- bind_rows(t_results)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 10:09:58