Python 在Numpy下对两个矩阵中的所有成对行应用函数

Python 在Numpy下对两个矩阵中的所有成对行应用函数,python,arrays,numpy,matrix,Python,Arrays,Numpy,Matrix,我有两个矩阵: import numpy as np def create(n): M = array([[ 0.33840224, 0.25420152, 0.40739624], [ 0.35087337, 0.40939274, 0.23973389], [ 0.40168642, 0.29848413, 0.29982946], [ 0.17442095, 0.5098227

我有两个矩阵:

import numpy as np

def create(n):
    M = array([[ 0.33840224,  0.25420152,  0.40739624],
               [ 0.35087337,  0.40939274,  0.23973389],
               [ 0.40168642,  0.29848413,  0.29982946],
               [ 0.17442095,  0.50982272,  0.31575633]])
    return np.concatenate([M] * n)

A = create(1)
nof_type = A.shape[1]       
I = np.eye(nof_type)
矩阵
A
维度是
4x3
,I是
3x3
。 我想做的是

  • 根据
    I
    中的每一行计算
    a
    中每一行的距离分数
  • 对于
    A
    中的每一行,报告
    I
    的行id和最大分数
  • 因此,在一天结束时,我们有4 x 2矩阵。 我是如何做到这一点的

    这是计算两个numpy数组之间距离分数的函数

    def jsd(x,y): #Jensen-shannon divergence
        import warnings
        warnings.filterwarnings("ignore", category = RuntimeWarning)
        x = np.array(x)
        y = np.array(y)
        d1 = x*np.log2(2*x/(x+y))
        d2 = y*np.log2(2*y/(x+y))
        d1[np.isnan(d1)] = 0
        d2[np.isnan(d2)] = 0
        d = 0.5*np.sum(d1+d2)    
        return d
    
    在实际情况下,
    A
    的行数约为40K。所以我们真的很喜欢它的速度

    使用循环方式:

    def scoreit (A, I):
        aoa = []
        for i, x in enumerate(A):
            maxscore = -10000
            id = -1
    
            for j, y in enumerate(I):
                distance = jsd(x, y) 
                #print "\t", i, j, distance
                if dist > maxscore:
                    maxscore = distance
                    id = j
            #print "MAX", maxscore, id
            aoa.append([maxscore,id])
        return aoa
    
    它将打印此结果:

    In [56]: scoreit(A,I)
    Out[56]:
    [[0.54393736529629078, 1],
     [0.56083720679952753, 2],
     [0.49502813447483673, 1],
     [0.64408263453965031, 0]]
    
    当前时间:

    In [57]: %timeit scoreit(create(1000),I)
    1 loops, best of 3: 3.31 s per loop
    

    您可以在不同的位置将
    I
    的尺寸扩展到
    3D
    阵列版本,以发挥作用。我们保留了
    A
    ,因为它是一个巨大的数组,我们不希望在移动其元素时导致性能损失。此外,您还可以避免检查
    nan
    并使用对
    非nan
    进行求和的单个操作进行求和的昂贵工作。因此,矢量化的解决方案看起来像这样-

    def jsd_vectorized(A,I):
    
        # Perform "(x+y)" in a vectorized manner
        AI = A+I[:,None]
    
        # Calculate d1 and d2 using AI again in vectorized manner
        d1 = A*np.log2(2*A/AI)
        d2 = I[:,None,:]*np.log2((2*I[:,None,:])/AI)
    
        # Use np.nansum to ignore NaNs & sum along rows to get all distances
        dists = np.nansum(d1,2) + np.nansum(d2,2)
    
        # Pack the argmax IDs and the corresponding scores as final output   
        ID = dists.argmax(0)
        return np.vstack((0.5*dists[ID,np.arange(dists.shape[1])],ID)).T
    

    样本运行

    循环函数以运行原始函数代码-

    def jsd_loopy(A,I):
        dists = np.empty((A.shape[0],I.shape[0]))
        for i, x in enumerate(A):   
            for j, y in enumerate(I):
                dists[i,j] = jsd(x, y)
        ID = dists.argmax(1)
        return np.vstack((dists[np.arange(dists.shape[0]),ID],ID)).T
    
    运行并验证-

    In [511]: A = np.array([[ 0.33840224,  0.25420152,  0.40739624],
         ...:        [ 0.35087337,  0.40939274,  0.23973389],
         ...:        [ 0.40168642,  0.29848413,  0.29982946],
         ...:        [ 0.17442095,  0.50982272,  0.31575633]])
         ...: nof_type = A.shape[1]       
         ...: I = np.eye(nof_type)
         ...: 
    
    In [512]: jsd_loopy(A,I)
    Out[512]: 
    array([[ 0.54393737,  1.        ],
           [ 0.56083721,  2.        ],
           [ 0.49502813,  1.        ],
           [ 0.64408263,  0.        ]])
    
    In [513]: jsd_vectorized(A,I)
    Out[513]: 
    array([[ 0.54393737,  1.        ],
           [ 0.56083721,  2.        ],
           [ 0.49502813,  1.        ],
           [ 0.64408263,  0.        ]])
    
    运行时测试

    In [514]: A = np.random.rand(1000,3)
    
    In [515]: nof_type = A.shape[1]       
         ...: I = np.eye(nof_type)
         ...: 
    
    In [516]: %timeit jsd_loopy(A,I)
    1 loops, best of 3: 782 ms per loop
    
    In [517]: %timeit jsd_vectorized(A,I)
    1000 loops, best of 3: 1.17 ms per loop
    
    In [518]: np.allclose(jsd_loopy(A,I),jsd_vectorized(A,I))
    Out[518]: True
    

    所以,
    I
    总是一个标识数组吗?@Divakar:没错!如果您已尝试和/或给定示例的预期输出,是否可以添加任何循环代码?我只是不确定输出的形状如何
    (4,2)
    。另外,你能为你的实际情况列出
    A
    I
    的形状吗?@Divakar:我用loopy way更新了。谢谢。当
    out=jsd\u矢量化(A,I)
    时,是否有方法将索引
    ids=out[:,1::][/code>设置为整数?我想用它来屏蔽一个列表,比如说
    foo=[“a”,“b”,“c”]
    @永远不要做像
    out[:,2]这样的事情。astype(int)
    ,其中
    out=jsd\u向量化(a,I)
    ?顺便问一句,为什么要这样做
    jsdout=jsd\u向量化(a,I)
    给我这个警告
    //anaconda/bin/ipython:4:RuntimeWarning:ipython import start_ipython//anaconda/bin/ipython:4:RuntimeWarning:ipython import start_python的乘法中遇到无效值
    @neversaint您可以使用问题中的忽略警告代码这里也有这种方法,对吗?输出不会改变,因此基本上可以忽略警告。