[英]To find the distance between two roots in R
假设我有一个在间隔I上定义好的函数f(x)。我想找到f(x)的最大和最小根,然后取它们的差。 有什么好的编程方法?
确切地说,f在最坏的情况下可能是一个有理函数,如(1 + x)/(1-x)。 大多数时候,它应该是(高次)多项式。 我只需要在某种程度上精确地知道结果。
我在考虑以下方面:
将f(x)转换为R可以识别的形式。(我可以)
使用R列出I上f(x)的所有根(我发现uniroot函数仅给我一个根)
使用R查找列表中的最大和最小元素(将其转换为向量后应该可以)
取二根之差。 (应该是微不足道的)
我被困在步骤(2)上,我不知道该怎么办。 我的教授给出了一种残酷的解决方案,建议我这样做:
将间隔I分为一百万个。
在每个端点上评估f,找到f> = 0的端点。
从步骤2中形成的集合中选择最大和最小元素。
拿他们之间的区别。
我觉得这种方法效率不高,一般来说可能不适用于所有f,但是即使对于二次运算,我也难以实现。 我也不知道如何执行步骤(2)。 所以我想问一个提示或一些玩具的例子。
此时,我正在尝试实现以下代码:
Y=rep(0,200)
dim(Y)=c(100,2)
for(i in 1:100){
X=rnorm(9,0,1)
Z=rnorm(16,0,1)
a=0.64
b=a*sum(Z^2)/sum(X^2)
root_intervals <- function(f, interval, n = 1e6) {
xvals <- seq(interval[1], interval[2], length = n)
yvals <- f(xvals)
ypos <- yvals > 0
x1 <- which(tail(ypos, -1) != head(ypos, -1))
x2 <- x1 + 1
## so all the zeroes we can see are between x1 and x2
return(cbind(xvals[x1], xvals[x2]))
}
在这里一切正常,但是当我尝试通过以下方式将根提取到Y [i,1],Y [i,2]时:
Y[i,1]=(ri<-root intervals(function(x)(x/(a*x+b))^{9/2}*(1/((1-a)+a*(1-a)/b*x))^4-0.235505, c(0,40),n=1e6)[1]
我发现我无法对其进行评估。 R不断告诉我
Error: unexpected symbol in:
"}
Y[i,1]=(ri<-root intervals"
我被卡住了。 当我感到迷茫时,我非常感谢大家的帮助。
我使用plot函数多次检查了函数的表达式,并且没有语法错误。 我也相信间隔中所有X的定义都很好。
这应该为您提供蛮力解决方案的良好开端。 没错,这并不优雅,但是对于相对简单的单变量函数而言,评估一百万点是微不足道的。
root_intervals <- function(f, interval, n = 1e6) {
xvals <- seq(interval[1], interval[2], length = n)
yvals <- f(xvals)
ypos <- yvals > 0
x1 <- which(ypos[-1] != head(ypos, -1))
x2 <- x1 + 1
## so all the zeroes we can see are between x1 and x2
return(cbind(xvals[x1], xvals[x2]))
}
此函数返回x值的两列矩阵,其中该函数在第1列和第2列之间更改符号:
f1 <- function (x) 0.05 * x^5 - 2 * x^4 + x^3 - x^2 + 1
> (ri <- root_intervals(f1, c(-10, 10), n = 1e6))
[,1] [,2]
[1,] -0.6372706 -0.6372506
[2,] 0.8182708 0.8182908
> f1(ri)
[,1] [,2]
[1,] -3.045326e-05 6.163467e-05
[2,] 2.218895e-05 -5.579081e-05
Wolfram Alpha按指定的时间间隔确认结果。
顶部和底部将是找到的最小和最大间隔。 这些间隔(函数改变符号的interval
)正是uniroot
想要的interval
,因此您可以使用它来求解(更多)确切的根。 当然,如果函数在一个时间间隔(或任何偶数次)内两次更改符号,它将不会被拾取,因此请选择大n
!
看起来您试图定义一堆函数,但是您的编辑存在语法错误。 这是我认为您要尝试执行的操作:(第一部分可能需要更多工作才能正常工作)
my_funs <- list()
Y=rep(0,200)
dim(Y)=c(100,2)
for(i in 1:100){
X=rnorm(9,0,1)
Z=rnorm(16,0,1)
a=0.64
b=a*sum(Z^2)/sum(X^2)
my_funs[[i]] <- function(x){(x/(a*x+b))^{9/2}*(1/((1-a)+a*(1-a)/b*x))^4-0.235505}
}
这是在您生成的第一个函数上使用root_intervals。
> root_intervals(my_funs[[1]], interval = c(0, 40))
[,1] [,2]
[1,] 0.8581609 0.8582009
[2,] 11.4401314 11.4401714
注意输出矩阵 ,函数的根在第一和第二列之间。 作为矩阵,您不能将其分配给向量。 如果要使用单个根, uniroot
每行中使用uniroot
设置上限和下限。 这留给读者练习。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.