将矢量化函数转换为矢量化函数Python

问题描述 投票:1回答:2

我想解决下一个问题:我有一个值矩阵,每个值代表一个电影的评级,我有下一个函数返回一个值(距离):

def getDistanceBetween2Movies(movie1, movie2):
    return np.linalg.norm(X[movie1]-X[movie2])

这个功能工作正常,所以我想得到一个列表,其中包含从一个指定电影到其他电影的所有距离,我就是这样做的,并且它有效

#Vector of indices of movies without our new user's one
moviesInd = np.arange(n_movies)
myMovie = 1

#Vectorizing our function
vfunc = np.vectorize(getDistanceBetween2Movies)
arrayDistances = vfunc(myMovie,moviesInd)
closestValue = np.min(arrayDistances)
closestIndex = np.argmin(arrayDistances)

print("Movie: " + str(closestIndex))
print("Distance: " + str(closestValue))

所以现在的问题是如何获得一个矩阵,其中包含从每部电影到其他电影的所有距离,我正在尝试再次对此函数进行矢量化,以便将相同的操作进行n_movies次并将其收集到列表或数组中。

    def getVectorDistances(i):
        vector = np.arange(n_movies)
        vFunc = np.vectorize(getDistanceBetween2Movies)
        return vFunc(i, vector)

    moviesInd = np.arange(n_movies)
    vFunc = np.vectorize(getVectorDistances)
    print(vFunc(moviesInd))

    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    <ipython-input-34-01b95a280035> in <module>()
          6 moviesInd = np.arange(n_movies)
          7 vFunc = np.vectorize(getVectorDistances)
    ----> 8 print(vFunc(moviesInd))
          9 
         10 

    c:\users\regis\appdata\local\programs\python\python36-32\lib\site-packages\numpy\lib\function_base.py in __call__(self, *args, **kwargs)
       2737             vargs.extend([kwargs[_n] for _n in names])
       2738 
    -> 2739         return self._vectorize_call(func=func, args=vargs)
       2740 
       2741     def _get_ufunc_and_otypes(self, func, args):

    c:\users\regis\appdata\local\programs\python\python36-32\lib\site-packages\numpy\lib\function_base.py in _vectorize_call(self, func, args)
       2816 
       2817             if ufunc.nout == 1:
    -> 2818                 res = array(outputs, copy=False, subok=True, dtype=otypes[0])
       2819             else:
       2820                 res = tuple([array(x, copy=False, subok=True, dtype=t)
ValueError: setting an array element with a sequence.

这就是我所做的,但它不起作用,我被卡住了。

先感谢您

python function numpy vectorization
2个回答
0
投票

我想你可以使用原始的vfunc而不需要嵌套它。 vectorize期望一个接受标量的函数。它根据需要广播输入,以将标量集传递给函数。

这是标量输入,它正在弄乱第二级矢量化。

但是看看我们可以用第一个矢量化做什么:

In [389]: def getDistanceBetween2Movies(movie1, movie2):
     ...:     return np.linalg.norm(X[movie1]-X[movie2])
     ...: 
In [390]: X = np.arange(20)

你的函数值有2个标量:

In [391]: getDistanceBetween2Movies(1,2)
Out[391]: 1.0
In [393]: getDistanceBetween2Movies(1,10)
Out[393]: 9.0

In [394]: vfunc = np.vectorize(getDistanceBetween2Movies)

vectorize有一个标量和数组,有效[getDistanceBetween2Movies(i,j) for j in movielist]

In [395]: vfunc(1,np.arange(5))
Out[395]: array([ 1.,  0.,  1.,  2.,  3.])

但我可以给它两个数组,一个列向量。这最终做了outer评估:

In [396]: vfunc(np.arange(5)[:,None], np.arange(5))
Out[396]: 
array([[ 0.,  1.,  2.,  3.,  4.],
       [ 1.,  0.,  1.,  2.,  3.],
       [ 2.,  1.,  0.,  1.,  2.],
       [ 3.,  2.,  1.,  0.,  1.],
       [ 4.,  3.,  2.,  1.,  0.]])

将该输出与这两个数组之间的简单广播差异进行比较:

In [397]: np.arange(5)[:,None]-np.arange(5)
Out[397]: 
array([[ 0, -1, -2, -3, -4],
       [ 1,  0, -1, -2, -3],
       [ 2,  1,  0, -1, -2],
       [ 3,  2,  1,  0, -1],
       [ 4,  3,  2,  1,  0]])

vectorize不会提高直接迭代的速度,但它可以更容易地评估复杂的标量函数,特别是如果你是需要相互广播的多个输入。

正如@Nils所示,你可能不需要使用vectorize


1
投票

由于您正在计算矩阵行之间的差异,因此我们尝试将以下double for循环分解

a = numpy.arange(25).reshape(5, 5)
y = numpy.zeros(5, 5)
for i in range(len(a)):
    for j in range(len(a)):
        y[i, j] = numpy.linalg.norm(a[i, :] - a[j, :])

第一步是向量化行差异

a[i, :] - a[j, :]  # difference between rows `i` and `j`

通过计算矩阵行的“外部差异”,产生3D张量:

x = a[:, None, :] - a[None, :, :]
x.shape  # (5, 5, 5)

之后,行ij的差异可以在张量的相应位置找到:

x[i, j, :]  # difference between rows `i` and `j`

循环变成了

for i in range(len(a)):
    for j in range(len(a)):
        y[i, j] = numpy.linalg.norm(x[i, j, :])

然而,由于我们现在只迭代x的前两个轴,我们可以用numpy.linalg.norm()的矢量化调用替换双循环:

y = numpy.linalg.norm(x, axis=-1)

并在相应的位置再次获得行ij的距离

y[i, j]  # distance between rows `i` and `j`
© www.soinside.com 2019 - 2024. All rights reserved.