代码之家  ›  专栏  ›  技术社区  ›  Joris Meys

R中自定义函数的约束优化

  •  5
  • Joris Meys  · 技术社区  · 14 年前

    我有一个复杂的组合模型,我可以在函数中定义一个可能性,我需要优化参数。问题是,如果不受限制的话,参数会向所有方向移动。因此,我需要实现对参数的一个限制,教授提出的一个限制是平方参数值之和应该等于1。

    我一直在玩 optim() nlm() 功能,但我不能得到我想要的。第一个想法是使用n-1参数并从其余的参数中计算出最后一个参数,但这并没有起作用(如预期的那样)。

    举例来说,一些玩具数据和函数反映了我想要实现的核心问题:

    dd <- data.frame(
        X1=rnorm(100),
        X2=rnorm(100),
        X3=rnorm(100)
    )
    dd <- within(dd,Y <- 2+0.57*X1-0.57*X2+0.57*X3+rnorm(100,0,0.2))
    
    myfunc2 <- function(alpha,dd){
        alpha <- c(alpha,sqrt(1-sum(alpha^2)))
        X <- as.matrix(dd[,-4]) %*% alpha
        m.mat <- model.matrix(~X)
        mod <- glm.fit(m.mat,dd$Y)
        Sq <- sum(resid(mod)^2)
        return(Sq)
    }
    
    b <- c(1,0)
    optim(b,myfunc2,dd=dd)
    

    这显然会导致:

    Error: (subscript) logical subscript too long
    In addition: Warning message:
    In sqrt(1 - sum(alpha^2)) : NaNs produced
    

    注:我知道这个示例代码根本没有意义。只是为了演示。


    编辑:解决了!-见Mareks的回答。

    3 回复  |  直到 12 年前
        1
  •  2
  •   Community CDub    7 年前

    我想是的 Ramnath answer

    这是改进版:

    myfunc2 <- function(alpha,dd){
        alpha <- alpha/sqrt(sum(alpha^2)) # here the modification ;)
        X <- as.matrix(dd[,-4]) %*% alpha
        m.mat <- model.matrix(~X)
        mod <- glm.fit(m.mat,dd$Y)
        Sq <- sum(resid(mod)^2)
        return(Sq)
    }
    
    b = c(1,1,1)
    ( x <- optim(b, myfunc2, dd=dd)$par )
    ( final_par <- x/sqrt(sum(x^2)) )
    

    我得到了和你的无限制版本相似的结果。


    [编辑]

    实际上,如果起点是错误的,这将无法正常工作。例如

    x <- optim(-c(1,1,1), myfunc2, dd=dd)$par
    ( final_par <- x/sqrt(sum(x^2)) )
    # [1] -0.5925  0.5620 -0.5771
    

    mod <- glm.fit(m.mat,dd$Y) 估计负系数 X .

    我认为这个glm的重新估计是不太正确的。我认为你应该把截距估计为残差的平均值 Y-X*alpha .

    类似于:

    f_err_1 <- function(alpha,dd) {
        alpha <- alpha/sqrt(sum(alpha^2))
        X <- as.matrix(dd[,-4]) %*% alpha
        a0 <- mean(dd$Y-X)
        Sq <- sum((dd$Y-a0-X)^2)
        return(Sq)
    }
    
    x <- optim(c(1,1,1), f_err_1, dd=dd)$par;( final_par <- x/sqrt(sum(x^2)) )
    # [1] 0.5924 -0.5620  0.5772
    x <- optim(-c(1,1,1), f_err_1, dd=dd)$par;( final_par <- x/sqrt(sum(x^2)) )
    # [1]  0.5924 -0.5621  0.5772
    
        2
  •  1
  •   Joris Meys    14 年前

    为了说明我的观点,在上面的示例中,可以通过对代码进行以下更改来运行优化:

    myfunc2 <- function(alpha,dd){
        alpha <- alpha^2/sum(alpha^2);
        X <- as.matrix(dd[,-4]) %*% alpha
        m.mat <- model.matrix(~X)
        mod <- glm.fit(m.mat,dd$Y)
        Sq <- sum(resid(mod)^2)
        return(Sq)
    }
    
    b = c(1,1,1)
    optim(b,myfunc2,dd=dd);
    ans = b^2/sum(b^2)
    

    这也适用于3个以上的变量。让我知道这是否合理,如果你还有其他问题。

        3
  •  0
  •   Ben Bolker    14 年前

    p_1' = p_1
    p_2' = sqrt(p_2*(1-p_1'^2))
    p_3' = sqrt(p_3*(1-(p_1^2+p_2^2))
    ...
    p_n' = 1-sqrt(sum(p_i^2))
    

    或者类似的事情。