在Python中使用分数幂进行二项式扩展

时间:2015-07-27 19:02:34

标签: python math numpy scipy polynomial-math

是否有一种快速方法可以扩展和解决在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)

2 个答案:

答案 0 :(得分:3)

编辑:在输出与Woldfram alpha的输出比较y = 1.03时,看起来fsolve不会返回复杂的根。 https://stackoverflow.com/a/15213699/3456127是一个类似的问题,可能会有所帮助。

重新排列等式:y = x^4.5 / (1+x)^4.8Scipy.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)

Plot

这表明只要x低于临界值,每yy有两个值。 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值感兴趣?