Python 为什么在numpy中,布尔运算比其他类型的运算慢?
我想在numpy模块中使用布尔矩阵而不是整数矩阵,因为我的一些矩阵只包含0和1。 所以,我想知道为什么不使用布尔矩阵来加速一些计算。 但实际上,布尔矩阵上的运算比浮点矩阵上的运算要长得多 例如:Python 为什么在numpy中,布尔运算比其他类型的运算慢?,python,numpy,matrix,time,boolean,Python,Numpy,Matrix,Time,Boolean,我想在numpy模块中使用布尔矩阵而不是整数矩阵,因为我的一些矩阵只包含0和1。 所以,我想知道为什么不使用布尔矩阵来加速一些计算。 但实际上,布尔矩阵上的运算比浮点矩阵上的运算要长得多 例如: import numpy as np import time RM = np.random.rand(1000,1000) RM = (RM >= .5 )*1. start_time = time.time() R = np.sum(RM) print("--- %s seconds --
import numpy as np
import time
RM = np.random.rand(1000,1000)
RM = (RM >= .5 )*1.
start_time = time.time()
R = np.sum(RM)
print("--- %s seconds ---" % (time.time() - start_time))
RM = RM.astype(np.bool)
start_time = time.time()
R = np.sum(RM)
print("--- %s seconds ---" % (time.time() - start_time))
对此作出回应:
--- 0.0010001659393310547 seconds ---
--- 0.002000093460083008 seconds ---
所以布尔矩阵使用了两倍的时间!
我想知道为什么会发生这种情况,是否存在一个解决办法
更新
正如一些评论所提到的,我计算时间执行的方式并不是最好的方式。
使用@Anis的方法,这里是新方法:
import numpy as np
import timeit
RMint = np.ones((1000,1000), dtype='int64')
RMbool = np.ones((1000,1000), dtype='bool')
RMfloat = np.ones((1000,1000), dtype='float64')
def test():
global RM
R = np.sum(RM)
if __name__ == '__main__':
print("int64")
RM= RMint
print(timeit.timeit("test( )", number=1000, setup="from __main__ import test"))
print("bool")
RM= RMbool
print(timeit.timeit("test( )", number=1000, setup="from __main__ import test"))
print("float64")
RM=RMfloat
print(timeit.timeit("test( )", number=1000, setup="from __main__ import test"))
我只是从测试函数中得到矩阵初始化,因为矩阵的构建不是这里的重点。
通过这种方法,我得出了相同的结论:
int64
0.7555235163780709
bool
1.9191522692976613
float64
0.935670545406214
所以布尔运算比int或float运算长得多。但我不明白为什么?不,布尔运算比其他运算快。5次运行后的平均剖面如下所示
dtype Average
int64 4.66626188
bool 1.243509225
float64 5.220022027
我的代码是从@Anis修改而来的
import numpy as np
import timeit
def test(dtype):
R = np.sum(np.ones((1000,1000), dtype=dtype))
if __name__ == '__main__':
dtype = 'int64'
print(dtype)
print(timeit.timeit(f"test('{dtype}')", number=1000, setup="from __main__ import test"))
dtype = 'bool'
print(dtype)
print(timeit.timeit(f"test('{dtype}')", number=1000, setup="from __main__ import test"))
dtype = 'float64'
print(dtype)
print(timeit.timeit(f"test('{dtype}')", number=1000, setup="from __main__ import test"))
使用的模块包括:
软件
版本
Python
3.4.5 64位
IPython
5.1.0
OS
Windows10
numpy
1.11.3
不,布尔运算比其他运算快。5次运行后的平均剖面如下所示
dtype Average
int64 4.66626188
bool 1.243509225
float64 5.220022027
我的代码是从@Anis修改而来的
import numpy as np
import timeit
def test(dtype):
R = np.sum(np.ones((1000,1000), dtype=dtype))
if __name__ == '__main__':
dtype = 'int64'
print(dtype)
print(timeit.timeit(f"test('{dtype}')", number=1000, setup="from __main__ import test"))
dtype = 'bool'
print(dtype)
print(timeit.timeit(f"test('{dtype}')", number=1000, setup="from __main__ import test"))
dtype = 'float64'
print(dtype)
print(timeit.timeit(f"test('{dtype}')", number=1000, setup="from __main__ import test"))
使用的模块包括:
软件
版本
Python
3.4.5 64位
IPython
5.1.0
OS
Windows10
numpy
1.11.3
根据我的经验,在布尔的N阵列上的操作与仅在uint8的N阵列上的操作相等(速度方面)。通常,如果使用其他数据类型,并且对它们执行相同的操作,则所用的时间更高 当然,这也取决于所执行的操作,例如,可能是numpy.sum强制布尔数组转换为int64,因此所用的时间与使用int64获得的时间相当(甚至略高) 事实上,使用非mod 2算法对两个布尔数组求和几乎没有意义,并且在可能的情况下,应该始终使用mod 2算法(and、OR、XOR等),这是布尔数组上几乎唯一可能的算法,而不必强制转换到其他(更麻烦的)类型 这与以下事实有关:bool和uint8的ndarrays在较低级别上基本相同。 事实上,它们占用的内存量相同:
>>>import sys
>>>import numpy as np
>>>sys.getsizeof(np.array([True], dtype="bool"))
Out: 97
>>>sys.getsizeof(np.array([1], dtype="uint8"))
Out: 97
>>>sys.getsizeof(np.array([1], dtype="int64"))
Out: 104
uint8和bool占用相同的内存量是因为x86系统(以及大多数ARM和其他嵌入式系统)上的最小可寻址内存量是8位字(1字节)。看
此后,我报告了支持我的主张的基准(numpy 1.13.3):
正如您所看到的,uint8和bool在这里几乎没有区别,而int64则慢得多。有趣的是,我发现np.add比bools上的np.logical\u xor更快。
实际上,np.add实际上执行元素或而不是元素XOR(即模2加法)。在bool数组上执行时,np.add和np.logical_或这两个操作是相同的,np.add返回bool数组。根据我的经验,bool n数组上的操作与uint8的n数组上的操作相等(速度)。通常,如果使用其他数据类型,并且对它们执行相同的操作,则所用的时间更高 当然,这也取决于所执行的操作,例如,可能是numpy.sum强制布尔数组转换为int64,因此所用的时间与使用int64获得的时间相当(甚至略高) 事实上,使用非mod 2算法对两个布尔数组求和几乎没有意义,并且在可能的情况下,应该始终使用mod 2算法(and、OR、XOR等),这是布尔数组上几乎唯一可能的算法,而不必强制转换到其他(更麻烦的)类型 这与以下事实有关:bool和uint8的ndarrays在较低级别上基本相同。 事实上,它们占用的内存量相同:
>>>import sys
>>>import numpy as np
>>>sys.getsizeof(np.array([True], dtype="bool"))
Out: 97
>>>sys.getsizeof(np.array([1], dtype="uint8"))
Out: 97
>>>sys.getsizeof(np.array([1], dtype="int64"))
Out: 104
uint8和bool占用相同的内存量是因为x86系统(以及大多数ARM和其他嵌入式系统)上的最小可寻址内存量是8位字(1字节)。看
此后,我报告了支持我的主张的基准(numpy 1.13.3):
正如您所看到的,uint8和bool在这里几乎没有区别,而int64则慢得多。有趣的是,我发现np.add比bools上的np.logical\u xor更快。
实际上,np.add实际上执行元素或而不是元素XOR(即模2加法)。在布尔数组上执行时,np.add和np.logical\u或两个操作相同,np.add返回布尔数组。您必须多次运行实验(在大型数据集上)才能得出结论。。。总的差异只有一毫秒。例如,进程可能暂时挂起,等等。此外,您应该使用像
timeit
这样的工具来计算CPU时间,而不是墙时间。可能相关,也可能不相关。对于布尔数组求和,应使用np.count\u nonzero
。好吧,我承认我之前的回答没有抓住重点,你完全正确。我没有考虑分配所造成的开销,因为我认为这与操作相比是很小的。错。