微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何创建与 scipy 一起使用的 n 个参数的方程生成器?

如何解决如何创建与 scipy 一起使用的 n 个参数的方程生成器?

我正在将我的代码从 MatLab 移植到 Python,我做了一个巧妙的技巧,但无法重现:

function [Equation,EquationComponents] = BezierEquation(n)
syms t x01 x02 x03 x04 x05 x06 x07 x08 x09 x10 x11 x12 x13 x14 x15 x16 x17 x18 x19 x20 x21 x22 x23 x24 x25 x26 x27 x28 x29 x30 x31 x32 x33 x34 x35 x36 x37 x38 x39 x40 x41;
xVar=[x01,x02,x03,x04,x05,x06,x07,x08,x09,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19,x20,x21,x22,x23,x24,x25,x26,x27,x28,x29,x30,x31,x32,x33,x34,x35,x36,x37,x38,x39,x40,x41];
for i = 0:n
    B(:,i+1)= nchoosek(n,i);
    Pol(:,i+1)= (1-t)^(n-i)*t^i;
    xVar2(:,i+1)=xVar(:,i+1);
end
EquationComponents=[xVar2;B;Pol];
Equation=sum(B.*xVar2.*Pol);
end

它的作用是生成一个具有 n 个参数的 n 次贝塞尔方程。用 n=30 或 n=40 手动编写这个方程会很痛苦。

我目前正在尝试对 scipy 做同样的事情并将其用于 curve_fit,但我不明白如何创建可变数量参数的方程。我目前有此代码,其中包含 n=5 的可工作的手写示例。如何为任何 n 生成? curve_fit 似乎不明白 co 不是标量。

import numpy as np
from scipy.special import comb
from scipy.optimize import curve_fit

class Bezier(object):
    def __init__(self,n):
        self.n = n
        self.i = np.arange(0,n + 1)
        self.n_minus_i = np.flip(self.i)
        self.b = comb(n,self.i)

    def generate_equation(self,x,co):
        b = self.b
        i = self.i
        eq = []
        for j,B in enumerate(b):
            eq.append(B * (1 - x)**(self.n - i[j]) * x**i[j] * co[j])
        return np.sum(eq)

    def equation_5(self,a,b,c,d,e,f):
        i = np.arange(0,6)
        B = comb(5,i)
        return a*B[0]*(1-x)**(5-i[0])*x**i[0] + b*B[1]*(1-x)**(5-i[1])*x**i[1] + c*B[2]*(1-x)**(5-i[2])*x**i[2] + d*B[3]*(1-x)**(5-i[3])*x**i[3] + e*B[4]*(1-x)**(5-i[4])*x**i[4] + f*B[5]*(1-x)**(5-i[5])*x**i[5]

更新:

通过查看 sympy 库,我用它做了一个简单的解决方案。我正在分享它,但我想保持这个问题的开放性,以寻求没有同情的解决方案。也许使用 numpy 数组而不是变量,或者是否有办法通过解包 n 个参数来创建 lambda 函数。相当于在 lambdify([x,*list_of_params],equation,'numpy') 中解包但没有同情的东西。

    import numpy as np
    from scipy.special import comb
    from scipy.optimize import curve_fit
    from sympy import symbols
    from sympy import lambdify
    
def bezier_generator(n):
    if n > 15:
        return
    i = np.arange(0,n + 1)
    b = comb(n,i)
    x,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15 = symbols(
        "x,c15")
    co = [c0,c15]

    eq = np.sum(b * (1 - x) ** (n - i) * x ** i * co[:n + 1])
    func = lambdify([x,*co[:n + 1]],eq,'numpy')
    return func

解决方法

如果我理解正确:

我想在没有同情的情况下保持这个问题的解决方案。也许使用 numpy 数组而不是变量

然后听起来你想从简单的 Python 实现开始(将二项式函数外包给一个已经实现它的库,比如 scipy),并提升仍然不足以完成你最终用它做的事情的部分:

from scipy.stats import binom

def evaluate_bezier_at(t,coords):
    mt = 1 - t
    sum = 0
    n = len(coords)
    for (i,w_i) in enumerate(coords):
        sum += w_i * binom(n,i) * (mt ** (n-i)) * (t ** i)
    return sum

(当然还有速度优化,但如果您使用 30 度以上的 Bezier 曲线,我假设您不会编写需要达到最佳性能代码的代码:没有人需要 Beziers这么高的学位=)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。