我有一段代码:

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

import time
import numpy as np

for t in [np.uint8, np.int8]:
  a=np.empty([480, 640], t)
  v=[10, 245]
  for y in range(480):
    for x in range(640):
      a[y, x]=v[x&1]  # 50%=10, 50%=245
  t1=time.clock()
  a[a<32]=0
  a[a>224]=0
  t2=time.clock()
  print("%2.3f ms"%((t2-t1)*1000), a.dtype)

我得到这个输出:
3.162 ms uint8
0.329 ms int8

如果它运行在一个有符号的数组上,为什么要快10倍?
有没有办法在无符号数组上加速呢?
是的…更多的样品也是一样的:
for t in [np.int8, np.uint8]:
  a=np.empty([480, 640], t)
  v=[10, 245]
  for y in range(480):
    for x in range(640):
      a[y, x]=v[x&1]  # 50%=10, 50%=235

  t1=time.process_time()
  for l in range(1000):
    b=1*a  # deep copy
    b[b<32]=0
    b[b>224]=0
  t2=time.process_time()
  print("%5.4f ms"%((t2-t1)*1000), a.dtype)

结果是:
328.0701 ms int8
3081.5300 ms uint8

最佳答案

为了确保每个人都知道时差从何而来,我将代码分解到每个单独的步骤:
整个密码

%%timeit
tmp = np.array(a, dtype=np.uint8, copy=True)
tmp[tmp < 30] = 0
tmp[tmp > 224] = 0

10个回路,最好3个:每个回路21.6 ms
%%timeit
tmp = np.array(a, dtype=np.int8, copy=True)
tmp[tmp < 30] = 0
tmp[tmp > 224] = 0

100个回路,最好3个:每个回路10.4 ms
所以是的,整个操作更快,但是让我们看看在每个设置操作中花费的时间:
%timeit tmp = np.array(a, dtype=np.uint8, copy=True); tmp[tmp < 30] = 0
tmp = np.array(a, dtype=np.uint8, copy=True)
tmp[tmp < 30] = 0
%timeit tmp2 = np.array(tmp, copy=True); tmp2[tmp2 > 224] = 0

100个回路,最好3个:每个回路19.3 ms
100个回路,最好3个:每个回路17.6 ms
因此,对于int8,每个设置都需要相同的时间:
100个回路,最好3个:每个回路6.75ms
100个回路,最好3个:每个回路4.36ms
让我们看看如果只创建基于索引的新视图会发生什么:
%timeit tmp = np.array(a, dtype=np.uint8, copy=True); _ = tmp[tmp < 30]
tmp = np.array(a, dtype=np.uint8, copy=True)
tmp[tmp < 30] = 0
%timeit tmp2 = np.array(tmp, copy=True); _ = tmp2[tmp2 > 224]

100个回路,最好3个:每个回路17.9ms
100个回路,最好3个:每个回路16.2 ms
对于int8
100个回路,最好3个:每个回路7.64 ms
100个回路,最好3个:每个回路4.3 ms
仍然int更快。那么创建布尔掩码呢:
%timeit tmp = np.array(a, dtype=np.uint8, copy=True); _ = tmp < 30
tmp = np.array(a, dtype=np.uint8, copy=True)
tmp[tmp < 30] = 0
%timeit tmp2 = np.array(tmp, copy=True); _ = tmp2 > 224

100个回路,最好3个:每个回路4.25 ms
100个回路,最好3个:每个回路2.58ms
对于int8
100个回路,最好3个:每个回路4.26 ms
100个回路,最好3个:每个回路4.08 ms
长话短说:在创建布尔掩码时,dtype并没有太大的区别,但是如果使用布尔掩码在数据上创建一个新视图,则使用int会更快但这只是一个幻觉,因为实际上numpy看到它在第一个操作中访问所有元素(因为在int8中235 get被转换为-21),而在第二个操作中没有元素。两个操作的掩码都包含True和False(混合)。
小结:因此numpy可以并且确实优化了获取和设置数组的所有/没有元素。
在你提到的评论中,uint对于v=[10,100]更快,但是在我的计算机中,与上面相同的设置,两者都近似相同:
uint: 10 loops, best of 3: 21.7 ms per loop
int:  10 loops, best of 3: 23.2 ms per loop

这是因为现在第一个操作有一个混合的布尔掩码,numpy不能像设置all/no元素那样优化它。但是第二个操作有一个布尔掩码,只有uint,所以numpy对uint和int都跳过这个。

08-07 15:26