如何使用 R 中的最大似然模型将非线性函数拟合到 ggplot2 中的数据?
How to fit non-linear function to data in ggplot2 using maximum likelihood model in R?
数据集(x.test、y.test)是指数拟合。我正在尝试拟合自定义非线性函数并附上代码。常规点图很好,但我无法使拟合线起作用。有什么建议吗?
x.test <- runif(50,2,8)
y.test <- 0.5^(x.test)
df <- data.frame(x.test, y.test)
library(ggpmisc)
my.formula <- y ~ lambda/ (1 + aii*x)
ggplot(data = df, aes(x=x.test,y=y.test)) +
geom_point(shape=21, fill="white", color="red", size=3) +
stat_smooth(method="nls",formula = y.test ~ lambda/ (1 + aii*x.test), method.args=list(start=c(lambda=1000,aii=-816.39)),se=F,color="red") +
geom_smooth(method="lm", formula = my.formula , col = "red") + stat_poly_eq(formula = my.formula, aes(label = stringr::str_wrap(paste(..eq.label.., ..rr.label.., sep = "~~~"))), parse = TRUE, size = 2.5, col = "red") + stat_function(fun=function (x.test){
y.test ~ lambda/ (1 + aii*x.test)}, color = "blue")
一些事情:
- 您需要使用
y
和 x
作为 formula
参数中 geom_smooth
的变量名称,无论数据集中的名称是什么
- 您需要更好的起始值(见下文)
- 您可以使用 GLM 技巧来拟合此模型;并不总是有效(可能在数值上不稳定),但它不需要起始值并且比
nls()
更频繁地工作
- 我认为
lm()
和 stat_poly_eq()
不会按预期(或者根本不会)使用非线性公式...
模拟数据
(与您的代码相同,但使用 set.seed()
- 此处可能不重要,但很好的做法)
set.seed(101)
x.test <- runif(50,2,8)
y.test <- 0.5^(x.test)
df <- data.frame(x.test, y.test)
尝试 nls 适合您的起始值
通过在 ggplot2
的 外部 拟合任何平滑项来排除故障通常是个好主意,因此您可以通过更少的层来挖掘问题:
nls(y.test ~ lambda/(1+ aii*x.test),
start = list(lambda=1000,aii=-816.39),
data = df)
Error in nls(y.test ~ lambda/(1 + aii * x.test), start = list(lambda = 1000, :
singular gradient
好的,还是不行。让我们使用 glm()
来获得更好的起始值:我们使用 inverse-link GLM:
1/y = b0 + b1*x
y = 1/(b0 + b1*x)
= (1/b0)/(1 + (b1/b0)*x)
所以:
g1 <- glm(y.test ~ x.test, family = gaussian(link = "inverse"))
s0 <- with(as.list(coef(g1)), list(lambda = 1/`(Intercept)`, aii = x.test/`(Intercept)`))
这给出了 lambda = -0.09,aii = -0.638(再多做一点工作,我们可能还可以通过查看曲线的起点和比例来弄清楚如何观察这些)。
ggplot(data = df, aes(x=x.test,y=y.test)) +
geom_point(shape=21, fill="white", color="red", size=3) +
stat_smooth(method="nls",
formula = y ~ lambda/ (1 + aii*x),
method.args=list(start=s0),
se=FALSE,color="red") +
stat_smooth(method = "glm",
formula = y ~ x,
method.args = list(gaussian(link = "inverse")),
color = "blue", linetype = 2)
数据集(x.test、y.test)是指数拟合。我正在尝试拟合自定义非线性函数并附上代码。常规点图很好,但我无法使拟合线起作用。有什么建议吗?
x.test <- runif(50,2,8)
y.test <- 0.5^(x.test)
df <- data.frame(x.test, y.test)
library(ggpmisc)
my.formula <- y ~ lambda/ (1 + aii*x)
ggplot(data = df, aes(x=x.test,y=y.test)) +
geom_point(shape=21, fill="white", color="red", size=3) +
stat_smooth(method="nls",formula = y.test ~ lambda/ (1 + aii*x.test), method.args=list(start=c(lambda=1000,aii=-816.39)),se=F,color="red") +
geom_smooth(method="lm", formula = my.formula , col = "red") + stat_poly_eq(formula = my.formula, aes(label = stringr::str_wrap(paste(..eq.label.., ..rr.label.., sep = "~~~"))), parse = TRUE, size = 2.5, col = "red") + stat_function(fun=function (x.test){
y.test ~ lambda/ (1 + aii*x.test)}, color = "blue")
一些事情:
- 您需要使用
y
和x
作为formula
参数中geom_smooth
的变量名称,无论数据集中的名称是什么 - 您需要更好的起始值(见下文)
- 您可以使用 GLM 技巧来拟合此模型;并不总是有效(可能在数值上不稳定),但它不需要起始值并且比
nls()
更频繁地工作
- 我认为
lm()
和stat_poly_eq()
不会按预期(或者根本不会)使用非线性公式...
模拟数据
(与您的代码相同,但使用 set.seed()
- 此处可能不重要,但很好的做法)
set.seed(101)
x.test <- runif(50,2,8)
y.test <- 0.5^(x.test)
df <- data.frame(x.test, y.test)
尝试 nls 适合您的起始值
通过在 ggplot2
的 外部 拟合任何平滑项来排除故障通常是个好主意,因此您可以通过更少的层来挖掘问题:
nls(y.test ~ lambda/(1+ aii*x.test),
start = list(lambda=1000,aii=-816.39),
data = df)
Error in nls(y.test ~ lambda/(1 + aii * x.test), start = list(lambda = 1000, : singular gradient
好的,还是不行。让我们使用 glm()
来获得更好的起始值:我们使用 inverse-link GLM:
1/y = b0 + b1*x
y = 1/(b0 + b1*x)
= (1/b0)/(1 + (b1/b0)*x)
所以:
g1 <- glm(y.test ~ x.test, family = gaussian(link = "inverse"))
s0 <- with(as.list(coef(g1)), list(lambda = 1/`(Intercept)`, aii = x.test/`(Intercept)`))
这给出了 lambda = -0.09,aii = -0.638(再多做一点工作,我们可能还可以通过查看曲线的起点和比例来弄清楚如何观察这些)。
ggplot(data = df, aes(x=x.test,y=y.test)) +
geom_point(shape=21, fill="white", color="red", size=3) +
stat_smooth(method="nls",
formula = y ~ lambda/ (1 + aii*x),
method.args=list(start=s0),
se=FALSE,color="red") +
stat_smooth(method = "glm",
formula = y ~ x,
method.args = list(gaussian(link = "inverse")),
color = "blue", linetype = 2)