mac*_*mac 51 python arrays mapping numpy multidimensional-array
是否可以映射NumPy阵列?如果有,怎么样?
给定a_values
- 二维数组 - 这是我现在可以解决的一些代码:
for row in range(len(a_values)):
for col in range(len(a_values[0])):
a_values[row][col] = dim(a_values[row][col])
Run Code Online (Sandbox Code Playgroud)
但它太难看了,我怀疑在NumPy中的某个地方必须有一个功能可以做同样的事情:
a_values.map_in_place(dim)
Run Code Online (Sandbox Code Playgroud)
但如果存在上述情况,我一直无法找到它.
sen*_*rle 54
如果你受到很大的空间限制,那么在这里进行这项工作是值得的.如果是这种情况,可以通过迭代数组的展平视图来加速代码.由于在可能的情况下reshape
返回新视图,因此不会复制数据本身(除非原始结构具有异常结构).
我不知道有一种更好的方法来实现任意Python函数的真正就地应用.
>>> def flat_for(a, f):
... a = a.reshape(-1)
... for i, v in enumerate(a):
... a[i] = f(v)
...
>>> a = numpy.arange(25).reshape(5, 5)
>>> flat_for(a, lambda x: x + 5)
>>> a
array([[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24],
[25, 26, 27, 28, 29]])
Run Code Online (Sandbox Code Playgroud)
一些时间:
>>> a = numpy.arange(2500).reshape(50, 50)
>>> f = lambda x: x + 5
>>> %timeit flat_for(a, f)
1000 loops, best of 3: 1.86 ms per loop
Run Code Online (Sandbox Code Playgroud)
它的速度大约是嵌套循环版本的两倍:
>>> a = numpy.arange(2500).reshape(50, 50)
>>> def nested_for(a, f):
... for i in range(len(a)):
... for j in range(len(a[0])):
... a[i][j] = f(a[i][j])
...
>>> %timeit nested_for(a, f)
100 loops, best of 3: 3.79 ms per loop
Run Code Online (Sandbox Code Playgroud)
当然,矢量化仍然更快,所以如果你可以复制,使用:
>>> a = numpy.arange(2500).reshape(50, 50)
>>> g = numpy.vectorize(lambda x: x + 5)
>>> %timeit g(a)
1000 loops, best of 3: 584 us per loop
Run Code Online (Sandbox Code Playgroud)
如果你可以dim
使用内置的ufunc 重写,那么请,请不要vectorize
:
>>> a = numpy.arange(2500).reshape(50, 50)
>>> %timeit a + 5
100000 loops, best of 3: 4.66 us per loop
Run Code Online (Sandbox Code Playgroud)
numpy
像+=
你期望的那样进行类似的操作- 这样你就可以免费使用就地应用程序来获得ufunc的速度.有时甚至更快!请看这里的例子.
顺便说一句,我对这个问题的原始答案,可以在其编辑历史中查看,是荒谬的,并涉及将索引矢量化为a
.它不仅必须做一些时髦的东西,以旁路vectorize
的类型检测机制,它竟然是一样的嵌套循环的版本一样慢.聪明才智!
mac*_*mac 44
这是我在接受问题答案后写的答案和评论中散布的贡献的记录.Upvotes总是受欢迎的,但是如果你赞成这个答案,请不要错过upvote的那些发送者和(如果他写了一个)eryksun,谁建议下面的方法.
问:是否可以将numpy数组映射到位?
答:可以,但不能使用单一阵列方法.你必须编写自己的代码.
下面是一个脚本,它比较了线程中讨论的各种实现:
import timeit
from numpy import array, arange, vectorize, rint
# SETUP
get_array = lambda side : arange(side**2).reshape(side, side) * 30
dim = lambda x : int(round(x * 0.67328))
# TIMER
def best(fname, reps, side):
global a
a = get_array(side)
t = timeit.Timer('%s(a)' % fname,
setup='from __main__ import %s, a' % fname)
return min(t.repeat(reps, 3)) #low num as in place --> converge to 1
# FUNCTIONS
def mac(array_):
for row in range(len(array_)):
for col in range(len(array_[0])):
array_[row][col] = dim(array_[row][col])
def mac_two(array_):
li = range(len(array_[0]))
for row in range(len(array_)):
for col in li:
array_[row][col] = int(round(array_[row][col] * 0.67328))
def mac_three(array_):
for i, row in enumerate(array_):
array_[i][:] = [int(round(v * 0.67328)) for v in row]
def senderle(array_):
array_ = array_.reshape(-1)
for i, v in enumerate(array_):
array_[i] = dim(v)
def eryksun(array_):
array_[:] = vectorize(dim)(array_)
def ufunc_ed(array_):
multiplied = array_ * 0.67328
array_[:] = rint(multiplied)
# MAIN
r = []
for fname in ('mac', 'mac_two', 'mac_three', 'senderle', 'eryksun', 'ufunc_ed'):
print('\nTesting `%s`...' % fname)
r.append(best(fname, reps=50, side=50))
# The following is for visually checking the functions returns same results
tmp = get_array(3)
eval('%s(tmp)' % fname)
print tmp
tmp = min(r)/100
print('\n===== ...AND THE WINNER IS... =========================')
print(' mac (as in question) : %.4fms [%.0f%%]') % (r[0]*1000,r[0]/tmp)
print(' mac (optimised) : %.4fms [%.0f%%]') % (r[1]*1000,r[1]/tmp)
print(' mac (slice-assignment) : %.4fms [%.0f%%]') % (r[2]*1000,r[2]/tmp)
print(' senderle : %.4fms [%.0f%%]') % (r[3]*1000,r[3]/tmp)
print(' eryksun : %.4fms [%.0f%%]') % (r[4]*1000,r[4]/tmp)
print(' slice-assignment w/ ufunc : %.4fms [%.0f%%]') % (r[5]*1000,r[5]/tmp)
print('=======================================================\n')
Run Code Online (Sandbox Code Playgroud)
上述脚本的输出 - 至少在我的系统中 - 是:
mac (as in question) : 88.7411ms [74591%]
mac (optimised) : 86.4639ms [72677%]
mac (slice-assignment) : 79.8671ms [67132%]
senderle : 85.4590ms [71832%]
eryksun : 13.8662ms [11655%]
slice-assignment w/ ufunc : 0.1190ms [100%]
Run Code Online (Sandbox Code Playgroud)
正如您所观察到的,与第二个最佳和最差的替代方案相比,使用numpy的ufunc
速度提高了2个以上,几乎达到了3个数量级.
如果使用ufunc
不是一个选项,这里只是对其他选择的比较:
mac (as in question) : 91.5761ms [672%]
mac (optimised) : 88.9449ms [653%]
mac (slice-assignment) : 80.1032ms [588%]
senderle : 86.3919ms [634%]
eryksun : 13.6259ms [100%]
Run Code Online (Sandbox Code Playgroud)
HTH!
归档时间: |
|
查看次数: |
55516 次 |
最近记录: |