如何在没有 for 循环的情况下调用 numpy 函数列表?
How do I call a list of numpy functions without a for loop?
我正在做数据分析,涉及最小化一组点和相应的一组正交函数之间的最小二乘误差。换句话说,我采用一组 y 值和一组函数,并尝试将 x 值归零,使所有函数最接近其相应的 y 值。一切都在 'data_set' class 中完成。我要比较的函数都存储在一个列表中,我正在使用 class 方法来计算所有函数的总 lsq-error:
self.fits = [np.poly1d(np.polyfit(self.x_data, self.y_data[n],10)) for n in range(self.num_points)]
def error(self, x, y_set):
arr = [(y_set[n] - self.fits[n](x))**2 for n in range(self.num_points)]
return np.sum(arr)
当我的时间比数据多得多时,这很好,但现在我要获取数千个 x 值,每个 x 值都有一千个 y 值,并且 for
循环慢得令人无法接受。我一直在尝试使用 np.vectorize
:
#global scope
def func(f,x):
return f(x)
vfunc = np.vectorize(func, excluded=['x'])
…
…
#within data_set class
def error(self, x, y_set):
arr = (y_set - vfunc(self.fits, x))**2
return np.sum(arr)
func(self.fits[n], x)
只要 n
有效就可以正常工作,据我所知 docs,vfunc(self.fits, x)
应该等同于
[self.fits[n](x) for n in range(self.num_points)]
而是抛出:
ValueError: cannot copy sequence with size 10 to array axis with dimension 11
10 是多项式拟合的次数,11(根据定义)是其中的项数,但我不知道为什么它们会出现在这里。如果我更改装配顺序,错误消息会反映更改。似乎 np.vectorize
将 self.fits
的每个元素作为列表而不是 np.poly1d
函数。
无论如何,如果有人可以帮助我更好地理解 np.vectorize
,或者建议另一种方法来消除该循环,那就太棒了。
由于所讨论的函数都具有非常相似的结构,我们可以在提取多边形系数后 "manually" 进行矢量化。其实函数就是那么一个相当简单的one-liner,eval_many
如下:
import numpy as np
def poly_vec(list_of_polys):
O = max(p.order for p in list_of_polys)+1
C = np.zeros((len(list_of_polys), O))
for p, c in zip(list_of_polys, C):
c[len(c)-p.order-1:] = p.coeffs
return C
def eval_many(x,C):
return C@np.vander(x,11).T
# make example
list_of_polys = [np.poly1d(v) for v in np.random.random((1000,11))]
x = np.random.random((2000,))
# put all coeffs in one master matrix
C = poly_vec(list_of_polys)
# test
assert np.allclose(eval_many(x,C), [p(x) for p in list_of_polys])
from timeit import timeit
print('vectorized', timeit(lambda: eval_many(x,C), number=100)*10)
print('loopy ', timeit(lambda: [p(x) for p in list_of_polys], number=10)*100)
样本运行:
vectorized 6.817315469961613
loopy 56.35076989419758
我正在做数据分析,涉及最小化一组点和相应的一组正交函数之间的最小二乘误差。换句话说,我采用一组 y 值和一组函数,并尝试将 x 值归零,使所有函数最接近其相应的 y 值。一切都在 'data_set' class 中完成。我要比较的函数都存储在一个列表中,我正在使用 class 方法来计算所有函数的总 lsq-error:
self.fits = [np.poly1d(np.polyfit(self.x_data, self.y_data[n],10)) for n in range(self.num_points)]
def error(self, x, y_set):
arr = [(y_set[n] - self.fits[n](x))**2 for n in range(self.num_points)]
return np.sum(arr)
当我的时间比数据多得多时,这很好,但现在我要获取数千个 x 值,每个 x 值都有一千个 y 值,并且 for
循环慢得令人无法接受。我一直在尝试使用 np.vectorize
:
#global scope
def func(f,x):
return f(x)
vfunc = np.vectorize(func, excluded=['x'])
…
…
#within data_set class
def error(self, x, y_set):
arr = (y_set - vfunc(self.fits, x))**2
return np.sum(arr)
func(self.fits[n], x)
只要 n
有效就可以正常工作,据我所知 docs,vfunc(self.fits, x)
应该等同于
[self.fits[n](x) for n in range(self.num_points)]
而是抛出:
ValueError: cannot copy sequence with size 10 to array axis with dimension 11
10 是多项式拟合的次数,11(根据定义)是其中的项数,但我不知道为什么它们会出现在这里。如果我更改装配顺序,错误消息会反映更改。似乎 np.vectorize
将 self.fits
的每个元素作为列表而不是 np.poly1d
函数。
无论如何,如果有人可以帮助我更好地理解 np.vectorize
,或者建议另一种方法来消除该循环,那就太棒了。
由于所讨论的函数都具有非常相似的结构,我们可以在提取多边形系数后 "manually" 进行矢量化。其实函数就是那么一个相当简单的one-liner,eval_many
如下:
import numpy as np
def poly_vec(list_of_polys):
O = max(p.order for p in list_of_polys)+1
C = np.zeros((len(list_of_polys), O))
for p, c in zip(list_of_polys, C):
c[len(c)-p.order-1:] = p.coeffs
return C
def eval_many(x,C):
return C@np.vander(x,11).T
# make example
list_of_polys = [np.poly1d(v) for v in np.random.random((1000,11))]
x = np.random.random((2000,))
# put all coeffs in one master matrix
C = poly_vec(list_of_polys)
# test
assert np.allclose(eval_many(x,C), [p(x) for p in list_of_polys])
from timeit import timeit
print('vectorized', timeit(lambda: eval_many(x,C), number=100)*10)
print('loopy ', timeit(lambda: [p(x) for p in list_of_polys], number=10)*100)
样本运行:
vectorized 6.817315469961613
loopy 56.35076989419758