2011-04-22 177 views
16

有什么我可以做的,以加快numpy中的屏蔽数组?我有一个非常低效的函数,我重写了使用被屏蔽的数组(我可以屏蔽行而不是复制和删除行)。但是,我惊讶地发现掩码函数速度慢了10倍,因为掩码阵列速度非常慢。Python/Numpy - 屏蔽数组非常慢

作为一个例子,可采取下列(掩蔽是对我来说更慢然后6次):

import timeit 
import numpy as np 
import numpy.ma as ma 

def test(row): 
    return row[0] + row[1] 

a = np.arange(1000).reshape(500, 2) 
t = timeit.Timer('np.apply_along_axis(test, 1, a)','from __main__ import test, a, np') 
print round(t.timeit(100), 6) 

b = ma.array(a) 
t = timeit.Timer('ma.apply_along_axis(test, 1, b)','from __main__ import test, b, ma') 
print round(t.timeit(100), 6) 
+2

请记住,MaskedArrays比实际解决方案更方便。如果您需要对数组中缺失/未定义值进行密集计算,那么在大多数情况下,您最好自己处理掩码和数据。直到在NumPy代码中更好地实现丢失/未定义的值(这种情况应该很快发生)之前,您将被禁止使用MaskedArrays。是的,它们很慢,因为它们是用纯Python编码的,当然不能像依赖某些C代码那样高效。 – 2012-08-17 11:46:38

+0

感谢您的问题,这证实了我怀疑我的代码 – 2017-08-29 10:11:50

回答

3

我不知道为什么被屏蔽阵列功能的移动得很慢,但因为它听起来像你使用面膜来选择行(而不是单独的值),你可以创建一个从蒙面行的规则排列,使用NP函数:

b.mask = np.zeros(500) 
b.mask[498] = True 
t = timeit.Timer('c=b.view(np.ndarray)[~b.mask[:,0]]; np.apply_along_axis(test, 1, c)','from __main__ import test, b, ma, np') 
print round(t.timeit(100), 6) 

更重要的是,在所有不使用屏蔽数组;只需将您的数据和一维掩模阵列作为单独的变量进行维护:

a = np.arange(1000).reshape(500, 2) 
mask = np.ones(a.shape[0], dtype=bool) 
mask[498] = False 
out = np.apply_along_axis(test, 1, a[mask]) 
+0

减速以及我做了类似于你的第二个例子,但我需要变量'out'具有相同数量的索引,因为有行在一个'。请参阅[此问题](http://stackoverflow.com/questions/5761642/python-numpy-get-index-into-main-array-from-subset) – 2011-07-07 20:08:59

0

编辑:我被测试它错误通过使用np.apply_along_axis代替np.ma.apply_along_axis,抱歉。 所以,我确认屏蔽数组版本比较慢也可以在Linux/numpy的5倍以上1.5.1

In [16]: %timeit np.apply_along_axis(test, 1, a) 
100 loops, best of 3: 15.3 ms per loop 

In [17]: %timeit np.apply_along_axis(test, 1, b) 
100 loops, best of 3: 15.3 ms per loop 

In [12]: %timeit np.ma.apply_along_axis(test, 1, b) 
10 loops, best of 3: 80.8 ms per loop 

In [18]: np.__version__ 
Out[18]: '1.5.1' 
+0

我在Windows XP 32bit上使用python 2.5.2和numpy 1.5.1。当我回家时,我会在我的Linux电脑上试用它。很奇怪。作为参考,当我运行我的发布的代码,我得到的输出:0.955434和5.136362。 – 2011-04-23 00:20:36

+0

我看到了显着的性能差异:第一个是1.298489,第二个是7.177839。我在Linux 64bit上使用Python 2.6.4和numpy 1.5.1。 – tkerwin 2011-04-23 00:27:11

+0

实际上,我没有看到使用'%timeit'命令的区别,就像你在例子中做的那样,但是我在使用'timeit.Timer'时做了。也许我不明白他们是如何工作的。 – tkerwin 2011-04-23 00:34:31