是否有一种快速方法可以扩展和解决在Scypy / numpy中提升为分数幂的二项式?
例如,我希望解决以下等式
y *(1 + x)^ 4.8 = x ^ 4.5
其中y是已知的(例如1.03)。
这需要二项式扩展(1 + x)^ 4.8。
我希望为数百万的y值做到这一点,所以我用一个很好的快速方法来解决这个问题。
我尝试过扩展(和简化),但它似乎不喜欢分数指数。我也在使用scipy fsolve模块。
任何指向正确方向的人都会受到赞赏。
编辑:
到目前为止,我发现最简单的解决方案是为假设的x(和已知的y)值生成一个真值表(https://en.wikipedia.org/wiki/Truth_table)。这允许快速插入“真实”' x值。
y_true = np.linspace(7,12, 1e6)
x = np.linspace(10,15, 1e6)
a = 4.5
b = 4.8
y = x**(a+b) / (1 + x)**b
x_true = np.interp(y_true, y, x)
答案 0 :(得分:3)
编辑:在输出与Woldfram alpha的输出比较y = 1.03时,看起来fsolve不会返回复杂的根。 https://stackoverflow.com/a/15213699/3456127是一个类似的问题,可能会有所帮助。
重新排列等式:y = x^4.5 / (1+x)^4.8
。
Scipy.optimize.fsolve()
需要一个函数作为它的第一个参数。
或者:
from scipy.optimize import fsolve
import math
def theFunction(x):
return math.pow(x, 4.5) / math.pow( (1+x) , 4.8)
for y in millions_of_values:
fsolve(theFunction, y)
或使用lambda
(匿名函数构造):
from scipy.optimize import fsolve
import math
for y in millions_of_values:
fsolve((lambda x: (math.pow(x, 4.5) / math.pow((1+x), 4.8))), y)
答案 1 :(得分:2)
我认为你不需要进行二项式扩展。用于评估多项式的Horner's method意味着有一个多项式的因式形式比扩展形式更好。
一般来说,非线性方程求解可以从符号微分中受益,这对于你的方程并不是很难手工完成。提供导数的解析表达式使得求解器不必在数值上估计导数。您可以编写两个函数:一个返回函数的值,另一个返回派生函数(即此简单1-D函数的函数的Jacobian),如the docs for scipy.optimize.fsolve()中所述。一些采用这种方法的代码:
import timeit
import numpy as np
from scipy.optimize import fsolve
def the_function(x, y):
return y * (1 + x)**(4.8) / x**(4.5) - 1
def the_derivative(x, y):
l_dh = x**(4.5) * (4.8 * y * (1 + x)**(3.8))
h_dl = y * (1 + x)**(4.8) * 4.5 * x**3.5
square_of_whats_below = x**9
return (l_dh - h_dl)/square_of_whats_below
print fsolve(the_function, x0=1, args=(0.1,))
print '\n\n'
print fsolve(the_function, x0=1, args=(0.1,), fprime=the_derivative)
%timeit fsolve(the_function, x0=1, args=(0.1,))
%timeit fsolve(the_function, x0=1, args=(0.1,), fprime=the_derivative)
...给我这个输出:
[ 1.79308495]
[ 1.79308495]
10000 loops, best of 3: 105 µs per loop
10000 loops, best of 3: 136 µs per loop
表明在这种特殊情况下,分析差异不会导致任何加速。我的猜测是函数的数值近似涉及更容易计算的函数,如乘法,平方和/或加法,而不是像分数幂函数那样的函数。
您可以通过获取等式的对数并绘制它来获得额外的简化。使用小代数,您应该能够获得ln_y
的显式函数,即y
的自然对数。如果我正确地完成了代数:
def ln_y(x):
return 4.5 * np.log(x/(1.+x)) - 0.3 * np.log(1.+x)
你可以绘制这个函数,我已经为lin-lin和log-log图绘制了这些函数:
%matplotlib inline
import matplotlib.pyplot as plt
x_axis = np.linspace(1, 100, num=2000)
f, ax = plt.subplots(1, 2, figsize=(8, 4))
ln_y_axis = ln_y(x_axis)
ax[0].plot(x_axis, np.exp(ln_y_axis)) # plotting y vs. x
ax[1].plot(np.log(x_axis), ln_y_axis) # plotting ln(y) vs. ln(x)
这表明只要x
低于临界值,每y
个y
有两个值。 y
的{{1}}的最小奇异值出现在x=ln(15)
且值y
为:
np.exp(ln_y(15))
0.32556278053267873
因此,y
的{{1}}值示例导致1.03
没有(真实)解决方案。
我们从以前的x
电话中概括了我们从情节中看出的这种行为:
scipy.optimize.fsolve()
这表明,当print fsolve(the_function, x0=1, args=(0.32556278053267873,), fprime=the_derivative)
[ 14.99999914]
为x=1
时,最初猜测y
会给出0.32556278053267873
作为解决方案。尝试更大的x=15
值:
y
导致错误:
print fsolve(the_function, x0=15, args=(0.35,), fprime=the_derivative)
错误的原因是Python(或numpy)中的/Users/curt/anaconda/lib/python2.7/site-packages/IPython/kernel/__main__.py:5: RuntimeWarning: invalid value encountered in power
函数默认情况下不接受小数指数的负基数。您可以通过将权力作为复数提供来解决这个问题,即写power
而不是x**(4.5+0j)
,但您是否真的对可以解决等式的复杂x**4.5
值感兴趣?