【问题标题】:Manually build logistic regression model for prediction in R手动构建逻辑回归模型以在 R 中进行预测
【发布时间】:2014-07-29 13:19:54
【问题描述】:

我正在尝试在数据集上测试逻辑回归模型(例如 3 个预测变量 X1、X2、X3 的 3 个系数)。我知道在创建模型对象后如何测试模型,例如,

mymodel <- glm( Outcome ~  X1 + X2 + X3 , family = binomial,data=trainDat)

然后测试数据

prob <- predict(mymodel,type="response",newdata=test)

但是我现在想使用我拥有的系数和截距创建一个逻辑模型,然后在数据上测试这个模型。

基本上我不清楚如何在不运行 glm 的情况下创建“mymodel”。

问题的背景: 我已经使用偏移量进行了逻辑回归,例如:

mymodel <- glm(Outcome ~ offset(C1 * X1) + offset(C2 * X2) + X3, 
               family = binomial, data = trainDat)

因此,mymodel 对象生成的模型只有截距 (I) 和 C3 系数(对于特征 X3)。
我现在需要在测试数据集上测试完整模型(即 I + C1*X1 + C2*X2 + C3*X3),但我不知道如何获取完整模型,因为 mymodel 的输出只有拦截和C3。所以我认为我更一般的问题是:“你如何手动构建逻辑回归模型对象?”

感谢您的耐心等待。

【问题讨论】:

  • 那么您是否只想保存mymodel 对象并稍后重新加载,这样您就不必再次运行glm?是不是需要很长时间才能运行?
  • 他们还包括方差/协方差矩阵?以及所有因子级别的编码?
  • 不,没有协方差矩阵。是的,我知道因子级编码。协方差矩阵不应该是不必要的吗?我知道您可以仅使用系数和因子水平规则在 excel 中手动创建逻辑函数。在这里,我将在我的问题中添加一些内容以允许多种答案类型。
  • 包含测试数据的问题会引起更多兴趣。

标签: r model regression building


【解决方案1】:

我找不到执行此操作的简单函数。 predict 函数中有一些代码取决于拟合模型(例如确定模型的等级)。但是,我们可以创建一个函数来制作一个可以与 predict 一起使用的假 glm 对象。这是我第一次尝试这样的功能

makeglm <- function(formula, family, data=NULL, ...) {
    dots <- list(...)
    out<-list()
    tt <- terms(formula, data=data)
    if(!is.null(data)) {
        mf <- model.frame(tt, data)
        vn <- sapply(attr(tt, "variables")[-1], deparse)

        if((yvar <- attr(tt, "response"))>0)
            vn <- vn[-yvar]
            xlvl <- lapply(data[vn], function(x) if (is.factor(x))
           levels(x)
        else if (is.character(x))
           levels(as.factor(x))
        else
            NULL)
        attr(out, "xlevels") <- xlvl[!vapply(xlvl,is.null,NA)]
        attr(tt, "dataClasses") <- sapply(data[vn], stats:::.MFclass)
    }
    out$terms <- tt
    coef <- numeric(0)
    stopifnot(length(dots)>1 & !is.null(names(dots)))
    for(i in seq_along(dots)) {
        if((n<-names(dots)[i]) != "") {
            v <- dots[[i]]
            if(!is.null(names(v))) {
                coef[paste0(n, names(v))] <- v
            } else {
                stopifnot(length(v)==1)
                coef[n] <- v
            }
        } else {
            coef["(Intercept)"] <- dots[[i]]
        }   
    }
    out$coefficients <- coef
    out$rank <- length(coef)
    out$qr <- list(pivot=seq_len(out$rank))
    out$family <- if (class(family) == "family") {
        family
    } else if (class(family) == "function") {
        family()
    } else {
        stop(paste("invalid family class:", class(family)))
    }
    out$deviance <- 1
    out$null.deviance <- 1
    out$aic <- 1
    class(out) <- c("glm","lm")
    out
}

所以这个函数创建一个对象并传递predictprint 期望在这样一个对象上找到的所有值。现在我们可以测试它了。首先,这是一些测试数据

set.seed(15)
dd <- data.frame(
    X1=runif(50),
    X2=factor(sample(letters[1:4], 50, replace=T)),
    X3=rpois(50, 5),
    Outcome = sample(0:1, 50, replace=T)
)

我们可以用

拟合标准二项式模型
mymodel<-glm(Outcome~X1+X2+X3, data=dd, family=binomial)

这给了

Call:  glm(formula = Outcome ~ X1 + X2 + X3, family = binomial, data = dd)

Coefficients:
(Intercept)           X1          X2b          X2c          X2d           X3  
    -0.4411       0.8853       1.8384       0.9455       1.5059      -0.1818  

Degrees of Freedom: 49 Total (i.e. Null);  44 Residual
Null Deviance:      68.03 
Residual Deviance: 62.67    AIC: 74.67

现在假设我们想试用我们在同一数据的出版物中读到的模型。下面是我们如何使用makeglm 函数

newmodel <- makeglm(Outcome~X1+X2+X3, binomial, data=dd, 
    -.5, X1=1, X2=c(b=1.5, c=1, d=1.5), X3=-.15)

第一个参数是模型的公式。这就像运行 glm 时一样定义响应和协变量。接下来,您可以像使用 glm() 一样指定族。您需要传递一个数据框,以便 R 可以为所涉及的每个变量嗅探正确的数据类型。这还将使用 data.frame 识别所有因子变量及其水平。因此,这可以是像拟合的 data.frame 一样编码的新数据,也可以是原始数据。

现在我们开始指定要在模型中使用的系数。系数将使用参数名称填充。未命名的参数将用作截距。如果您有一个因子,则需要通过命名参数为所有级别提供系数。在这里,我只是决定将拟合的估计值四舍五入为“不错”的数字。

现在我可以将 newmodel 与 predict 一起使用。

predict(mymodel, type="response")
#         1         2         3         4         5
# 0.4866398 0.3553439 0.6564668 0.7819917 0.3008108

predict(newmodel, newdata=dd, type="response")

#         1         2         3         4         5
# 0.5503572 0.4121811 0.7143200 0.7942776 0.3245525

在这里,我使用带有我指定系数的旧数据对原始模型和新模型进行预测。我们可以看到概率估计发生了一些变化。

现在我还没有彻底测试过这个功能,所以使用风险自负。我没有做尽可能多的错误检查。也许其他人确实知道更好的方法。

【讨论】:

  • 这是一项了不起的努力,我欠你的。我非常感谢这一点,并且知道其他人也会这样做。我将使用它并对其进行审查,并尝试在下面添加一些进一步的见解。
  • 我还将代码发布为gist。我稍后会发布我对代码所做的任何更新。
猜你喜欢
  • 2018-08-18
  • 1970-01-01
  • 1970-01-01
  • 2015-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-28
  • 2018-01-26
相关资源
最近更新 更多