sympy
一.前言
sympy是一个符号计算系统
符号计算:数学对象是精确表示的,而不是近似的,并且具有未计算变量的数学表达式以符号形式保留。
举个例子:
使用python自带数学函数计算库math计算sqrt(8)
import math
math.sqrt(8)
输出:2.82842712475
使用sympy库计算sqrt(8)
import sympy
sympy.sqrt(8)
输出:2*sqrt(2)
总结:
对于math库是求值,如果求不出精确值就求近似
对于 sympy库求值,如果求不出精确值就以符号形式表示
二.sympy库基本函数使用
1.基础函数
1.1.symbols函数
sympy.symbols()
用于创建符号变量的函数。
定义数学表达式中的未知数,比如变量 x, y 等。
实例代码如下:
import sympy
x,y = sympy.symbols('x y')
f_x_y = x+2*y
print(f_x_y)
输出:x+2*y
此时创建了符号变量后,f_x_y可以像数学算式一样进行加减
如
:
import sympy
x,y = sympy.symbols('x y')
f_x_y = x+2*y
f_x_y -= x
print(f_x_y )
输出:2*y
1.2.expand函数
用于展开代数表达式,比如把乘法形式的多项式展开。
如
:
import sympy
x,y = sympy.symbols("x y")
f_x_y = (x + y)**2
print(sympy.expand(f_x_y))
输出:x**2 + 2*x*y + y**2
1.3.factor函数
用于因式分解代数表达式,把表达式转化为乘法形式。
如
:
import sympy
x,y = sympy.symbols("x y")
f_x_y = x**2 + 2*x*y + y**2
print(sympy.factor(f_x_y))
输出:(x + y)**2
2.sympy库的求导函数
2.1diff函数
sympy.diff()
一阶导数
from sympy import symbols, diff
x = symbols('x')
f = x**3 + 2*x**2 + x
df = diff(f, x)
print(df) # 输出: 3*x**2 + 4*x + 1
输出: 3*x**2 + 4*x + 1
高阶导数
from sympy import symbols, diff,expand
x = symbols('x')
f = x**3 + 2*x**2 + x
df = diff(f, x,2)
print(expand(df))
输出: 6*x + 4
多个变量的偏导数
from sympy import symbols, diff
x, y = symbols('x y')
f = x**2 * y + x * y**2
df_dx = diff(f, x) # 对 x 求偏导
df_dy = diff(f, y) # 对 y 求偏导
输出:
2*x*y + y**2 | x**2 + 2*x*y
2.2subs函数
sympy.subs()
是 SymPy 中用来替换表达式中的变量或子表达式的方法
变量代值
from sympy import symbols
x = symbols('x')
expr = x**2 + 2*x + 1
print(expr.subs(x, 3))
输出:16
变量互换
from sympy import symbols
y = symbols('y')
x = symbols('x')
f = x**2 + 2*x + 1
print(f.subs(x, y))
输出: y**2 + 2*y + 1
多个同时替换
from sympy import symbols
x, y = symbols('x y')
f = x**2 + y**2
print(f.subs({x: 1, y: 2}))
输出: 5
2.3solv函数
sympy.solve()
是 SymPy 中用于 **解方程(组)**的函数
解方程
from sympy import symbols, solve, Eq
x = symbols('x')
f = x**2 - 4
print(solve(f, x) )
输出:[-2, 2]
注意:
在数学中,方程的解指的是“让表达式等于 0 的变量值 相当于f(x)=0
三.使用sympy库实现对极小值的求解
1.利用导数为0求极值
代码如下:
import sympy
x = sympy.symbols("x")
y = x**2
dev = sympy.diff(y,x) #求导
x_r = sympy.solve(dev,x) #解方程
y_min = y.subs(x,x_r[0])
print(y_min)
x = sympy.symbols("x")
y = sympy.sin(x)
dev = sympy.diff(y,x)
x_r = sympy.solve(dev,x)
print(x_r)
y_1 = y.subs(x,x_r[0])
y_2= y.subs(x,x_r[1])
print(y_1,y_2)
2.工程逼近法
工程逼近法是一种基于简化模型、经验数据或数值计算的近似求解方法
我们已经知道 f(x)=x² 的图像
在x坐标轴上取一点x,将该点的值带入函数求得y值
假设一个步长step=0.01(步长越小越精确)
将x对步长进行加或减使得y值减小,这样就可以不断逼近于极小值
import sympy
x = sympy.symbols('x')
y = x**2
x_value = 10 #取一点x
y_value = y.subs(x,x_value) #求得y值
step = 0.01#设置步长
while 1 :
x_value = x_value -step
if y.subs(x,x_value)<=y_value: #判断是否逼近极小值,逼近就继续循环
y_value = y.subs(x,x_value)
continue
else: #远离退出循环
break
print(y_value,x_value) #得到近似值
3.梯度下降法
数学类比:梯度 = 多维导数
在一维中,导数 f’(x) 是“切线斜率”。
在多维中,梯度 ∇f 就是每个方向的“切线斜率”合集,是一个向量。
如图
如果要找函数的极小值,我们可以用自变量x-导数 f '(x)
为什么呢?
导数 f(x)'相当于点(x , f(x))处做一条切线
此时我们让自变量x-导数 f '(x),重复此操作斜率就如图不断下降,自变量x逼近于极小值x的点,当斜率为0时,自变量x就等于极小值x
根据思路代码如下:
import sympy
import random
x = sympy.symbols('x')
y = x**2
dev = sympy.diff(y,x)
x_value = random.randint(-100,100) #随机一个起始点
iter = 10000
lr = 0.01 #学习率 下降的步长
for i in range(iter):
x_value = x_value - dev.subs(x,x_value)*lr #逼近
print(y.subs(x,x_value),x_value)
注意:
学习率不能为1
拿 ( f(x) = x^2 ) 举例:
函数:
( f(x) = x^2 )
导数:
( f’(x) = 2x )
当 lr = 1 时:
x= x-2x
x=-x
-x = -x+2x
-x=x
也就是说每一步都变成 “取反”:在不断震荡,无法收敛
所以学习率 lr <1