簡體   English   中英

R中非線性最小二乘內的樣條

[英]Splines inside nonlinear least squares in R

考慮R中的非線性最小二乘模型,例如以下形式:

 y ~ theta / ( 1 + exp( -( alpha + beta * x) ) )

(我真正的問題有幾個變量,外部函數不是邏輯但更多涉及;這個更簡單,但我想如果我能做到這一點,我的情況應該幾乎立即跟隨)

我想用(例如)自然三次樣條替換術語“alpha + beta * x”。

這里有一些代碼用於在邏輯內部創建一些非線性函數的示例數據:

set.seed(438572L)
x <- seq(1,10,by=.25)
y <- 8.6/(1+exp( -(-3+x/4.4+sqrt(x*1.1)*(1.-sin(1.+x/2.9))) )) + rnorm(x, s=0.2 )

如果我在lm中不需要邏輯,我可以輕松地用樣條項替換線性項; 所以線性模型是這樣的:

 lm( y ~ x ) 

然后成為

 library("splines")
 lm( y ~ ns( x, df = 5 ) )

生成擬合值很簡單,並借助於(例如)rms包得到預測值似乎很簡單。

實際上,將原始數據與基於lm的樣條擬合擬合並不是太糟糕,但我有理由在邏輯函數中需要它(或者更確切地說,在我的問題中等價)。

nls的問題是我需要為所有參數提供名稱(我很高興他們稱之為(b1,...,b5)為一個樣條擬合(並說c1,...,c6為另一個變量) - 我需要能夠制作其中的幾個)。

是否有一種合理的方法來生成nls的相應公式,以便我可以用樣條函數替換非線性函數內的線性項?

我能想到的唯一方法就是可以做到這一點有點尷尬和笨重,如果不編寫一大堆代碼就不能很好地概括。

編輯以供澄清 )對於這個小問題,我當然可以手工完成 - 寫出由ns生成的矩陣中每個變量的內積的表達式,乘以參數的向量。 但是,我必須為每個其他變量中的每個樣條再次逐個編寫整個項目,並且每次我在任何樣條曲線中更改df時再次編寫,並且如果我想使用cs而不是ns,則再次。 然后,當我想嘗試做一些預測(/插值)時,我們會得到一系列新的問題需要處理。 我需要一遍又一遍地繼續這樣做,並且可能需要大量的結和幾個變量,以便在分析后進行分析 - 我想知道是否有一種比寫出每個單獨術語更簡潔,更簡單的方法,無需編寫大量代碼。 我可以看到一個相當牛逼的方式,這將涉及到相當多的代碼,但是作為R,我懷疑有更簡潔的方式(或更可能是3或4個更簡潔的方式)只是躲避我。 因此問題。

我以為我曾經看到有人在過去以相當不錯的方式做過這樣的事情,但對於我的生活,我現在找不到它; 我已經嘗試了很多次來找到它。

[更具體地說,我通常希望能夠嘗試適合每個變量中的幾個不同樣條曲線 - 嘗試幾種可能性 - 以便看看我是否能找到一個簡單的模型,但仍然適合這個目的是足夠的(噪音真的非常低;合適的偏差可以達到很好的平滑效果,但只能達到一定程度)。 它更像是“找到一個漂亮的,可解釋的,但足夠的擬合函數”,而不是任何接近推理和數據挖掘的東西都不是這個問題的真正問題。

或者,如果這比gnm或ASSIST或其他包裝更容易,那將是有用的知識,但是關於如何繼續上述玩具問題的一些指示將有所幫助。

ns實際上生成了一個預測變量矩陣。 您可以做的是將該矩陣拆分為單個變量,並將它們提供給nls

m <- ns(x, df=5)
df <- data.frame(y, m)  # X-variables will be named X1, ... X5
# starting values should be set as appropriate for your data
nls(y ~ theta * plogis(alpha + b1*X1 + b2*X2 + b3*X3 + b4*X4 + b5*X5), data=df,
        start=list(theta=1, alpha=0, b1=1, b2=1, b3=1, b4=1, b5=1))

ETA:這是針對不同df值自動執行此操作。 這使用文本munging構造公式,然后使用do.call來調用nls 警告:未經測試。

my.nls <- function(x, y, df)
{
    m <- ns(x, df=df)
    xn <- colnames(m)
    b <- paste("b", seq_along(xn), sep="")
    fm <- formula(paste("y ~ theta * plogis(1 + alpha + ", paste(b, xn, sep="*",
          collapse=" + "), ")", sep=""))
    start <- c(1, 1, rep(1, length=length(b)))
    names(start) <- c("theta", "alpha", b)
    do.call(nls, list(fm, data=data.frame(y, m), start=start))
}

我在澄清自己的問題時得到的一個認識讓我發現,與我以前見過的方式相比,這種方式不那么笨拙。

即使有一些明顯的流線型可以進入,但這對我來說仍然有點不優雅,但至少可以忍受重復使用,所以我認為這是一個充分的答案。 仍然對比下面這個更簡潔的方式感興趣。

Hong Ooi在ns生成的矩陣上使用data.frame來自動命名列的技巧很可愛,我在下面使用它。 我可能會使用粘貼來構建它們,因為我有幾個變量可以使用。

假設問題中給出的數據設置 -

lin.expr <- function(p,xn) {
  pn<-paste(p, 1:length(xn), sep = "")
  paste(paste(pn,xn,sep=" * "),collapse=" + ")
  }


m <- ns(x, df=3)
mydf <- data.frame(y, m)  # X-variables will be named X1, X2, ... 
xn <- names(mydf)[2:dim(mydf)[2]]

nspb <- lin.expr("b",xn)

c.form <- paste("y ~ theta * plogis( a + ",nspb,")",sep="")
stl <- list(theta=2, a=-5,b1=10, b2=10, b3=10)
nls( c.form, data=mydf, start= stl)

我的實際公式將有幾個術語,如nspb。 實質性改進得到贊賞; 我不想選擇自己的答案,但我想如果一兩天內沒有任何進展,我會選擇它。

編輯:Hong Ooi的補充(發布時我正在打字並使用類似的想法,但添加了幾個不錯的額外內容)幾乎就是這樣; 這是一個可以接受的答案,所以我已經檢查過了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM