使用SymPy通过给定的点构造符号插值样条线 [英] Construct a symbolic interpolating spline through given points using SymPy

查看:118
本文介绍了使用SymPy通过给定的点构造符号插值样条线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我从R2上定义的一些简单数据集开始:

Pretend I start with some simple dataset which is defined on R2 follows:

DataPointsDomain = [0,1,2,3,4,5]
DataPointsRange =  [3,6,5,7,9,1]

借助scipy,我可以使用以下方法制作懒惰的多项式样条:

With scipy I can make a lazy polynomial spline using the following:

ScipySplineObject = scipy.interpolate.InterpolatedUnivariateSpline( 
    DataPointsDomain, 
    DataPointsRange, 
    k = 1, )

sympy中的等效对象是什么?

What is the equivalent object in sympy??

SympySplineObject = ...???

(我想定义这个对象并进行分析性的sympy操作,例如对sympy对象进行积分,导数等)

(I want to define this object and do analytic sympy manipulation like taking integrals, derivatives, etc... on the sympy object )

推荐答案

在1.1.1以上的SymPy版本中,包括当前开发版本,有一个内置方法interpolating_spline,它带有四个参数:样条曲线度,变量,域值和范围值.

In SymPy versions above 1.1.1, including the current development version, there is a built-in method interpolating_spline which takes four arguments: the spline degree, the variable, domain values and range values.

from sympy import *
DataPointsDomain = [0,1,2,3,4,5]
DataPointsRange =  [3,6,5,7,9,1]
x = symbols('x')
s = interpolating_spline(3, x, DataPointsDomain, DataPointsRange)

这将返回

Piecewise((23*x**3/15 - 33*x**2/5 + 121*x/15 + 3, (x >= 0) & (x <= 2)),
   (-2*x**3/3 + 33*x**2/5 - 55*x/3 + 103/5, (x >= 2) & (x <= 3)), 
   (-28*x**3/15 + 87*x**2/5 - 761*x/15 + 53, (x >= 3) & (x <= 5)))

是通过给定点的非打结"三次样条.

which is a "not a knot" cubic spline through the given points.

可以使用SymPy构造插值样条线,但这需要一些努力.方法bspline_basis_set返回给定x值的B样条曲线的基础,但是由您自己确定它们的系数.

An interpolating spline can be constructed with SymPy, but this takes some effort. The method bspline_basis_set returns the basis of B-splines for given x-values, but then it's up to you to find their coefficients.

首先,我们需要一个结点列表,它与x值列表(下面的xv)不完全相同.端点xv[0]xv[-1]将出现deg + 1次,其中deg是样条曲线的度数,因为在端点处,所有系数都将值更改(从某值变为零).而且,接近它们的某些x值可能根本不会出现,因为那里的系数不会发生变化(无结"条件).最后,对于偶数度的样条曲线(偏转),内部结位于数据点之间的中间.所以我们需要这个辅助函数:

First, we need the list of knots, which is not exactly the same as the list of x-values (xv below). The endpoints xv[0] and xv[-1] will appear deg+1 times where deg is the degree of the spline, because at the endpoints all the coefficients change values (from something to zero). Also, some of the x-values close to them may not appear at all, as there will be no changes of coefficients there ("not a knot" conditions). Finally, for even-degree splines (yuck) the interior knots are placed midway between data points. So we need this helper function:

from sympy import *
def knots(xv, deg):
    if deg % 2 == 1:
        j = (deg+1) // 2
        interior_knots = xv[j:-j]
    else:
        j = deg // 2
        interior_knots = [Rational(a+b, 2) for a, b in zip(xv[j:-j-1], xv[j+1:-j])]
    return [xv[0]] * (deg+1) + interior_knots + [xv[-1]] * (deg+1)

bspline_basis_set方法获得b样条曲线后,必须插入x值并形成一个线性系统,从中可以找到系数coeff.最后构建样条线:

After getting b-splines from bspline_basis_set method, one has to plug in the x-values and form a linear system from which to find the coefficients coeff. At last, the spline is constructed:

xv = [0, 1, 2, 3, 4, 5]
yv =  [3, 6, 5, 7, 9, 1]
deg = 3
x = Symbol("x")
basis = bspline_basis_set(deg, knots(xv, deg), x)
A = [[b.subs(x, v) for b in basis] for v in xv]
coeff = linsolve((Matrix(A), Matrix(yv)), symbols('c0:{}'.format(len(xv))))
spline = sum([c*b for c, b in zip(list(coeff)[0], basis)])
print(spline)

此样条线是一个SymPy对象.这是3级学位:

This spline is a SymPy object. Here it is for degree 3:

3*Piecewise((-x**3/8 + 3*x**2/4 - 3*x/2 + 1, (x >= 0) & (x <= 2)), (0, True)) + Piecewise((x**3/8 - 9*x**2/8 + 27*x/8 - 27/8, (x >= 3) & (x <= 5)), (0, True)) + 377*Piecewise((19*x**3/72 - 5*x**2/4 + 3*x/2, (x >= 0) & (x <= 2)), (-x**3/9 + x**2 - 3*x + 3, (x >= 2) & (x <= 3)), (0, True))/45 + 547*Piecewise((x**3/9 - 2*x**2/3 + 4*x/3 - 8/9, (x >= 2) & (x <= 3)), (-19*x**3/72 + 65*x**2/24 - 211*x/24 + 665/72, (x >= 3) & (x <= 5)), (0, True))/45 + 346*Piecewise((x**3/30, (x >= 0) & (x <= 2)), (-11*x**3/45 + 5*x**2/3 - 10*x/3 + 20/9, (x >= 2) & (x <= 3)), (31*x**3/180 - 25*x**2/12 + 95*x/12 - 325/36, (x >= 3) & (x <= 5)), (0, True))/45 + 146*Piecewise((-31*x**3/180 + x**2/2, (x >= 0) & (x <= 2)), (11*x**3/45 - 2*x**2 + 5*x - 10/3, (x >= 2) & (x <= 3)), (-x**3/30 + x**2/2 - 5*x/2 + 25/6, (x >= 3) & (x <= 5)), (0, True))/45

您可以通过

spline.diff(x)

您可以集成它:

integrate(spline, (x, 0, 5))   #  197/3

您可以对其进行绘制,并看到它确实对给定值进行了插值:

You can plot it and see it indeed interpolates the given values:

plot(spline, (x, 0, 5))

我什至将它们一起绘制了1,2,3度:

I even plotted them for degrees 1,2,3 together:

免责声明:

  • 上面给出的代码在 SymPy的开发版本中工作,并且应在1.1.2中工作. +;以前的版本中B样条方法存在一个错误.
  • 其中一些需要花费大量时间,因为逐段对象很慢.以我的经验,基础建设花费的时间最长.
  • The code given above works in the development version of SymPy, and should work in 1.1.2+; there was a bug in B-spline method in previous versions.
  • Some of this takes a good deal of time because Piecewise objects are slow. In my experience, the basis construction takes longest.

这篇关于使用SymPy通过给定的点构造符号插值样条线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