如何最好地处理线性模型中的左删失预测器(因为检测限)?

机器算法验证 回归 贝叶斯 多重回归 审查 斯坦
2022-01-25 14:22:25

背景:我是贝叶斯统计的新手,正在尝试使用rstan. 所有变量都是连续的,没有层次结构。

我的一个预测因子是左删失的,因为它低于化学分析的检测限。在多元回归中处理这个问题的最佳方法是什么?到目前为止,我可以看到一些可能性:

  1. 替换规则,例如“将低于检测限的所有值替换为常数,例如检测限/2”。这显然不严谨。
  2. 多重插补,但是(i)我不知道如何处理高于检测限的值可能由插补过程产生的事实,我很可能知道这是错误的,并且(ii)我'不确定多重插补与贝叶斯方法的效果如何,因为我想不出一种将后验分布从拟合汇总到不同插补数据集的好方法
  3. 根据先验知识和数据从有意义的分布中模拟值数据,并将低于检测限的值随机分配给相关点。这会遇到与#2 类似的问题,因为我必须模拟多组值,分别对它们进行建模,然后弄清楚如何整合后验。

我错过了更好的选择吗?是否有有用的贝叶斯技巧可以帮助解决这个问题?我也对非贝叶斯选项持开放态度。

下面的直方图显示了值的分布。该图采用对数刻度,因为这对于该变量来说是最自然的。为了清晰起见,我将低于检测限(约 25% 的数据)的值视为检测限的 1/10,并添加了一条红线将它们与其余点分开。注意红线不是精确的检测限;红线右侧的最小量化值处于假定极限。事实上,只有很少的值恰好处于极限,这表明测量之间的检测极限可能存在一些变化,但我不介意为了这个问题的目的而忽略这一点。 直方图

更新:

这是我的rstan代码,以防万一。Beta 1 到 4 代表主效应,5 和 6 是交互项(介于 1 和 3 和 2 和 4 之间)。因此,删失预测变量也存在于交互项中,这是我之前忽略的一个复杂因素。

data {
  int<lower=0> n;       // number of data items
  int<lower=0> k;       // number of predictors
  vector[n] Y;          // outcome vector
  matrix[n,k] X;        // predictor matrix
  int n2;               //the size of the new_X matrix
  matrix[n2,k] new_X;   //the matrix for the predicted values
}
parameters {
  real alpha; // intercept
  vector[k] beta; // coefficients for predictors
  real<lower=0> sigma; // error scale (cauchy truncated at zero)
}
model {
  beta[1] ~ normal(-0.75, 1);   //prior for beta
  beta[2] ~ normal(0, 3);   //prior for beta
  beta[3] ~ normal(0, 3);   //prior for beta
  beta[4] ~ normal(0, 3);   //prior for beta
  beta[5] ~ normal(0, 3);   //prior for beta
  beta[6] ~ normal(0, 3);   //prior for beta
  sigma ~ cauchy (0, 2.5);  //prior for sigma

  Y ~ normal(alpha + X * beta, sigma); // likelihood
}
generated quantities {
  vector[n2] y_pred;
  y_pred = new_X * beta; //the y values predicted by the model
}
4个回答

rstan 为您提供了使用贝叶斯推理解决此问题所需的所有工具。除了根据预测变量的通常回归模型之外,您还应该在 Stan 代码中包含一个这个模型应该包括左审查。Stan 用户手册中关于审查的章节用 Stan 语言解释了两种不同的方法。第一种方法更容易融入回归模型。的模型看起来像这样(省略 N_obs 等的定义):yxxx

data {
  real x_obs[N_obs];
}
parameters {
  real<upper=DL> x_cens[N_cens];
  real x[N];
}
model {
  x_obs ~ normal(mu, sigma);
  x_cens ~ normal(mu, sigma);
  x = append_array(x_obs, x_cens);
}

关键思想是删失数据由上限为检测限的参数表示。审查后的数据将与模型中的其他参数一起采样,因此您获得的后验将自动整合审查后的数据。

在 McElreath 的Statistical Rethinking (2020) 中,他举了一个几乎与您所描述的完全一样的例子,在化学分析中,有一个阈值,低于该阈值(例如特定化合物的浓度)是无法测量的。在这种情况下,他讨论了障碍模型的使用。从我正在阅读的内容来看,它们可能适用于您的分析,并且使用 Stan 也可以相对轻松地拟合它们。

