使用 numpy 多项式便利类 (>1.14) 给出拟合多项式
p = np.polynomial.Polynomial.fit(...)
保存和加载此拟合的最佳方法是什么?
重现该对象需要三个参数,即
p.coef
、p.domain
和p.window
。
请参阅这个问题,了解仅加载系数时会发生什么。
可以将所有三个文件保存为不同的文件并重新加载它们,但这既麻烦又烦人。
我的两个最初想法是将整个对象保存为 0d 数组
np.save("polyfit.npy", p, allow_pickle=True)
np.load("polyfit.npy", allow_pickle=True).item()
或者作为一维数组,因为老实说我必须查找
.item()
才能访问该元素。
np.save("polyfit.npy", [p], allow_pickle=True)
np.load("polyfit.npy", allow_pickle=True)[0]
这两种方式都需要使用pickle模块,这会导致跨版本/平台问题,并且是潜在的安全问题。所以我宁愿避免使用它。
有没有推荐的方法来做到这一点?
该文档似乎没有包含任何好的提示
https://numpy.org/doc/stable/reference/routines.polynomials.html
https://numpy.org/doc/stable/reference/routines.polynomials.classes.html
制作聚合物系列样品:
In [432]: x=np.linspace(0,1,10); y = x**3
In [433]: p = np.polynomial.Polynomial.fit(x,x**3, 3); p
Out[433]:
Polynomial([0.125, 0.375, 0.375, 0.125], domain=[0., 1.], window=[-1., 1.], symbol='x')
所以它是一个具有几个属性的类实例,这些属性是数组和列表。 我们可以使用
p(x)
创建新的拟合数组:
In [434]: np.allclose(x**3,p(x))
Out[434]: True
正如您所注意到的,我们可以保存并加载它,从而允许pickle:
In [436]: np.save('test.npy', p); pp = np.load('test.npy',allow_pickle=True)
In [437]: pp
Out[437]:
array(Polynomial([0.125, 0.375, 0.375, 0.125], domain=[0., 1.], window=[-1., 1.], symbol='x'),
dtype=object)
这是一个单项对象 dtype 数组,包含 Poly 系列实例。 我们通过
.item()
: 得到这个实例
In [438]: np.allclose(x**3,pp.item()(x))
Out[438]: True
我们可以使用 3 个属性重新创建一个多边形系列:
In [439]: np.polynomial.Polynomial(p.coef,p.domain, p.window)
Out[439]:
Polynomial([0.125, 0.375, 0.375, 0.125], domain=[0., 1.], window=[-1., 1.], symbol='x')
并对
pp.item()
的属性执行相同操作
In [440]: p1=pp.item(); np.polynomial.Polynomial(p1.coef,p1.domain, p1.window)
Out[440]:
Polynomial([0.125, 0.375, 0.375, 0.125], domain=[0., 1.], window=[-1., 1.], symbol='x')
另一种保存方式是使用
savez
,将多个 npy
文件保存在 zip
存档中:
In [441]: np.savez('test.npz', **vars(p))
In [442]: dd = np.load('test.npz')
In [443]: list(dd.keys())
Out[443]: ['coef', 'domain', 'window', '_symbol']
dd
不是多边形系列,但 3 个键可用于重新创建一个:
In [444]: np.polynomial.Polynomial(dd['coef'],dd['domain'], dd['window'])
Out[444]:
Polynomial([0.125, 0.375, 0.375, 0.125], domain=[0., 1.], window=[-1., 1.], symbol='x')
p
的三个属性都是数组,所以savez/load
不使用pickle
。