矢量化的pythonic方式来获取比当前元素更大的元素数

Eru*_*tio 5 python performance numpy vectorization

我想比较数组b中的每个条目及其各自的列,以查找有多少条目(来自该列)大于引用.我的代码似乎令人尴尬地缓慢,我怀疑这是由于循环而不是向量操作.

我们可以"矢量化"以下代码吗?

import numpy as np

n = 1000
m = 200
b = np.random.rand(n,m)
p = np.zeros((n,m))

for i in range(0,n): #rows
   for j in range(0,m):  # cols
     r = b[i,j]  
     p[i,j] = ( ( b[:,j] > r).sum() ) / (n) 
Run Code Online (Sandbox Code Playgroud)

经过一番思考之后,我认为对每个列进行排序可以通过使后续比较更快来改善整体运行时间.

经过一番搜索,我相信我要逐列percentileofscore(http://lagrange.univ-lyon1.fr/docs/scipy/0.17.1/generated/scipy.stats.percentileofscore.html)

Div*_*kar 3

只需要进行一些更深入的研究即可发现,我们可以简单地使用argsort()每列的索引来获取每次迭代时大于当前元素的计数。

方法#1

考虑到这一理论,一种解决方案就是简单地使用两个argsort- 来获得计数 -

p = len(b)-1-b.argsort(0).argsort(0)
Run Code Online (Sandbox Code Playgroud)

方法#2

鉴于索引argsort是唯一的数字,我们可以进一步优化它。因此,第二步argsort可以使用一些数组赋值 + advanced-indexing,如下所示 -

def count_occ(b):
    n,m = b.shape     
    out = np.zeros((n,m),dtype=int)
    idx = b.argsort(0)
    out[idx, np.arange(m)] = n-1-np.arange(n)[:,None]
    return out
Run Code Online (Sandbox Code Playgroud)

n最后,按照两种方法的问题中所述除以。


标杆管理

对迄今为止发布的所有方法进行计时 -

In [174]: np.random.seed(0)
     ...: n = 1000
     ...: m = 200
     ...: b = np.random.rand(n,m)

In [175]: %timeit (len(b)-1-b.argsort(0).argsort(0))/float(n)
100 loops, best of 3: 17.6 ms per loop

In [176]: %timeit count_occ(b)/float(n)
100 loops, best of 3: 12.1 ms per loop

# @Brad Solomon's soln
In [177]: %timeit np.sum(b > b[:, None], axis=-2) / float(n)
1 loop, best of 3: 349 ms per loop

# @marco romelli's loopy soln
In [178]: %timeit loopy_soln(b)/float(n)
10 loops, best of 3: 139 ms per loop
Run Code Online (Sandbox Code Playgroud)