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

2024-03-29 10:44:21 发布

您现在位置:Python中文网/ 问答频道 /正文

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

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\u 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.

这是我做的,但它不工作,我卡住了。你知道吗

先谢谢你


Tags: inself距离电影libnpargsmovies
2条回答

由于您正在计算矩阵行之间的差异,因此我们尝试将以下双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`

通过计算矩阵行的“外差”,得到一个三维张量:

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

之后,在张量的相应位置可以发现i行和j行的差异:

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`

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

是标量输入干扰了第二级矢量化。你知道吗

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

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

你的函数值有两个标量:

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。你知道吗

相关问题 更多 >