我正在执行大量这些计算:
A == A[np.newaxis].T
其中A是一个密集的numpy数组,通常具有共同的值 .
出于基准测试目的,我们可以使用:
n = 30000
A = np.random.randint(0, 1000, n)
A == A[np.newaxis].T
当我执行此计算时,我遇到了内存问题 . 我相信这是因为输出不是更高效的bitarray或np.packedbits格式 . 第二个问题是我们正在进行两次必要的比较,因为得到的布尔数组是对称的 .
我的问题是:
-
是否可以在不牺牲速度的情况下以更高内存效率的方式生成布尔numpy数组输出?我所知道的选项是bitarray和np.packedbits,但我只知道在创建大型布尔数组后如何应用这些选项 .
-
我们能否利用计算的对称性将处理的比较数量减半,同样不会牺牲速度?
我需要能够执行&和|对布尔数组输出的操作 . 我尝试过bitarray,这对于这些按位操作非常快 . 但是打包np.ndarray - > bitarray然后解压缩bitarray - > np.ndarray是很慢的 .
[编辑提供澄清 . ]
4 回答
这是一个
numba
给我们一个NumPy布尔数组作为输出 -计时 -
这甚至不是一个愚蠢的答案,但应该通过使用一些自制的稀疏表示法来降低数据要求
现在
c
是一个坐标元组列表(i, j)
,i < j
,它对应于布尔数组中"True"的坐标 . 您可以轻松地对这些setwise执行and
和or
操作:稍后,当您想要将此蒙版应用于数组时,您可以退出坐标并将其用于花式索引:
如果你关心订单,你可以
np.lexsort
i
ndj
或者,您可以将
sparse_outer_eq
定义为:保持> 2倍的数据,但坐标简单地出现:
如果你做了任何
set
操作,如果你想要一个合理的订单,这仍然需要lexsort
.如果你的坐标都是n位整数,那么这应该比布尔格式更节省空间,只要你的稀疏度小于1 / n - > 32%左右 .
至于时间,多亏了
numba
,它甚至比广播更快:和比较:
编辑:如果你想做
&~
(根据你的评论)使用第二个sparse_outer_eq
方法(所以你不必跟踪对角线),只是做:这是或多或少的规范
argsort
解决方案:我正在为我的问题添加一个解决方案,因为它满足这三个属性:
低,固定,内存要求
快速按位运算(&,|,〜等)
低存储,每布尔1位,通过打包整数
缺点是它以np.packbits格式存储 . 它比其他方法(尤其是argsort)慢得多,但如果速度不是问题,算法应该运行良好 . 如果有人想出进一步优化的方法,这将非常有帮助 .
Update: 可以在此处找到以下算法的更高效版本:Improving performance on comparison algorithm np.packbits(A==A[:, None], axis=1) .