Python中分数次幂的二项式展开
在Scypy/numpy中,是否有一种快速扩展和求解提升为分数次幂的二项式的方法 例如,我想解下面的方程 y*(1+x)^4.8=x^4.5 其中y是已知的(例如1.03) 这需要(1+x)^4.8的二项式展开 我希望对数百万个y值执行此操作,因此我正在寻找一个好的、快速的方法来解决此问题 我尝试过辛展开(和简化),但它似乎不喜欢分数指数。我也在努力学习scipy fsolve模块 任何指向正确方向的指示都将不胜感激 编辑: 到目前为止,我发现的最简单的解决方案是为假设值x(和已知的y)生成一个真值表()。这允许快速插值“真”x值Python中分数次幂的二项式展开,python,math,numpy,scipy,polynomial-math,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)生成一个
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)
编辑:将y=1.03的输出与Woldfram alpha的输出进行比较后,fsolve似乎不会返回复数根。这是一个类似的问题,可能会更有帮助 重新排列方程式:
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
(匿名函数构造):
我认为你不需要二项式展开。对多项式的求值意味着多项式的分解形式比展开形式更好 一般来说,非线性方程的求解可以从符号微分中获益,而对于方程来说,手工求解并不太困难。为导数提供一个分析表达式可以避免解算器必须以数值方式估计导数。您可以编写两个函数:一个返回函数值,另一个返回导数(即此简单一维函数的函数值),如中所述。采用这种方法的一些代码:
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和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)
这表明只要y
低于临界值,每个y
都有两个x
值。当x=ln(15)
且y
值为以下值时,出现y
的最小奇异值:
np.exp(ln_y(15))
0.32556278053267873
因此,您的示例y
值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)
导致错误:
/Users/curt/anaconda/lib/python2.7/site-packages/IPython/kernel/__main__.py:5: RuntimeWarning: invalid value encountered in power
该错误的原因是Python(或numpy)中的
power
函数默认情况下不接受分数指数的负基。你可以通过以复数形式提供幂来解决这个问题,也就是说,写x**(4.5+0j)
而不是x**4.5
,但是你真的对解方程的复数x
感兴趣吗?我认为你需要为函数提供y
;否则,它将如何求解不同的y
?我定义的函数不会求解y,因为y是一个已知的值,我们希望发现x的值,这是fsolve应该做的,但不能,因为这个方程有复杂的根。示例:给定1.03=x^4.5/(1+x)^4.8
求解x。显示x有4个复数值。是的,但在编写时,theFunction
将始终返回相同的值,而不管y
是什么。您的fsolve
语法将使用y
作为根的x
值的初始猜测,而不是作为函数的附加参数。不幸的是,我的微积分技能没有我希望的那么强。我看到您在下面的答案中有返回y*(1+x)**(4.8)/x**(4.5)-1
。我本来会做返回y*(1+x)**4.8-x**4.5
,但我认为我不正确。不,那实际上也是正确的,我在我的版本中尝试了它,但它不起作用。我认为这与数值稳定性有关,尽管我没有证实这一点。如果可以的话,最好将两个大数字相除,而不是相减。
/Users/curt/anaconda/lib/python2.7/site-packages/IPython/kernel/__main__.py:5: RuntimeWarning: invalid value encountered in power