scipy.interpolate - 离散数据求根&两组离散数据求交点
第一部分:离散数据求根
import numpy as np
np.set_printoptions(linewidth=1000)
import matplotlib.pyplot as plt
# 支持中文
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
from scipy import interpolate
# 离散点坐标
X = np.array([5, 7, 12, 13, 14, 16, 18, 22])
# X必须是严格单调递增数据,判断方法:if np.all(np.diff(X)>0)
Y = np.array([2, 6, 5, 3, 10, -3, 6, 8])
# 显示离散点
plt.figure(figsize=(12, 6))
plt.title('两组离散数据与零线')
plt.xlabel('X')
plt.ylabel('Y')
plt.plot(
X,
Y,
linestyle= 'dashed',
marker='*',
label='X,Y离散数据')
plt.plot(
[X[0], X[-1]],
[0, 0],
linestyle= '-',
marker='',
color = 'black',
label='零线')
plt.legend()
plt.show()
# 根据离散点XY构造样条曲线
# BSpline(builtins.object)
# tck: A spline, as returned by `splrep` or a BSpline object.
tck = interpolate.make_interp_spline(x=X, y=Y, k=1) # roots = [ 3. 15.53846154 16.66666667]
# tuple(object)
# tck: A spline, as returned by `splrep` or a BSpline object.
#tck = interpolate.splrep(x=X, y=Y, k=1, s=0) # roots = [ 3. 15.53846154 16.66666667]
# k为样条曲线的阶数,k=1为线性,k=2为二次多项式,...
# 转换
# class PPoly(_PPolyBase); Construct a piecewise polynomial from a spline
piecewise_polynomial = interpolate.PPoly.from_spline(tck, extrapolate=None)
# 求根
roots_X_ = piecewise_polynomial.roots() # class ndarray(builtins.object)
# 在X范围内筛选根
roots_X = roots_X_[np.where(np.logical_and(roots_X_>=X[0], roots_X_<=X[-1]))]
print(roots_X)
[15.53846154 16.66666667]
# 显示样条函数
X_view = np.linspace(X[0], X[-1], 1080) # 类似于分标率080p
Y_view = piecewise_polynomial(X_view)
# 显示样条函数
plt.figure(figsize=(12, 6))
plt.title('离散数据与零线')
plt.xlabel('X')
plt.ylabel('Y')
plt.plot(
X,
Y,
linestyle= '',
marker='*',
label='X,Y离散数据')
plt.plot(
X_view,
Y_view,
linestyle= '-',
label='样条曲线(线性)')
plt.plot(
[X[0], X[-1]],
[0, 0],
linestyle= '-',
marker='',
color = 'black',
label='零线')
plt.legend()
plt.show()
# 封装成函数便于调用
def numpy_scipy_find_roots_by_XY(X, Y, print_=0, plot=0):
# X必须为严格单调递增数据
if np.all(np.diff(X) > 0) == True:
pass
else:
raise Exception('X必须为严格单调递增数据!')
# 根据离散点XY构造样条曲线
# BSpline(builtins.object)
# tck: A spline, as returned by `splrep` or a BSpline object.
tck = interpolate.make_interp_spline(x=X, y=Y, k=1) # roots = [ 3. 15.53846154 16.66666667]
# tuple(object)
# tck: A spline, as returned by `splrep` or a BSpline object.
#tck = interpolate.splrep(x=X, y=Y, k=1, s=0) # roots = [ 3. 15.53846154 16.66666667]
# k为样条曲线的阶数,k=1为线性,k=2为二次多项式,...
# 转换
# class PPoly(_PPolyBase); Construct a piecewise polynomial from a spline
piecewise_polynomial = interpolate.PPoly.from_spline(tck, extrapolate=None)
# 求根
roots_X_ = piecewise_polynomial.roots() # class ndarray(builtins.object)
# 在X范围内筛选根
roots_X = roots_X_[np.where(np.logical_and(roots_X_>=X[0], roots_X_<=X[-1]))]
if print_ == 1:
print(roots_X)
if plot == 1:
# 显示样条函数
X_view = np.linspace(X[0], X[-1], 1080) # 类似于分标率080p
Y_view = piecewise_polynomial(X_view)
# 显示样条函数
plt.figure(figsize=(12, 6))
plt.title('离散数据与零线')
plt.xlabel('X')
plt.ylabel('Y')
plt.plot(
X,
Y,
linestyle= '',
marker='*',
label='X,Y离散数据')
plt.plot(
X_view,
Y_view,
linestyle= '-',
label='样条曲线(线性)')
plt.plot(
[X[0], X[-1]],
[0, 0],
linestyle= '-',
marker='',
color = 'black',
label='零线')
plt.legend()
plt.show()
return roots_X
# 调用
roots_X = numpy_scipy_find_roots_by_XY(X=X, Y=Y, print_=1, plot=1)
[15.53846154 16.66666667]
第二部分:两组离散数据求交点
# 寻找X1、X2的公共定义域
def numpy_find_commen_definitional_domain_X_by_X1X2(
X1 = np.array([1, 1.8, 3, 4, 5]),
X2 = np.array([2, 3.2, 4.5, 5.1, 6, 8, 11])
):
X1.sort()
X2.sort()
a = np.max([X1[0], X2[0]])
b = np.min([X1[-1], X2[-1]])
X_full = np.append(X1, X2)
X_full = np.array(list(set(X_full))) # 去重
X_full.sort()
X_commen = X_full[np.where(np.logical_and(X_full>=a, X_full<=b))]
return X_commen # [2. 3. 3.2 4. 4.5 5. ]
# 两组离散数据点(#不允许线段有重合!)
X1 = [1, 1.8, 3, 6.5, 12]
Y1 = [5, 5, 9, 6.2, 5]
X2 = [1, 3.2, 4.5, 5.1, 6, 8, 11] # 2
Y2 = [8, 5, 5, 8, 3, 5, 4]
# 显示离散点(#不允许线段有重合!)
plt.figure(figsize=(12, 6))
plt.title('两组离散数据')
plt.xlabel('X')
plt.ylabel('Y')
plt.plot(
X1,
Y1,
linestyle= 'dashed',
marker='*',
label='X1,Y1离散数据')
plt.plot(
X2,
Y2,
linestyle= 'dashed',
marker='*',
label='X2,Y2离散数据')
plt.legend()
plt.show()
# 寻找公共定义域(严格单调递增数据)
X_new = numpy_find_commen_definitional_domain_X_by_X1X2(X1=X1, X2=X2)
print(X_new)
[ 1. 1.8 3. 3.2 4.5 5.1 6. 6.5 8. 11. ]
Y1_new = np.interp(X_new, X1, Y1)
Y2_new = np.interp(X_new, X2, Y2)
Y_new = Y1_new - Y2_new # 作差
# 两离散数据的交点
inersections_X = numpy_scipy_find_roots_by_XY(X=X_new, Y=Y_new, plot=0)
inersections_Y = np.interp(inersections_X, X1, Y1)
print(inersections_X, inersections_Y) # 3个交点
[2.20645161 4.98275862 5.24299065] [6.35483871 7.4137931 7.20560748]
# 封装成函数便于调用
# 两组离散曲线求交点
def numpy_scipy_find_inersections_by_X1Y1X2Y2(X1, Y1, X2, Y2, print_=0, plot=0, xlabel='X', ylabel='Y'):
# X1、X2必须为严格单调递增数据
if np.all(np.diff(X1) > 0) == True:
pass
else:
raise Exception('X1必须为严格单调递增数据!')
if np.all(np.diff(X2) > 0) == True:
pass
else:
raise Exception('X2必须为严格单调递增数据!')
# 寻找公共定义域(严格单调递增数据)
X_new = numpy_find_commen_definitional_domain_X_by_X1X2(X1=X1, X2=X2)
#print(X_new)
Y1_new = np.interp(X_new, X1, Y1)
Y2_new = np.interp(X_new, X2, Y2)
Y_new = Y1_new - Y2_new
inersections_X = numpy_scipy_find_roots_by_XY(X=X_new, Y=Y_new, print_=print_, plot= plot)
inersections_Y = np.interp(inersections_X, X1, Y1)
if print_ == 1:
print(inersections_X, inersections_Y)
if plot == 1:
# 显示曲线
plt.figure(figsize=(12, 6))
plt.title('两组离散数据的交点')
plt.xlabel(xlabel)
plt.ylabel(ylabel)
plt.plot(
X1,
Y1,
linestyle= '-',
marker='*',
label='X1,Y1离散数据')
plt.plot(
X2,
Y2,
linestyle= '-',
marker='*',
label='X2,Y2离散数据')
plt.legend()
plt.show()
return inersections_X, inersections_Y
inersections_X, inersections_Y = numpy_scipy_find_inersections_by_X1Y1X2Y2(X1, Y1, X2, Y2, plot=1, print_=1)
[2.20645161 4.98275862 5.24299065]
[2.20645161 4.98275862 5.24299065] [6.35483871 7.4137931 7.20560748]