https://mc-stan.org/docs/2_20/stan-users-guide/zero-inflated-section.html

麦克尔瑞思,R. (2020)。Statistical rethinking: A Bayesian course with examples in R and Stan。CRC出版社。

这是一个有点相关的问题:应该向 x 添加多小的数量以避免取零的对数?

这看起来像是一篇非常相关的论文,它使用贝叶斯回归和 LOD 审查预测变量:https ://www.ncbi.nlm.nih.gov/pmc/articles/PMC6241297/

一个简单但可能不太理想的选择是添加一个指示变量来判断观察值是否低于 LOD。

多重插补与贝叶斯推理相当好。您只需在每个插补上拟合贝叶斯模型(确保不会太少,例如至少进行 100 次左右插补),然后将后验样本放在一起(=您使用后验的混合作为整体后验)。但是,进行良好的多重插补需要一个知道左删失的多重插补工具(如果您忽略这一点,MI 更有可能插补值,例如未删失的观察值)。从技术上讲,我认为进行多重插补并仅选择值低于检测限的插补是有效的,但是您很快就会到达 1000 个插补都不符合标准的地方。

如果删失量是模型中的因变量,那么您提到的替换规则显然不会太糟糕(例如,请参阅本文以获取有关该主题的参考列表)。它对协变量有什么作用?不知道。我推测它可能没问题,如果审查值很少的话。但是,您有很多被审查的值。

Tom Minka 提到的另一个明显的方法是协变量和感兴趣的结果的联合建模。我试图用 Stan 用一些虚构的数据来真正拼出这个,比如你的例子。我怀疑像往常一样,我的 Stan 程序没有写得那么有效,但至少我希望它是相当清楚的。

library(rstan)

stancode = "
data {
  int<lower=0> N_obs; // Number of observation
  real y[N_obs]; // Observed y-values
  
  real x[N_obs]; // observed value or limit below which x is left-censored when x_censored=1
  int x_censored[N_obs]; // 1=left-censored, 0=not censored, 2=right-censored
  real measurement_error[N_obs]; // measurement error we know for the covariates
}
parameters {
  real mu; // intercept for the regression model for y
  real<lower=0> sigma; // residual SD for the regression model for y
  real beta; // regression coefficient for x in the regression model for y
  
  real x_randomeff[N_obs]; // A random effect we use to capture the underlying true value 
     // (obtained by multiplying by sigmax and adding mux - for more on the rationale for this parameterization look "non-centralized parameterization")
  real mux; // True population mean of the covariate values
  real<lower=0> sigmax; // True population SD of the covariate values
}
transformed parameters {
  real x_imputed[N_obs]; // Imputed values for x (or rather log(x))
  for (r in 1:N_obs){
    x_imputed[r] = mux + x_randomeff[r] * sigmax;
  }
}
model {
  // Specifying some wide weakly informative priors
  mu ~ normal(0, 100);
  sigma ~ normal(0, 100);
  beta ~ normal(0, 100);
  mux ~ normal(0, 10);
  sigmax ~ normal(0, 10);
  
  x_randomeff ~ normal(0,1);
  
  for (r in 1:N_obs){
    // Dealing with the covariate model
    if (x_censored[r]==1){
      target += normal_lcdf(x[r] | x_imputed[r], measurement_error[r]);
    } else if (x_censored[r]==2){
      target += normal_lccdf(x[r] | x_imputed[r], measurement_error[r]);
    } else {
      x[r] ~ normal(x_imputed[r], measurement_error[r]);
    }
    
    // fitting the regression model for y
    y[r] ~ normal(mu + x_imputed[r]*beta, sigma);
  }
  
}
"

sfit = stan(model_code = stancode,
         data=list(N_obs=12,
                   y=c(44, 40, 37, 33, 31, 27, 24, 19, 16, 13, 9, 6),
                   x=log( c(15,  7,  5,  3,  0.9, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5) ),
                   x_censored = c(rep(0,5), rep(1, 7)),
                   measurement_error=rep(0.1, 12)),
         control=list(adapt_delta=0.95))

summary(sfit)$summary

正如您所看到的,该模型甚至会输出它为缺失值估算的内容。可能还有其他方法可以做到这一点,但这对我来说似乎相当直观。目前,我在回归方程中使用,但你可以通过取幂来改变它log(x)×βx_imputed[r]

更新这篇论文刚刚出现在我的 Twitter 提要中。